// Author: Thach Nguyen <thach.nguyen@rmit.edu.au>, (C) 2007
//
// Copyright: See COPYING file that comes with this distribution
//

// Adapted from Tellico


#include <config.h>

#include "searchmanager.h"

#include "z3950searcher.h"
#include "srusearcher.h"
#include "entrezsearcher.h"
#include "ieeexploresearcher.h"
#include "woksearcher.h"
#include "scholarsearcher.h"
#include "citebasesearcher.h"
#include "arxivsearcher.h"
#include "spiressearcher.h"
#include "scitationsearcher.h"

#include <kglobal.h>
#include <kconfig.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kmimetype.h>
#include <kstandarddirs.h>
#include <dcopref.h>
#include <iostream>

#include <config.h>

using namespace std;

searchManager* searchManager::s_self = 0;

searchManager::searchManager() : QObject()
{
    searchersList.setAutoDelete(true);
    loadSearchers();
    m_loadDefaults = false;

    m_keyMap.insert(Title,      i18n("Title"));
    m_keyMap.insert(Author,     i18n("Author"));
    m_keyMap.insert(Keyword,    i18n("Keywords"));
    m_keyMap.insert(Subject,    i18n("Subject"));
    m_keyMap.insert(All,        i18n("All fields"));
    m_keyMap.insert(Journal,        i18n("Journal"));
    m_keyMap.insert(Year,    i18n("Year"));
    m_keyMap.insert(Topic,    i18n("Topic"));
    m_keyMap.insert(Subject,    i18n("Subject"));
    m_keyMap.insert(Abstract,    i18n("Abstract"));
}

searchManager::~searchManager()
{}

void searchManager::loadSearchers()
{
    //  myDebug() << "Manager::loadFetchers()" << endl;
    searchersList.clear();

    KConfig* config = KGlobal::config();
    if(config->hasGroup(QString::fromLatin1("Data Sources")))
    {
        KConfigGroupSaver saver(config, QString::fromLatin1("Data Sources"));
        int nSources = config->readNumEntry("Sources Count", 0);
        for(int i = 0; i < nSources; ++i)
        {
            QString group = QString::fromLatin1("Data Source %1").arg(i);
            searcher* f = createSearcher(config, group);
            if(f)
            {
                searchersList.append(f);
            }
        }
        m_loadDefaults = false;
    }
    else
    { // add default sources
        //	  m_searchers = defaultSearchers();
        m_loadDefaults = true;
    }
}

QStringList searchManager::sources()
{
    QStringList sources;
    //searcher* it = m_searchers.first();

    for ( uint i = 0; i < searchersList.count(); ++i )
    {
        if ( searchersList.at(i) )
            sources << searchersList.at(i)->source();

    }
    return sources;
}



searcher* searchManager::createSearcher(KConfig* config_, const QString& group_)
{
    if(!config_->hasGroup(group_))
    {
        cerr << "Manager::createFetcher() - no config group for " << group_.ascii() << endl;
        return 0;
    }

    KConfigGroupSaver groupSaver(config_, group_);

    int type = config_->readNumEntry("Type", Unknown);
    if(type == Unknown)
    {
        cerr << "Manager::createFetcher() - unknown type " << type << ", skipping" << endl;
        return 0;
    }

    searcher* f = 0;
    switch(type)
    {
    case Z3950:
#if HAVE_YAZ
        f = new Z3950Searcher(this);
#endif
        break;
    case SRU:
        f = new SRUSearcher(this);
        break;
    case Entrez:
        f = new EntrezSearcher(this);
        break;
    case IEEEXplore:
        f = new IEEEXploreSearcher(this);
        break;
    case WOK:
        f = new WOKSearcher(this);
        break;
    case Scholar:
        f = new ScholarSearcher(this);
        break;
    case Citebase:
        f = new CitebaseSearcher(this);
        break;
    case ArXiv:
	f = new ArXivSearcher(this);
	break;
    case Spires:
	f = new SpiresSearcher(this);
	break;
    case Scitation:
	f = new ScitationSearcher(this);
	break;
    case Unknown:
	break;
    default:
        break;
    }
    if(f)
    {
        f->readConfig(config_, group_);
    }
    return f;
}


SearchKey searchManager::searchKey(const QString& key_) const
{
    for(SearchKeyMap::ConstIterator it = m_keyMap.begin(); it != m_keyMap.end(); ++it)
    {
        if(it.data() == key_)
        {
            return it.key();
        }
    }
}

QString searchManager::searchKeyString(const SearchKey& key_) const
{
    for(SearchKeyMap::ConstIterator it = m_keyMap.begin(); it != m_keyMap.end(); ++it)
    {
        if(it.key() == key_)
        {
            return it.data();
        }
    }
}

int searchManager::maxSearchTerms(const QString& source_)
{
	searcher *s;
	for ( s = searchersList.first(); s; s = searchersList.next() )
	{
		if(source_ == s->source())
		{
			return 	s->maxSearchTerms();
		}
	}
}


QStringList searchManager::searchKeyList(const QString& source_)
{
    searcher *s;
    for ( s = searchersList.first(); s; s = searchersList.next() )
    {
        if(source_ == s->source())
        {
            return 	s->searchKey();
        }
    }
}

QString searchManager::helpURL(const QString& source)
{
	searcher *s;
    for ( s = searchersList.first(); s; s = searchersList.next() )
    {
        if(source == s->source())
        {
            return 	s->helpURL();
        }
    }
}

void searchManager::startSearch(const QString& source, SearchKey key1, SearchKey key2, SearchKey key3 , const QString& value1, const QString& value2, const QString& value3, int operator1, int operator2)
{
    cerr << "Starting searching " << source.ascii() << "\n";

    searcher *s;
    for ( s = searchersList.first(); s; s = searchersList.next() )
    {
        if(source == s->source())
        {
            connect(s, SIGNAL(signalResultFound( BibEntry* ) ), SIGNAL(signalResultFound( BibEntry * ) ) );
            connect(s, SIGNAL(signalQueryResult(unsigned int )), SIGNAL(signalQueryResult( unsigned int ) ) );
            connect(s, SIGNAL(signalMessage( QString, int) ), SIGNAL(signalMessage( QString, int) ) );
            connect(s, SIGNAL(signalDone( searcher* ) ), SLOT(slotSearcherDone( searcher *) ) );
            s->search(key1, key2, key3, value1, value2, value3, operator1, operator2);
            break;
        }
    }
}


void searchManager::startSearch(const QString& source, QString queryString)
{
    cerr << "Starting searching " << source.ascii() << "\n";

    searcher *s;
    for ( s = searchersList.first(); s; s = searchersList.next() )
    {
        if(source == s->source())
        {
            connect(s, SIGNAL(signalResultFound( BibEntry* ) ), SIGNAL(signalResultFound( BibEntry * ) ) );
            connect(s, SIGNAL(signalQueryResult(unsigned int )), SIGNAL(signalQueryResult( unsigned int ) ) );
            connect(s, SIGNAL(signalMessage( QString, int) ), SIGNAL(signalMessage( QString, int) ) );
            connect(s, SIGNAL(signalDone( searcher* ) ), SLOT(slotSearcherDone( searcher *) ) );
            s->search(queryString);
            break;
        }
    }
}

void searchManager::stop()
{
    for ( searcher *s = searchersList.first(); s; s = searchersList.next() )
    {
        if(s->isSearching())
        {
            s->stop();
        }
    }
}

void searchManager::retrieveRange(unsigned int start, unsigned int end)
{
    searcher *s;
    for ( s = searchersList.first(); s; s = searchersList.next() )
    {
        if (s->isWaitingRetrieveRange())
            s->retrieveRange(start, end);
    }

}


QString searchManager::typeName(Type type_)
{
    switch(type_)
    {
#if HAVE_YAZ
    case Z3950: return Z3950Searcher::defaultName();
#endif
    case Entrez: return EntrezSearcher::defaultName();
    case SRU: return SRUSearcher::defaultName();
	case IEEEXplore: return IEEEXploreSearcher::defaultName();
	case WOK: return WOKSearcher::defaultName();
	case Scholar: return ScholarSearcher::defaultName();
	case Citebase: return CitebaseSearcher::defaultName();
	case ArXiv: return ArXivSearcher::defaultName();
	case Spires: return SpiresSearcher::defaultName();
	case Scitation: return ScitationSearcher::defaultName();
    default: break;
    }
    return QString::null;
}

void searchManager::slotSearcherDone(searcher *searcher_)
{
    searcher_->disconnect(); // disconnect all signals
    emit signalDone();
}

SearchMap searchManager::sourceMap()
{
    SearchMap map;
#if HAVE_YAZ
    map.insert(Z3950, Z3950Searcher::defaultName());
#endif
    map.insert(SRU, SRUSearcher::defaultName());
    map.insert(Entrez, EntrezSearcher::defaultName());
    map.insert(IEEEXplore, IEEEXploreSearcher::defaultName());
	map.insert(WOK, WOKSearcher::defaultName());
	map.insert(Scholar, ScholarSearcher::defaultName());
	map.insert(Citebase, CitebaseSearcher::defaultName());
	map.insert(ArXiv, ArXivSearcher::defaultName() );
	map.insert(Spires, SpiresSearcher::defaultName() );
	map.insert(Scitation, ScitationSearcher::defaultName() );
    return map;
}

searcher* searchManager::searcherFromName(QString source){
  searcher *s;
  for ( s = searchersList.first(); s; s = searchersList.next() )
    {
        if(source == s->source())
        {
		return s;
	}
  }
	return 0;
}

QPixmap searchManager::searcherIcon(searcher *s) {
        if (!s)
	return QPixmap();
#if HAVE_YAZ
		if(s->type() == Z3950){
			Z3950Searcher *searcher = dynamic_cast<Z3950Searcher*>(s);
			KURL u;
			u.setProtocol(QString::fromLatin1("http"));
			u.setHost(searcher->host());
			QString icon = favIcon(u);
			if(u.isValid() && !icon.isEmpty()) {
      				return SmallIcon(icon);
    			}
  		} 
		else
#endif
			return searcherIcon(s->type());	
	
}


QPixmap searchManager::searcherIcon(Type type_) {
  QString name;
  switch(type_) {
    case Z3950:
      name = QString::fromLatin1("network"); break; // rather arbitrary
    case SRU:
      name = QString::fromLatin1("network_local"); break; // just to be different than z3950
    case Entrez:
      name = favIcon("http://www.ncbi.nlm.nih.gov"); break;    
    case IEEEXplore:
      name = favIcon("http://ieeexplore.ieee.org"); break;
    case WOK:
      name = favIcon("http://scientific.thomson.com"); break;
    case Scholar:
      name = favIcon("http://scholar.google.com"); break;		
    case ArXiv:
      name = favIcon("http://arxiv.org"); break;
    case Citebase:
      name = favIcon("http://citebase.org"); break;
    case Spires:
      name = favIcon("http://www.slac.stanford.edu/spires"); break;
    case Scitation:
      name = favIcon("http://scitation.aip.org"); break;
    default: break;
  }

  return name.isEmpty() ? QPixmap() : SmallIcon(name);
}

QString searchManager::favIcon(const KURL& url_) {
  DCOPRef kded("kded", "favicons");
  DCOPReply reply = kded.call("iconForURL(KURL)", url_);
  QString iconName = reply.isValid() ? reply : QString();
  if(!iconName.isEmpty()) {
    return iconName;
  } else {
    // go ahead and try to download it for later
    kded.call("downloadHostIcon(KURL)", url_);
  }
  return KMimeType::iconForURL(url_);
}




//#include "../searchmanager.moc"
