// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2009
// 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;
  this._queue = null;
}

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

StreamHousekeeping.prototype.capAllStreams =
function SHK_capAllStreams() {
  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 resources = faves.GetSources(capItems, RDFS.GetLiteral("true"), true);
  if (this._queue == null) {
    this._queue = [];
    this._startHouseKeeping();
  }
  while (resources.hasMoreElements()) {
    this._queue.push(resources.getNext().QueryInterface(CI.nsIRDFResource));
  }
}

StreamHousekeeping.prototype.capItemsforStream =
function SHK_capItemsforStream(aStreamResource) {
  if (this._queue == null) {
    this._queue = [];
    this._startHouseKeeping();
  } else if (this._queue.indexOf(aStreamResource) != -1) {
    return;
  }
  this._queue.push(aStreamResource);
}

StreamHousekeeping.prototype._startHouseKeeping =
function SHK__startHouseKeeping() {
  this._logger.info("Starting to cap stream items...");
  var inst = this;

  function capItems(aShouldYield) {
    while (inst._queue.length != 0) {
      if (aShouldYield()) {
        yield;
      }

      var obj = inst._coop.get_from_resource(inst._queue.pop());
      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();
        }
      }

      inst._logger.debug("maxItems for " + obj.id() + " is " + maxItems);

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

      inst._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) {
        inst._logger.info("Removing stream item " + item.id());
        item.destroy();

        if (aShouldYield()) {
          yield;
        }
      }
    }
    inst._queue = null;
  }

  FlockScheduler.schedule(null, 0.3, 30, capItems);
}

var gComponentsArray = [StreamHousekeeping];

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