//
// 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 MM_CONTRACTID = "@flock.com/migration-manager;1";
const MM_CLASSID    = Components.ID("{481E822D-937F-4E76-8AFC-F636061B7AC6}");
const MM_CLASSNAME  = "Flock Migration Manager";


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


function DEBUG(x) {
  debug("flockMigrationManager: " + x + "\n");  
}

function MigrationManager() {
}

MigrationManager.prototype = {
  setup: function MM_setup(oldVersion) {
    var prefs = Cc["@mozilla.org/preferences-service;1"]
                .getService(Ci.nsIPrefBranch);
    prefs.setBoolPref("flock.webdetective.upgraded", false);

    var args = Cc['@mozilla.org/supports-array;1']
      .createInstance(Ci.nsISupportsArray);

    var versionStr = Cc['@mozilla.org/supports-cstring;1']
      .createInstance(Ci.nsISupportsCString);
    versionStr.data = oldVersion;
    args.AppendElement(versionStr);
    
    var catman = Cc['@mozilla.org/categorymanager;1']
      .getService(Ci.nsICategoryManager);

    var e = catman.enumerateCategory('flockMigratable');
    while (e.hasMoreElements()) {
      var entry = e.getNext().QueryInterface(Ci.nsISupportsCString);
      if (!entry)
        continue;

      var contractID = catman.getCategoryEntry('flockMigratable', entry.data);
      var service = Cc[contractID].getService(Ci.flockIMigratable);

      try {
        DEBUG("Checking " + service.migrationName + " (" + contractID + ")");
        if (service.needsMigration(oldVersion)) {
          DEBUG(service.migrationName + " needs migration");
          args.AppendElement(service);
        }
      } catch (e) { 
        DEBUG(e);
      }
    }

    DEBUG('Found '+ (args.Count() - 1) + ' services needing migration');
    return args;
  },

  getInterfaces: function MM_getInterfaces(countRef) {
    var interfaces = [Ci.flockIMigrationManager, Ci.nsIClassInfo]
    countRef.value = interfaces.length;
    return interfaces;
  },
  getHelperForLanguage: function MM_getHelperForLanguage(language) {
    return null;
  },
  contractID: MM_CONTRACTID,
  classDescription: MM_CLASSNAME,
  classID: MM_CLASSID,
  implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
  flags: Ci.nsIClassInfo.SINGLETON,

  QueryInterface: function MM_QueryInterface(iid) {
    if (iid.equals(Ci.flockIMigrationManager) ||
        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(MM_CLASSID))
      return new GenericComponentFactory(MigrationManager)

    throw Cr.NS_ERROR_NO_INTERFACE;
  },

  registerSelf: function(cm, file, location, type) {
    var cr = cm.QueryInterface(Ci.nsIComponentRegistrar);
    cr.registerFactoryLocation(MM_CLASSID, MM_CLASSNAME, MM_CONTRACTID,
                               file, location, type);
  },

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

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

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