/* This file is part of the KDE libraries
   Copyright (C) 2000 Torben Weis <weis@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "ktrader.h"
#include "ktraderparsetree.h"

#include <tqtl.h>
#include <tqbuffer.h>

#include <kuserprofile.h>
#include <kstandarddirs.h>
#include <kstaticdeleter.h>
#include <kdebug.h>

template class KStaticDeleter<TDETrader>;

using namespace TDEIO;

class TDETraderSorter
{
public:
  TDETraderSorter() { m_pService = 0; };
  TDETraderSorter( const TDETraderSorter& s ) : m_userPreference( s.m_userPreference ),
    m_bAllowAsDefault( s.m_bAllowAsDefault ),
    m_traderPreference( s.m_traderPreference ), m_pService( s.m_pService ) { }
  TDETraderSorter( const KService::Ptr &_service, double _pref1, int _pref2, bool _default )
  { m_pService = _service;
    m_userPreference = _pref2;
    m_traderPreference = _pref1;
    m_bAllowAsDefault = _default;
  }

  KService::Ptr service() const { return m_pService; }

  bool operator< ( const TDETraderSorter& ) const;

private:
  /**
   * The bigger this number is, the better is this service in
   * the users opinion.
   */
  int m_userPreference;
  /**
   * Is it allowed to use this service for default actions.
   */
  bool m_bAllowAsDefault;

  /**
   * The bigger this number is, the better is this service with
   * respect to the queries preferences expression.
   */
  double m_traderPreference;

  KService::Ptr m_pService;
};

bool TDETraderSorter::operator< ( const TDETraderSorter& _o ) const
{
  if ( _o.m_bAllowAsDefault && !m_bAllowAsDefault )
    return true;
  if ( _o.m_userPreference > m_userPreference )
    return true;
  if ( _o.m_userPreference < m_userPreference )
    return false;
  if ( _o.m_traderPreference > m_traderPreference )
    return true;
  return false;
}

// --------------------------------------------------

TDETrader* TDETrader::s_self = 0;
static KStaticDeleter<TDETrader> ktradersd;

TDETrader* TDETrader::self()
{
    if ( !s_self )
	ktradersd.setObject( s_self, new TDETrader );

    return s_self;
}

TDETrader::TDETrader()
{
}

TDETrader::~TDETrader()
{
}

TDETrader::OfferList TDETrader::query( const TQString& _servicetype, const TQString& _constraint,
                                   const TQString& _preferences ) const
{
    return query( _servicetype, TQString::null, _constraint, _preferences );
}

TDETrader::OfferList TDETrader::query( const TQString& _servicetype, const TQString& _genericServiceType,
                                   const TQString& _constraint,
                                   const TQString& _preferences ) const
{
  // TODO: catch errors here
  ParseTreeBase::Ptr constr;
  ParseTreeBase::Ptr prefs;

  if ( !_constraint.isEmpty() )
    constr = TDEIO::parseConstraints( _constraint );

  if ( !_preferences.isEmpty() )
    prefs = TDEIO::parsePreferences( _preferences );

  KServiceTypeProfile::OfferList lst;
  TDETrader::OfferList ret;

  // Get all services of this service type.
  lst = KServiceTypeProfile::offers( _servicetype, _genericServiceType );
  if ( lst.count() == 0 )
    return ret;

  if ( !!constr )
  {
    // Find all services matching the constraint
    // and remove the other ones
    KServiceTypeProfile::OfferList::Iterator it = lst.begin();
    while( it != lst.end() )
    {
      if ( matchConstraint( constr, (*it).service(), lst ) != 1 )
	it = lst.remove( it );
      else
	++it;
    }
  }

  if ( !!prefs )
  {
    TQValueList<TDETraderSorter> sorter;
    KServiceTypeProfile::OfferList::Iterator it = lst.begin();
    for( ; it != lst.end(); ++it )
    {
      PreferencesReturn p = matchPreferences( prefs, (*it).service(), lst );
      if ( p.type == PreferencesReturn::PRT_DOUBLE )
	sorter.append( TDETraderSorter( (*it).service(), p.f, (*it).preference(), (*it).allowAsDefault() ) );
    }
    qBubbleSort( sorter );

    TQValueList<TDETraderSorter>::Iterator it2 = sorter.begin();
    for( ; it2 != sorter.end(); ++it2 )
      ret.prepend( (*it2).service() );
  }
  else
  {
    KServiceTypeProfile::OfferList::Iterator it = lst.begin();
    for( ; it != lst.end(); ++it )
      ret.append( (*it).service() );
  }

#ifndef NDEBUG
  TQString query = _servicetype;
  if ( !_genericServiceType.isEmpty() ) {
      query += ", ";
      query += _genericServiceType;
  }
  kdDebug(7014) << "query for " << query
                << " : returning " << ret.count() << " offers" << endl;
#endif
  return ret;
}

void TDETrader::virtual_hook( int, void* )
{ /*BASE::virtual_hook( id, data );*/ }

#include "ktrader.moc"
