// 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 SHK_CONTRACTID = "@flock.com/stream-housekeeping;1";
const SHK_CLASSID    = Components.ID("{c4a5d459-3644-4557-9cd6-a3a4cb09c59a}");
const SHK_CLASSNAME  = "Flock Stream Housekeeping";


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/FlockScheduler.jsm");

const PREF_STREAM_MAXITEMS = "flock.streams.maxItems";


function getDefaultMaxItems() {
  var prefs = CC["@mozilla.org/preferences-service;1"]
              .getService(CI.nsIPrefBranch);
  return prefs.getIntPref(PREF_STREAM_MAXITEMS);
}


function StreamHousekeeping() {
  this._logger = CC["@flock.com/logger;1"].createInstance(CI.flockILogger);
  this._logger.init("streamhousekeeping");
  this._logger.info("starting up...");

  this._coop = CC["@flock.com/singleton;1"]
               .getService(CI.flockISingleton)
               .getSingleton("chrome://flock/content/common/load-faves-coop.js")
               .wrappedJSObject;
}

StreamHousekeeping.prototype = new FlockXPCOMUtils.genericComponent(
  SHK_CLASSNAME,
  SHK_CLASSID,
  SHK_CONTRACTID,
  StreamHousekeeping,
  CI.nsIClassInfo.SINGLETON,
  [
    CI.flockIStreamHousekeeping,
    CI.flockIHousekeeping
  ]
);

StreamHousekeeping.prototype._xpcom_categories = [
  { category: "flockHousekeeping" }
];

StreamHousekeeping.prototype.runHousekeeping =
function SHK_runHousekeeping() {
  this._logger.info("running stream housekeeping...");

  const RDFS = CC["@mozilla.org/rdf/rdf-service;1"]
               .getService(CI.nsIRDFService);
  var capItems = RDFS.GetResource("http://flock.com/rdf#capItems");

  var faves = RDFS.GetDataSource("rdf:flock-favorites");

  var enumerator = {
    _coop: this._coop,
    _resources: faves.GetSources(capItems, RDFS.GetLiteral("true"), true),
    hasMoreElements: function SHK_enumerator_hasMoreElements() {
      return this._resources.hasMoreElements();
    },
    getNext: function SHK_enumerator_getNext() {
      var res = this._resources.getNext().QueryInterface(CI.nsIRDFResource);
      return this._coop.get_from_resource(res);
    }
  };

  this._capItemsForObjects(enumerator);
}

StreamHousekeeping.prototype.capItemsForObject =
function SHK_capItemsForObject(aURN) {
  var singletonEnumerator = {
    _coop: this._coop,
    _consumed: false,
    hasMoreElements: function SHK_singletonEnumerator_hasMoreElements() {
      return !this._consumed;
    },
    getNext: function SHK_singletonEnumerator_getNext() {
      this._consumed = true;
      return this._coop.get(aURN);
    }
  };

  this._capItemsForObjects(singletonEnumerator);
}

StreamHousekeeping.prototype._capItemsForObjects =
function SHK__capItemsForObjects(aObjects) {
  var logger = this._logger;

  function capItems(aShouldYield) {
    while (aObjects.hasMoreElements()) {
      if (aShouldYield()) {
        yield;
      }

      var obj = aObjects.getNext();
      if (!obj || !obj.capItems) {
        continue;
      }

      var maxItems = obj.maxItems;
      if (maxItems <= 0) {
        if (obj.serviceId) {
          try {
            var service = CC[obj.serviceId].getService(CI.nsISupports);
            if (service instanceof CI.flockIStreamOwner) {
              maxItems = service.getMaxItemsForStream(obj.id());
            }
          } catch (ex) {
            // fall through to default setting below
          }
        }

        if (maxItems <= 0) {
          maxItems = getDefaultMaxItems();
        }
      }

      logger.debug("maxItems for object " + obj.id() + " is " + maxItems);

      var removeCount = obj.count - maxItems;
      if (removeCount <= 0) {
        continue;
      }

      logger.info("Removing " + removeCount
                  + " of " + obj.count
                  + " items from " + obj.id());

      var itemsToRemove = [];

      var items = obj.children.enumerate();
      while (items && items.hasMoreElements()) {
        var item = items.getNext();
        if (item && !item.flagged) {
          itemsToRemove.push(item);
          if (itemsToRemove.length >= removeCount) {
            break;
          }
        }
      }

      if (aShouldYield()) {
        yield;
      }

      for each (var item in itemsToRemove) {
        if (!item.flagged) {
          logger.info("Removing " + item.id());
          item.destroy();
        }

        if (aShouldYield()) {
          yield;
        }
      }
    }
  }

  FlockScheduler.schedule(null, 0.1, 10, capItems);
}

var gComponentsArray = [StreamHousekeeping];

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