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

const FLOCK_ERROR_CID = Components.ID("{2DB3FC08-E5F8-11DA-8ACF-C9DED1573834}");
const FLOCK_ERROR_CONTRACTID = "@flock.com/error;1";
const FLOCK_ERROR_IID = CI.flockIError;

const FLOCK_LOGGER_CONTRACTID = "@flock.com/logger;1";
const STRING_BUNDLE_CONTRACTID = "@mozilla.org/intl/stringbundle;1";
const STRING_BUNDLE_IID = CI.nsIStringBundleService;
const STRING_BUNDLE_URL = "chrome://flock/locale/common/flockErrors.properties";

const STRING_KEY_PREFIX = "flock.service.errorCode_";
// Alternate string when we want to substitute in a service name or similar.
const STRING_KEY_SUBST_SUFFIX = ".subst";

function flockError() {
  this._logger = CC[FLOCK_LOGGER_CONTRACTID].createInstance(CI.flockILogger);
  this._logger.init("flockerror");
}

flockError.prototype = {
  errorCode: null,
  serviceErrorCode: "",
  serviceErrorString: "",
  serviceName: "",
  QueryInterface: function QueryInterface(aIid) {
    if (!aIid.equals(CI.nsISupports) &&
        !aIid.equals(FLOCK_ERROR_IID))
    {
      throw CR.NS_ERROR_NO_INTERFACE;
    }
    return this;
  }
};

flockError.prototype.__defineGetter__("errorString",
                                      function () {
                                        return this.lookUp(this.errorCode,
                                                           this.serviceName);
                                      });

//////////////////////////////////////////////////////////////////////////////
// internal methods
//////////////////////////////////////////////////////////////////////////////

flockError.prototype.lookUp =
function flockError_lookUp(aErrorCode, aServiceName)
{
  var msg;
  var stringKey = STRING_KEY_PREFIX + aErrorCode;
  // The generated string key may not be valid; catch the exception.

  try {
    if (aServiceName != "") {
      // 1: array length
      msg = this.mStringBundle
                .formatStringFromName(stringKey + STRING_KEY_SUBST_SUFFIX,
                                      [aServiceName], 1);
    } else {
      msg = this.mStringBundle.GetStringFromName(stringKey);
    }
  } catch(ex) {
    if (aErrorCode == null) {
      // Avoid an infinite recursive loop
      this._logger.error("The entity "
                         + stringKey
                         + " is missing, this localization is incomplete!");
      throw ex;
    } else {
      this._logger.warn("The entity "
                        + stringKey
                        + " is missing, using default string as a fallback");
      return this.lookUp(null, aServiceName);
    }
  }
  this._logger.info("Error code is " + aErrorCode + ": " + msg);

  return msg;
};

flockError.prototype.mStringBundle = CC[STRING_BUNDLE_CONTRACTID].
                                     getService(STRING_BUNDLE_IID).
                                     createBundle(STRING_BUNDLE_URL);

//////////////////////////////////////////////////////////////////////////////
// Factory Definitions
//////////////////////////////////////////////////////////////////////////////
var flockErrorModule = {
  registerSelf: function registerSelf(aCompMgr, aFileSpec, aLocation, aType)
  {
    aCompMgr = aCompMgr.QueryInterface(CI.nsIComponentRegistrar);
    aCompMgr.registerFactoryLocation(FLOCK_ERROR_CID,
                                     "flockError JS component",
                                     FLOCK_ERROR_CONTRACTID,
                                     aFileSpec,
                                     aLocation,
                                     aType);
  },

  getClassObject: function getClassObject(aCompMgr, aCid, aIid)
  {
    if (!aCid.equals(FLOCK_ERROR_CID)) {
      throw CR.NS_ERROR_NO_INTERFACE;
    }
    if (!aIid.equals(CI.nsIFactory)) {
      throw CR.NS_ERROR_NOT_IMPLEMENTED;
    }
    return flockErrorFactory;
  },

  canUnload: function canUnload(aCompMgr)
  {
    return true;
  }
};

var flockErrorFactory = {
  createInstance: function createInstance(aOuter, aIid)
  {
    if (aOuter != null) {
      throw CR.NS_ERROR_NO_AGGREGATION;
    }
    if (!aIid.equals(FLOCK_ERROR_IID) &&
        !aIid.equals(CI.nsISupports))
    {
      throw CR.NS_ERROR_INVALID_ARG;
    }
    return new flockError();
  }
}

// module initialisation
function NSGetModule(aComMgr, aFileSpec)
{
  return flockErrorModule;
}
