// 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 CC = Components.classes;
const CI = Components.interfaces;
const CR = Components.results;
const CU = Components.utils;

CU.import("resource:///modules/FlockXPCOMUtils.jsm");
CU.import("resource:///modules/FlockPrefsUtils.jsm");

const COOKIE_SCAN_CLASSNAME = "Flock OOBE Cookie Scan";
const COOKIE_SCAN_CLASSID =
  Components.ID("{966db6f8-7850-4751-9f6f-6cdef9c06e0f}");
const COOKIE_SCAN_CONTRACTID = "@flock.com/oobe-cookie-scan;1";

const WD_NAME = "flockoobe";

const PREF_FLOCK_IMPORT_SOURCE = "flock.firstrun.import.source";

function CookieScan() {
  this._logger = CC["@flock.com/logger;1"].createInstance(CI.flockILogger);
  this._logger.init("cookiescan");

  var acUtils = CC["@flock.com/account-utils;1"]
                .getService(CI.flockIAccountUtils);

  this._wd = acUtils.useWebDetective(WD_NAME + ".xml");

  this._metrics = CC["@flock.com/metrics-service;1"]
                  .getService(CI.flockIMetricsService);
}

CookieScan.prototype = new FlockXPCOMUtils.genericComponent(
  COOKIE_SCAN_CLASSNAME,
  COOKIE_SCAN_CLASSID,
  COOKIE_SCAN_CONTRACTID,
  CookieScan,
  CI.nsIClassInfo.SINGLETON,
  [CI.flockIOOBECookieScan]
);


let gServiceRankings = {
  "people": [ "facebook", "myspace", "digg", "twitter" ],
  "media": [ "youtube", "flickr", "searchvideo", "revver" ],
  "webmail": [ "gmail", "yahoomail", "aolmail" ],
  "blog": [ "blogger", "wordpress", "livejournal", "typepad", "blogsome",
            "xanga" ],
  "upload": [ "photobucket", "picasa", "flickr" ],
  "onlinefaves": [ "delicious", "magnolia" ]
};

let gCategoryRankings = [
  "people", "media", "webmail", "blog", "upload", "onlinefaves"
];

let gHistoryOnlyServices = [
  "@flock.com/webservice/revver;1",
  "@flock.com/?photo-api-searchvideo;1"
];

let gRequireHistory = {
  "picasa": true,
};

let gUseLoginHistory = {
  "blogger": true,
  "wordpress": true,
  "livejournal": true,
  "typepad": true,
  "blogsome": true,
  "xanga": true
};

CookieScan.prototype.getServiceData =
function CS_getServiceData() {
  this._loadRankings();
  this._loadServiceInfo();

  this._serviceData = [];

  this._categories = {};
  for each (let category in gCategoryRankings) {
    this._categories[category] = { serviceList: [], found: {} };
  }

  let importSource = FlockPrefsUtils.getCharPref(PREF_FLOCK_IMPORT_SOURCE);

  if (importSource) {
    this._scanCookies();
    this._scanHistory();
    this._fillServiceData();
  }

  let noHits = (this._serviceData.length == 0);

  this._fillDefaultServiceData();
  this._addOtherCategory(noHits, importSource);

  return this._serviceData;
}

CookieScan.prototype._fillServiceData =
function CS__fillServiceData() {
  for each (let category in gCategoryRankings) {
    let categoryInfo = this._categories[category];
    let serviceList = categoryInfo.serviceList;
    if (serviceList.length) {
      this._serviceData.push({ category: category, services: serviceList });
      this._reportServicesFound(serviceList);
    }
  }
};

CookieScan.prototype._fillDefaultServiceData =
function CS__fillDefaultServiceData() {
  for each (let category in gCategoryRankings) {
    let categoryInfo = this._categories[category];
    let serviceList = categoryInfo.serviceList;
    if (serviceList.length == 0) {
      for each (let name in gServiceRankings[category]) {
        let info = this._serviceInfo[name];
        if (info) {
          serviceList.push(this._createServiceEntry(info));
        }
      }
      this._serviceData.push({ category: category, services: serviceList });
    }
  }
}

CookieScan.prototype._addOtherCategory =
function CS__addOtherCategory(aNoHits, aImportSource) {
  let pos = aNoHits ? 0 : gCategoryRankings.length;
  this._serviceData.splice(pos, 0, { category: "other", services: null });
};

CookieScan.prototype._fillCategories =
function CS__fillCategories(aHitFunc) {
  for (let [category, categoryState] in Iterator(this._categories)) {
    let categoryList = categoryState.serviceList;
    let categoryFound = categoryState.found;

    let foundList = [];

    for each (let name in gServiceRankings[category]) {
      if (categoryFound[name]) {
        continue;
      }

      let info = this._serviceInfo[name];
      if (!info) {
        continue;
      }

      try {
        if (aHitFunc(info.service)) {
          categoryFound[info.name] = true;
          foundList.push(info);
        }
      } catch (ex) {
        // Something went wrong with the hit function, just ignore
      }
    }

    for each (let info in foundList) {
      categoryList.push(this._createServiceEntry(info));
    }
  }
};

CookieScan.prototype._createServiceEntry =
function CS__createServiceEntry(aServiceInfo) {
  let service = aServiceInfo.service;

  let url = service.url;
  if (service instanceof CI.flockILoginWebService) {
    url = service.loginURL;
  }

  return { name: aServiceInfo.name, url: url, contractId: service.contractId };
};

CookieScan.prototype._loadRankings =
function CS__loadRankings() {
  let nsJSON = CC["@mozilla.org/dom/json;1"].createInstance(CI.nsIJSON);

  let ranking;

  ranking = this._wd.getLocalizedString(WD_NAME, "serviceRankings", null);
  let serviceRankings = nsJSON.decode(ranking);
  if (serviceRankings) {
    gServiceRankings = serviceRankings;
  }

  ranking = this._wd.getLocalizedString(WD_NAME, "categoryRankings", null);
  let categoryRankings = nsJSON.decode(ranking);
  if (categoryRankings) {
    gCategoryRankings = categoryRankings;
  }
};

CookieScan.prototype._loadServiceInfo =
function CS__loadServiceInfo() {
  let serviceInfo = {};

  function addService(aCID) {
    try {
      let service = CC[aCID].getService(CI.flockIWebService);
      let name = service.shortName;
      serviceInfo[name] = { name: name, service: service };
    } catch (ex) {
      // bad service implementation, ignore
    }
  }

  let wd = CC["@flock.com/web-detective;1"].getService(CI.flockIWebDetective);

  let catMgr = CC["@mozilla.org/categorymanager;1"]
               .getService(CI.nsICategoryManager);
  let svcEnum = catMgr.enumerateCategory("wsm-startup");

  while (svcEnum.hasMoreElements()) {
    let entry = svcEnum.getNext().QueryInterface(CI.nsISupportsCString).data;
    let contractID = catMgr.getCategoryEntry("wsm-startup", entry);
    addService(contractID);
  }

  for each (let contractID in gHistoryOnlyServices) {
    addService(contractID);
  }

  this._serviceInfo = serviceInfo;
};

CookieScan.prototype._scanCookies =
function CS__scanCookies() {
  function cookieHit(aService) {
    if (gRequireHistory[aService.shortName]) {
      return false;
    }

    aService.QueryInterface(CI.flockILoginWebService);
    return Boolean(aService.getSessionValue());
  }

  this._fillCategories(cookieHit);
};

CookieScan.prototype._scanHistory =
function CS__scanHistory() {
  let ios = CC["@mozilla.org/network/io-service;1"]
            .getService(CI.nsIIOService);
  let navHistory = CC["@mozilla.org/browser/nav-history-service;1"]
                   .getService(CI.nsINavHistoryService);

  let query = navHistory.getNewQuery();
  let options = navHistory.getNewQueryOptions();

  query.domainIsHost = false;

  function historyHit(aService) {
    let useLoginURL = gUseLoginHistory[aService.shortName] ? true : false;

    if (useLoginURL) {
      aService.QueryInterface(CI.flockILoginWebService);
      let uri = ios.newURI(aService.loginURL, null, null);

      query.domain = null;
      query.uri = uri;
    } else {
      let uri = ios.newURI(aService.url, null, null);

      query.domain = uri.host.replace(/^www\./, "");
      query.uri = null;
    }

    let queryResults = navHistory.executeQuery(query, options);
    let resultsRoot = queryResults.root;
    resultsRoot.containerOpen = true;

    return resultsRoot.hasChildren;
  }

  this._fillCategories(historyHit);
};

CookieScan.prototype._reportServicesFound =
function CS__reportServicesFound(aServiceList) {
  for each (let serviceInfo in aServiceList) {
    this._metrics.report("GettingStarted-OOBE2-ServiceFound",
                         serviceInfo.name);
  }
};

var gComponentsArray = [CookieScan];

var NSGetModule = FlockXPCOMUtils.generateNSGetModule(COOKIE_SCAN_CLASSNAME,
                                                      gComponentsArray);
