const Cc = Components.classes;
const CI = Components.interfaces;
const kStringBundleBaseURL = "chrome://zeipisplayer/locale/";


function assert(test, failmsg)
{
  if (!test)
    throw new Exception(failmsg);
}

function extend(child, supertype)
{
  child.prototype.__proto__ = supertype.prototype;
}

function ArrayRemove(array, element, all)
{
  var found = 0;
  var pos = 0;
  while ((pos = array.indexOf(element, pos)) != -1)
  {
    array.splice(pos, 1);
    found++
    if ( ! all)
      return found;
  }
  return found;
}


function Exception(msg)
{
  this._message = msg;

  try {
    foo.does.not.exist += 1; // cause JS exception
  } catch (e) {
    this._artificialException = e;
    this.stack = e.stack;
  }
}
Exception.prototype =
{
  get message()
  {
    return this._message;
  },
  toString : function()
  {
    return this._message;
  }
}

function NotReached(msg)
{
}
extend(NotReached, Exception);



/**
 * A handle for an async function which you can cancel.
 * The async function will return an object of this type (a subtype)
 * and you can call cancel() when you feel like killing the function.
 */
function Abortable()
{
}
Abortable.prototype =
{
  cancel : function()
  {
  }
}

function xhrXMLResult(xhr)
{
  var mimetype = xhr.getResponseHeader("Content-Type");
  if (mimetype)
    mimetype = mimetype.split(";")[0];
  if (mimetype && mimetype != "text/xml")
  {
    alert("Server did not return XML, but " + xhr.responseText);
    return;
  }
  var text = xhr.responseText;  // bug 270553 and
  text = text.replace(/<\?xml[^>]*\?>/, ""); // bug 336551
  return new XML(text);
}



var gConsoleServiceCache;
function consoleService()
{
    if (gConsoleServiceCache)
        return gConsoleServiceCache;
    gConsoleServiceCache = Cc["@mozilla.org/consoleservice;1"]
                           .getService(CI.nsIConsoleService);
    return gConsoleServiceCache;
}


var gPrefService;
function prefService()
{
    if (gPrefService)
        return gPrefService;
    gPrefService = Cc["@mozilla.org/preferences-service;1"]
                        .getService(CI.nsIPrefService)
                        .getBranch(null);
    return gPrefService;
}

var gStringBundleService;
function stringBundleService()
{
    if (gStringBundleService)
        return gStringBundleService;
    gStringBundleService = Cc["@mozilla.org/intl/stringbundle;1"]
                                    .getService(CI.nsIStringBundleService);
    return gStringBundleService;
}

function getStringBundle(name)
{
    var uri = kStringBundleBaseURL + name + ".properties";
    try {
        return stringBundleService().createBundle(uri);
    } catch (e) {
        throw new Exception("Could not get stringbundle from <" + uri + ">, because " + e);
    }
}


/**
 * @param file {nsIFile}
 * @return {Array of String}   one string per line of file
 */
function readFile(file)
{
    assert(file instanceof CI.nsIFile, "not an nsIFile");
    var fis = Cc["@mozilla.org/network/file-input-stream;1"]
        .createInstance(CI.nsIFileInputStream);
    const MODE_READONLY = 0x01;
    const PERM_FILE = 0644;
    fis.init(file, MODE_READONLY, PERM_FILE, false);
    var result = new Array();
    try {
        var lis = fis.QueryInterface(CI.nsILineInputStream);
        var line = {value: null};
        var haveMore = true;
        while (haveMore)
        {
            haveMore = lis.readLine(line);
            result.push(line.value);
        }
    } finally {
        fis.close();
    }
    return result;
}


/**
 * @param file {nsIFile}
 * @return {Object, associative Array}   keys and values in INI file
 *    mapped to JS object properties,
 *    e.g. "RED = 34" -> result.RED = "34"; .
 *    Keys with funny characters or spaces
 *    (which generally not expected in keys) will be URL encoded,
 *    e.g. "RED COLOR = 34" -> result["RED%20COLOR"] = "34";
 */
function readINIFile(file)
{
    var lines = readFile(file);
    var result = new Object();
    for (var i = 0; i < lines.length; i++)
    {
        let line = lines[i].trim();
        if (line.length == 0 || // empty line
            line[0] == "#") // comment
            continue;
        let sp = line.split("=", 2);
        if (sp.length < 2)
            continue; // malformed
        let key = sp[0].trim();
        let value = sp[1].trim();
        key = encodeURIComponent(key);
        result[key] = value;
    }
    return result;
}

/**
 * Use nsIDirectoryService to get special folders
 * like home directory, temp folder, root folder etc.
 * @param key {String}   @see Moz docs
 * @result {nsIFile} of directory
 */
function getSpecialFolder(key)
{
   var directoryService = Cc["@mozilla.org/file/directory_service;1"]
       .getService(CI.nsIProperties);
   return directoryService.get(key, CI.nsIFile);
}
