// 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;

Components.utils.import("resource:///modules/FlockXPCOMUtils.jsm");
FlockXPCOMUtils.debug = false;

const MODULE_NAME = "Flock Account Service";

// Account Service
const FLOCK_SERVICE_CLASS_NAME = "Flock Account Service";
const FLOCK_SERVICE_CLASS_ID =
        Components.ID("{23f2e8b4-9599-11dc-8314-0800200c9a66}");
const FLOCK_SERVICE_CONTRACT_ID = "@flock.com/account-service;1";

const OBSERVER_SERVICE_CONTRACTID = "@mozilla.org/observer-service;1";
const ACCOUNTSERVICE_TOPIC = "AccountService";

// Account Observer
const FLOCK_OBSERVER_CLASS_NAME = "Flock Account Observor";
const FLOCK_OBSERVER_CLASS_ID =
        Components.ID("{4ea94378-9599-11dc-8314-0800200c9a66}");
const FLOCK_OBSERVER_CONTRACT_ID = "@flock.com/account-observer;1";

/**************************************************************************
 * Component: Flock Account Service
 **************************************************************************/

// Constructor.
function flockAccountService() {
  this._logger = CC["@flock.com/logger;1"]
                 .createInstance(CI.flockILogger);
  this._logger.init("flockAccountService");
  this._coop = CC["@flock.com/singleton;1"]
               .getService(CI.flockISingleton)
               .getSingleton("chrome://flock/content/common/load-faves-coop.js")
               .wrappedJSObject;
  this._accountObserverService = CC[OBSERVER_SERVICE_CONTRACTID]
                                 .getService(CI.nsIObserverService);
  this._rdfSvc = CC["@mozilla.org/rdf/rdf-service;1"]
                 .getService(CI.nsIRDFService);

  this._ds = this._rdfSvc.GetDataSource("rdf:flock-favorites");
  var inst = this;
  this._rdfObserver = {
    rdfChanged: function flockAccountService_rdfChanged(ds, type, source,
                                                        predicate, target,
                                                        oldtarget)
    {
      inst._logger.debug("rdfChanged()");
      if (!source) {
        inst._logger.debug("rdfChanged: source is nothing so exiting");
        return null;
      }
      var coopObj = inst._coop.get_from_resource(source);
      if (!coopObj) {
        inst._logger.debug("rdfChanged: coopObj is nothing so exiting");
        return null;
      }

      if (coopObj.isInstanceOf(inst._coop.Account)) {
        inst._logger.debug("rdfChanged: coopObj is an Account");
        var account = null;
        if (coopObj.serviceId) {
          account = CC[coopObj.serviceId].getService(CI.flockIWebService)
                                         .getAccount(coopObj.id());
        }
        if (predicate.Value == "http://flock.com/rdf#isAuthenticated") {
          if (account instanceof CI.flockISocialAccount ||
              account instanceof CI.flockIMediaAccount ||
              account instanceof CI.flockIWebmailAccount)
          {
            inst._logger.debug("rdfChanged: Authenticate account");
            if (coopObj.isAuthenticated) {
              inst._notifyObservers("accountIsAuthenticated", source.Value);
            } else {
              inst._notifyObservers("accountNotAuthenticated", source.Value);
            }
            inst._logger.debug("Account authentication changed");
          }
        } else if (predicate.Value == "http://flock.com/rdf#isRefreshing") {
          if (account instanceof CI.flockISocialAccount) {
            inst._logger.debug("rdfChanged: Refresh account");
            if (coopObj.isRefreshing) {
              inst._logger.debug("rdfChanged: isRefreshing == true\n");
              inst._notifyObservers("accountRefreshing", source.Value);
            } else {
              inst._logger.debug("rdfChanged: isRefreshing == false");
              inst._notifyObservers("accountNotRefreshing", source.Value);
            }
          }
        }
      }
    }
  }
}


/**************************************************************************
* Flock Account Service: XPCOM Component Creation
**************************************************************************/

flockAccountService.prototype = new FlockXPCOMUtils.genericComponent(
  FLOCK_SERVICE_CLASS_NAME,
  FLOCK_SERVICE_CLASS_ID,
  FLOCK_SERVICE_CONTRACT_ID,
  flockAccountService,
  CI.nsIClassInfo.SINGLETON,
  [
    CI.flockIAccountService,
  ]
);

/**************************************************************************
 * Flock Account Service: flockIAccountService Implementation
 **************************************************************************/

flockAccountService.prototype.addObserver =
function flockAccountService_addObserver(aObserver) {
  this._logger.info("addObserver");
  if (!this._hasObservers()) {
    this._logger.info("doesn't have rdf observers...add!");
    this._addRDFObservers();
  }
  this._accountObserverService
      .addObserver(aObserver, ACCOUNTSERVICE_TOPIC, false);
}

flockAccountService.prototype.removeObserver =
function flockAccountService_removeObserver(aObserver) {
  this._logger.info("removeObserver");
  this._accountObserverService
      .removeObserver(aObserver, ACCOUNTSERVICE_TOPIC);
  if (!this._hasObservers()) {
    this._logger.info("no one needing observers..remove!");
    this._removeRDFObservers();
  }
}

flockAccountService.prototype.fireAccountRemoved =
function flockAccoutService_fireAccountRemoved(aAccountURN) {
  var enumerator = this._accountObserverService
                       .enumerateObservers(ACCOUNTSERVICE_TOPIC);
  while (enumerator.hasMoreElements()) {
    var obs = enumerator.getNext();
    obs.QueryInterface(CI.flockIAccountObserver);
    obs.onAccountRemoved(aAccountURN);
  }
}

flockAccountService.prototype._notifyObservers =
function flockAccountService__notifyObservers(aMethod, aValue) {
  var enumerator = this._accountObserverService
                       .enumerateObservers(ACCOUNTSERVICE_TOPIC);
  while (enumerator.hasMoreElements()) {
    var obs = enumerator.getNext();
    obs.QueryInterface(CI.flockIAccountObserver);
    switch (aMethod)
    {
      case "accountNotRefreshing":
        obs.onAccountNoLongerRefreshing(aValue);
        break;
      case "accountRefreshing":
        obs.onAccountRefreshing(aValue);
        break;
      case "accountIsAuthenticated":
        obs.onAccountAuthenticated(aValue);
        break;
      case "accountNotAuthenticated":
        obs.onAccountUnauthenticated(aValue);
        break;
      default:
        break;
    }
  }
}

flockAccountService.prototype._hasObservers =
function flockAccountService__hasObservers() {
  var enumerator = this._accountObserverService
                       .enumerateObservers(ACCOUNTSERVICE_TOPIC);
  return enumerator.hasMoreElements();
}

flockAccountService.prototype._addRDFObservers =
function flockAccountService__addRDFObservers() {
  var observable = this._ds.QueryInterface(CI.flockIRDFObservable);
  var authPredicate = "http://flock.com/rdf#isAuthenticated";
  var refreshPredicate = "http://flock.com/rdf#isRefreshing";
  observable.addArcObserver(CI.flockIRDFObserver.WATCH_TYPES,
                            null,
                            this._rdfSvc.GetResource(authPredicate),
                            null,
                            this._rdfObserver);
  observable.addArcObserver(CI.flockIRDFObserver.WATCH_TYPES,
                            null,
                            this._rdfSvc.GetResource(refreshPredicate),
                            null,
                            this._rdfObserver);
}

flockAccountService.prototype._removeRDFObservers =
function flockAccountService__removeRDFObservers() {
  var observable = this._ds.QueryInterface(CI.flockIRDFObservable);
  var authPredicate = "http://flock.com/rdf#isAuthenticated";
  var refreshPredicate = "http://flock.com/rdf#isRefreshing";
  observable.removeArcObserver(CI.flockIRDFObserver.WATCH_TYPES,
                               null,
                               this._rdfSvc.GetResource(authPredicate),
                               null,
                               this._rdfObserver);
  observable.removeArcObserver(CI.flockIRDFObserver.WATCH_TYPES,
                               null,
                               this._rdfSvc.GetResource(refreshPredicate),
                               null,
                               this._rdfObserver);
}
/**************************************************************************
 * BEGIN Flock Account Observer
 **************************************************************************/

// Constructor.
function flockAccountObserver() {
  
}

/**************************************************************************
 * Flock Account: XPCOM Component Creation
 **************************************************************************/

flockAccountObserver.prototype = new FlockXPCOMUtils.genericComponent(
  FLOCK_OBSERVER_CLASS_NAME,
  FLOCK_OBSERVER_CLASS_ID,
  FLOCK_OBSERVER_CONTRACT_ID,
  flockAccountObserver,
  CI.nsIClassInfo.SINGLETON,
  [
    CI.flockIAccountObserver,
  ]
);
/**************************************************************************
 * XPCOM Support - Module Construction
 **************************************************************************/

// Create array of components.
var gComponentsArray = [flockAccountService, flockAccountObserver];

// Generate a module for XPCOM to find.
var NSGetModule = FlockXPCOMUtils.generateNSGetModule(MODULE_NAME,
                                                      gComponentsArray);

/**************************************************************************
 * END XPCOM Support
 **************************************************************************/
