// 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 People Service";

// People Service
const FLOCK_PEOPLE_SERVICE_CLASS_NAME = "Flock People Service";
const FLOCK_PEOPLE_SERVICE_CLASS_ID =
        Components.ID("{c04112e6-de37-438e-9ccc-4efae2b75ecb}");
const FLOCK_PEOPLE_SERVICE_CONTRACT_ID = "@flock.com/people-service;1";

const OBSERVER_SERVICE_CONTRACTID = "@mozilla.org/observer-service;1";
const PEOPLESERVICE_TOPIC = "PeopleService";

// People Observer
const FLOCK_PEOPLE_OBSERVER_CLASS_NAME = "Flock People Observer";
const FLOCK_PEOPLE_OBSERVER_CLASS_ID =
        Components.ID("{587c5c29-89c2-4bdf-8996-8915d7f42c3b}");
const FLOCK_PEOPLE_OBSERVER_CONTRACT_ID = "@flock.com/people-observer;1";


/**************************************************************************
 * Component: Flock People Service
 **************************************************************************/

// Constructor.
function flockPeopleService() {
  this._logger = CC["@flock.com/logger;1"]
                 .createInstance(CI.flockILogger);
  this._logger.init("flockPeopleService");
  this._coop = CC["@flock.com/singleton;1"]
               .getService(CI.flockISingleton)
               .getSingleton("chrome://flock/content/common/load-faves-coop.js")
               .wrappedJSObject;
  this._peopleObserverService = 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 flockPeopleService_rdfChanged(ds, type, source,
                                                       predicate, target,
                                                       oldtarget)
    {
      inst._logger.debug("rdfChanged");
      if (!source) {
        inst._logger.error("rdfChanged: source is nothing so exiting");
        return;
      }
      if (type == CI.flockIRDFObserver.TYPE_UNASSERT) {
        if (predicate.Value == "http://www.w3.org/1999/02/22-rdf-syntax-ns#type") {
          inst._logger.debug("removeFriend");
          inst._notifyObservers("removeFriend", source.Value);
        }
      }
      var coopObj = inst._coop.get_from_resource(source);
      if (type == CI.flockIRDFObserver.TYPE_CHANGE) {
        if (coopObj.isInstanceOf(inst._coop.Identity)) {
          if (predicate.Value == "http://flock.com/rdf#lastUpdate" ||
              predicate.Value == "http://flock.com/rdf#avatar" ||
              predicate.Value == "http://flock.com/rdf#unseenMedia")
          {
            inst._logger.debug("updateFriend");
            inst._notifyObservers("updateFriend", source.Value);
          }
        }
      } else if (type == CI.flockIRDFObserver.TYPE_ASSERT) {
        if (coopObj.isInstanceOf(inst._coop.Identity)) {
          inst._logger.debug("addFriend");
          inst._notifyObservers("addFriend", source.Value);
        }
      }
    }
  } 
}


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

flockPeopleService.prototype = new FlockXPCOMUtils.genericComponent(
  FLOCK_PEOPLE_SERVICE_CLASS_NAME,
  FLOCK_PEOPLE_SERVICE_CLASS_ID,
  FLOCK_PEOPLE_SERVICE_CONTRACT_ID,
  flockPeopleService,
  CI.nsIClassInfo.SINGLETON,
  [
    CI.flockIPeopleService,
  ]
);

/**************************************************************************
 * Flock People Service: flockIPeopleService Implementation
 **************************************************************************/

flockPeopleService.prototype.addObserver =
function flockPeopleService_addObserver(aObserver) {
  this._logger.info("addObserver");
  if (!this._hasObservers()) {
    this._logger.info("doesn't have rdf observers...gonna add!");
    this._addRDFObservers();
  }
  this._peopleObserverService.addObserver(aObserver, PEOPLESERVICE_TOPIC, false);
}

flockPeopleService.prototype.removeObserver =
function flockPeopleService_removeObserver(aObserver) {
  this._logger.info("removeObserver");
  this._peopleObserverService.removeObserver(aObserver, PEOPLESERVICE_TOPIC);
  if (!this._hasObservers()) {
    this._logger.info("lose the observers...gonna remove!");
    this._removeRDFObservers();
  }
}

flockPeopleService.prototype._notifyObservers =
function flockPeopleService__notifyObservers(aMethod, aValue) {
  var enumerator = this._peopleObserverService.enumerateObservers(PEOPLESERVICE_TOPIC);
  while (enumerator.hasMoreElements()) {
    var obs = enumerator.getNext();
    obs.QueryInterface(CI.flockIPeopleObserver);
    switch (aMethod)
    {
      case "removeFriend":
        obs.onFriendRemove(aValue);
        break;
      case "updateFriend":
        obs.onFriendUpdate(aValue);
        break;
      case "addFriend":
        obs.onInsertFriend(aValue);
        break;
      default:
        break;
    }
  }  
}

flockPeopleService.prototype._hasObservers =
function flockPeopleService__hasObservers() {
  var enumerator = this._peopleObserverService
                       .enumerateObservers(PEOPLESERVICE_TOPIC);
  return enumerator.hasMoreElements();
}

flockPeopleService.prototype._addRDFObservers =
function flockPeopleService__addRDFObservers() {
  var observable = this._ds.QueryInterface(CI.flockIRDFObservable);
  observable.addArcObserver(CI.flockIRDFObserver.TYPE_CHANGE,
                            null,
                            this._rdfSvc.GetResource("http://flock.com/rdf#lastUpdate"),
                            null,
                            this._rdfObserver);
  observable.addArcObserver(CI.flockIRDFObserver.TYPE_CHANGE,
                            null,
                            this._rdfSvc.GetResource("http://flock.com/rdf#avatar"),
                            null,
                            this._rdfObserver);
  observable.addArcObserver(CI.flockIRDFObserver.TYPE_CHANGE,
                            null,
                            this._rdfSvc.GetResource("http://flock.com/rdf#unseenMedia"),
                            null,
                            this._rdfObserver);
  observable.addArcObserver(CI.flockIRDFObserver.TYPE_CHANGE,
                            null,
                            this._rdfSvc.GetResource("http://flock.com/rdf#isAuthenticated"),
                            null,
                            this._rdfObserver);
  observable.addArcObserver(CI.flockIRDFObserver.TYPE_ASSERT,
                            null,
                            this._rdfSvc.GetResource("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
                            this._rdfSvc.GetResource("http://flock.com/rdf#Identity"),
                            this._rdfObserver);
  observable.addArcObserver(CI.flockIRDFObserver.TYPE_UNASSERT,
                            null,
                            this._rdfSvc.GetResource("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
                            this._rdfSvc.GetResource("http://flock.com/rdf#Identity"),
                            this._rdfObserver);
}

flockPeopleService.prototype._removeRDFObservers =
function flockPeopleService__removeRDFObservers() {
  var observable = this._ds.QueryInterface(CI.flockIRDFObservable);
  observable.removeArcObserver(CI.flockIRDFObserver.TYPE_CHANGE,
                               null,
                               this._rdfSvc.GetResource("http://flock.com/rdf#lastUpdate"),
                               null,
                               this._rdfObserver);
  observable.removeArcObserver(CI.flockIRDFObserver.TYPE_CHANGE,
                               null,
                               this._rdfSvc.GetResource("http://flock.com/rdf#avatar"),
                               null,
                               this._rdfObserver);
  observable.removeArcObserver(CI.flockIRDFObserver.TYPE_CHANGE,
                               null,
                               this._rdfSvc.GetResource("http://flock.com/rdf#unseenMedia"),
                               null,
                               this._rdfObserver);
  observable.removeArcObserver(CI.flockIRDFObserver.TYPE_CHANGE,
                               null,
                               this._rdfSvc.GetResource("http://flock.com/rdf#isAuthenticated"),
                               null,
                               this._rdfObserver);
  observable.removeArcObserver(CI.flockIRDFObserver.TYPE_ASSERT,
                               null,
                               this._rdfSvc.GetResource("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
                               this._rdfSvc.GetResource("http://flock.com/rdf#Identity"),
                               this._rdfObserver);
  observable.removeArcObserver(CI.flockIRDFObserver.TYPE_UNASSERT,
                               null,
                               this._rdfSvc.GetResource("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"),
                               this._rdfSvc.GetResource("http://flock.com/rdf#Identity"),
                               this._rdfObserver);
}

/**************************************************************************
 * BEGIN Flock People Observer
 **************************************************************************/

// Constructor.
function flockPeopleObserver() {
}

/**************************************************************************
 * Flock People Observer: XPCOM Component Creation
 **************************************************************************/

flockPeopleObserver.prototype = new FlockXPCOMUtils.genericComponent(
  FLOCK_PEOPLE_OBSERVER_CLASS_NAME,
  FLOCK_PEOPLE_OBSERVER_CLASS_ID,
  FLOCK_PEOPLE_OBSERVER_CONTRACT_ID,
  flockPeopleObserver,
  CI.nsIClassInfo.SINGLETON,
  [
    CI.flockIPeopleObserver,
  ]
);

/**************************************************************************
 * END Flock People Observer
 **************************************************************************/

/**************************************************************************
 * XPCOM Support - Module Construction
 **************************************************************************/

// Create array of components.
var gComponentsArray = [flockPeopleService, flockPeopleObserver];

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

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