//
// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2008
// http://flock.com
//
// This file may be used under the terms of the
// GNU General Public License Version 2 or later (the "GPL"),
// http://www.gnu.org/licenses/gpl.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// END FLOCK GPL
//

const SM_CONTRACTID = '@flock.com/search-migratable;1';
const SM_CLASSID    = Components.ID('{24ddbfe0-4216-40cb-a037-2c17ab7d5a47}');
const SM_CLASSNAME  = 'Flock Search Service Migratable';

const SEARCHELSEWHERE_EXCLUSION_PREF  = "flock.search.excludedEngines";

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;


function SearchMigratable() {
}

SearchMigratable.prototype = {
  get migrationName() { return "Search Preferences"; },

  needsMigration: function SM_needsMigration(oldVersion) {
    var minorVersion = oldVersion.substr(0, 3);
    if (minorVersion == "0.7" || minorVersion == "0.9") {
      var prefs = Cc['@mozilla.org/preferences-service;1']
        .getService(Ci.nsIPrefBranch);
      return prefs.prefHasUserValue(SEARCHELSEWHERE_EXCLUSION_PREF);
    } else {
      return false;
    }
  },
  startMigration: function SM_startMigration(oldVersion, listener) {
    var minorVersion = oldVersion.substr(0, 3);

    var prefs = Cc['@mozilla.org/preferences-service;1']
      .getService(Ci.nsIPrefBranch);
    var excluded = prefs.getCharPref(SEARCHELSEWHERE_EXCLUSION_PREF);

    var ctxt = {
      listener: listener,
      minorVersion: minorVersion,

      oldExcluded: excluded.split(","),
      newExcluded: []
    };

    if (minorVersion == "0.7") {
      var engineMap = {};

      var searchService = Cc["@mozilla.org/browser/search-service;1"]
                          .getService(Ci.nsIBrowserSearchService);
      var engines = searchService.getEngines({});

      for each (var engine in engines) {
        engine = engine.wrappedJSObject;

        var engineFile;
        if (engine._unconvertedFile) {
          engineFile = engine._unconvertedFile;
        } else {
          engineFile = engine._file;
        }

        engineMap[engineFile.leafName] = engine.name;
      }

      ctxt.engineMap = engineMap;
    }

    return { wrappedJSObject: ctxt };
  },
  finishMigration: function SM_finishMigration(ctxtWrapper) {
    var ctxt = ctxtWrapper.wrappedJSObject;

    var prefs = Cc['@mozilla.org/preferences-service;1']
      .getService(Ci.nsIPrefBranch);
    prefs.setCharPref(SEARCHELSEWHERE_EXCLUSION_PREF, ctxt.newExcluded.join());
  },
  doMigrationWork: function SM_doMigrationWork(ctxtWrapper) {
    var ctxt = ctxtWrapper.wrappedJSObject;

    var oldEngine = ctxt.oldExcluded.shift();
    var newEngine;

    if (ctxt.minorVersion == "0.7") {
      var engineFilename =
        oldEngine.replace("NC:SearchCategory?engine=urn:search:engine:", "");
      newEngine = ctxt.engineMap[engineFilename];
    } else if (ctxt.minorVersion == "0.9") {
      newEngine = oldEngine;
    }

    if (newEngine) {
      if (newEngine == "Yahoo") {
        newEngine = "Yahoo!";
      }
      ctxt.newExcluded.push(newEngine);
    }

    return Boolean(ctxt.oldExcluded.length);
  },

  getInterfaces: function SM_getInterfaces(countRef) {
    var interfaces = [Ci.flockIMigratable, Ci.nsIClassInfo, Ci.nsISupports];
    countRef.value = interfaces.length;
    return interfaces;
  },
  getHelperForLanguage: function SM_getHelperForLanguage(language) {
    return null;
  },
  contractID: SM_CONTRACTID,
  classDescription: SM_CLASSNAME,
  classID: SM_CLASSID,
  implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
  flags: Ci.nsIClassInfo.SINGLETON,

  QueryInterface: function SM_QueryInterface(iid) {
    if (iid.equals(Ci.flockIMigratable) ||
        iid.equals(Ci.nsIClassInfo) ||
        iid.equals(Ci.nsISupports))
      return this;
    throw Cr.NS_ERROR_NO_INTERFACE;
  }
}


function GenericComponentFactory(ctor) {
  this._ctor = ctor;
}

GenericComponentFactory.prototype = {

  _ctor: null,

  // nsIFactory
  createInstance: function(outer, iid) {
    if (outer != null)
      throw Cr.NS_ERROR_NO_AGGREGATION;
    return (new this._ctor()).QueryInterface(iid);
  },

  // nsISupports
  QueryInterface: function(iid) {
    if (iid.equals(Ci.nsIFactory) ||
        iid.equals(Ci.nsISupports))
      return this;
    throw Cr.NS_ERROR_NO_INTERFACE;
  },
};

var Module = {
  QueryInterface: function(iid) {
    if (iid.equals(Ci.nsIModule) ||
        iid.equals(Ci.nsISupports))
      return this;

    throw Cr.NS_ERROR_NO_INTERFACE;
  },

  getClassObject: function(cm, cid, iid) {
    if (!iid.equals(Ci.nsIFactory))
      throw Cr.NS_ERROR_NOT_IMPLEMENTED;

    if (cid.equals(SM_CLASSID))
      return new GenericComponentFactory(SearchMigratable)

    throw Cr.NS_ERROR_NO_INTERFACE;
  },

  registerSelf: function(cm, file, location, type) {
    var cr = cm.QueryInterface(Ci.nsIComponentRegistrar);
    cr.registerFactoryLocation(SM_CLASSID, SM_CLASSNAME, SM_CONTRACTID,
                               file, location, type);

    var catman = Cc['@mozilla.org/categorymanager;1']
      .getService(Ci.nsICategoryManager);
    catman.addCategoryEntry('flockMigratable', SM_CLASSNAME, SM_CONTRACTID,
                            true, true);
  },

  unregisterSelf: function(cm, location, type) {
    var cr = cm.QueryInterface(Ci.nsIComponentRegistrar);
    cr.unregisterFactoryLocation(SM_CLASSID, location);
  },

  canUnload: function(cm) {
    return true;
  },
};

function NSGetModule(compMgr, fileSpec)
{
  return Module;
}
