function Installer()
{
  this._install = $(document.createElement("div"));
  this._veil = $(document.createElement("div"));
  this._box = $(document.createElement("div"));

  this._install.attr("id", "install");
  this._veil.addClass("veil");
  this._box.addClass("box");

  this._install.append(this._veil);
  this._install.append(this._box);

  Installer.prototype.setBox = function(box) { this._box.empty(); this._box.append(box.getContents()); }
  Installer.prototype.show = function() { $("body").empty(); $("body").append(this._install); }
}

function IntroBox()
{
  var _onInstallClick = null;

  this._box = $(document.createElement("div"));
  this._install = $(document.createElement("button"));
  this._quit = $(document.createElement("p"));

  this._install.addClass("large");
  this._install.bind("click", function(e) { if (_onInstallClick) { _onInstallClick(e); } } );

  this._box.html("<p>To use the Offline Bible on your computer the installation program needs to download some system files, the entire contents of the Bible, and a concordance.</p><p>Depending on the speed of your internet connection, this may take a few minutes. Do you want to do this now?</p>");
  this._install.html("<h1>Install</h1>");
  this._quit.html("or return to the <a href=\"http://www.offlinebible.com/\">home page</a>.");

  this._box.append(this._install);
  this._box.append(this._quit);

  IntroBox.prototype.getContents = function() { return this._box; }
  IntroBox.prototype.onInstallClick = function(callback) { _onInstallClick = callback; }
}

function ProgressBox()
{
  var _onCancelClick = null;
  var _onContinueClick = null;

  var _facts = new Array();
  var _factRun = false;
  var _factIndex = -1;
  var _factTimeoutId = -1;
  var _factTimeoutDelay = 5000;

  var _progressValue = 5000;

  this._box = $(document.createElement("div"));
  this._title = $(document.createElement("h1"));
  this._action = $(document.createElement("p"));
  this._progress = $(document.createElement("div"));
  this._fact = $(document.createElement("p"));
  this._cancel = $(document.createElement("button"));

  this._progress.addClass("progress");
  this._progress.html("<div class=\"start\">&#160;</div><div class=\"progressValue\">&#160;</div><div class=\"end\">&#160;</div>");

  this._fact.addClass("fact");
  this._fact.text("Loading fun install facts...");

  this._cancel.addClass("cancel");
  this._cancel.text("Cancel");
  this._cancel.bind("click", function(e) { ProgressBox.prototype.stopFacts(); if (_onCancelClick) { _onCancelClick(e); } } );

  this._box.append(this._title);
  this._box.append(this._action);
  this._box.append(this._progress);
  this._box.append(this._fact);
  this._box.append(this._cancel);

  function cycleFacts()
  {
    if (_facts && _facts.length > 0 && _factRun)
    {
      _factIndex = (_factIndex + 1) % _facts.length;

      $("p.fact").fadeOut("slow", function () {$(this).html(_facts[_factIndex]).fadeIn("slow")});
      _factTimeoutId = window.setTimeout(cycleFacts, _factTimeoutDelay);
    }
    else
    {
      this.stopFacts();
    }
  }

  ProgressBox.prototype.startFacts = function()
  {
    this.stopFacts();
    _factRun = true;
    _factTimeoutId = window.setTimeout(cycleFacts, 1000);
  }

  ProgressBox.prototype.stopFacts = function()
  {
    _factRun = false;
    if (_factTimeoutId != -1)
    {
      window.clearTimeout(_factTimeoutId);
      _factTimeoutId = -1;
    }

  }

  ProgressBox.prototype.facts = function(value)
  {
    if (value == null || value == undefined) { return value; }
    else { _facts = value; }
  }

  ProgressBox.prototype.progress = function(val)
  {
    if (val == undefined)
    {
      return this._progressValue;
    }
    else
    {
      this._progressValue = val;
      var availableWidth = this._progress.innerWidth() - 8;

      this._progress.children(".progressValue").width((availableWidth /100) * val);
    }
  }

  ProgressBox.prototype.finish = function()
  {
    this._cancel.removeClass("cancel");
    this._cancel.addClass("regular");
    this._cancel.text("Continue");
    this._cancel.unbind("click");
    this._cancel.bind("click", function(e) { ProgressBox.prototype.stopFacts(); if (_onContinueClick) { _onContinueClick(e); } } );
  }

  ProgressBox.prototype.title = function(text) { return this._title.text(text); }
  ProgressBox.prototype.action = function(text) { return this._action.html(text); }
  ProgressBox.prototype.getContents = function() { return this._box; }
  ProgressBox.prototype.onCancelClick = function(callback) { _onCancelClick = callback; }
  ProgressBox.prototype.onContinueClick = function(callback) { _onContinueClick = callback; }
}

function ErrorBox()
{
  var _onContinueClick = null;

  this._box = $(document.createElement("div"));
  this._title = $(document.createElement("h1"));
  this._explanation = $(document.createElement("p"));
  this._messageContainer = $(document.createElement("p"));
  this._message = $(document.createElement("code"));
  this._continue = $(document.createElement("button"));

  this._continue.addClass("cancel");
  this._continue.bind("click", function(e) { if (_onContinueClick) { _onContinueClick(e); } } );
  this._continue.text("Continue");

  this._box.append(this._title);
  this._box.append(this._explanation);
  this._messageContainer.append(this._message);
  this._box.append(this._messageContainer);
  this._box.append(this._continue);

  ErrorBox.prototype.getContents = function() { return this._box; }
  ErrorBox.prototype.setError = function(message, lineNumber, title, explanation)
  {
    this._title.text(title);
    this._explanation.html(explanation);
    this._message.text("Line " + lineNumber + ": " + message);
  }

  ErrorBox.prototype.onContinueClick = function(callback) { _onContinueClick = callback; }
}

function PackageBox()
{
  var self = this;
  var _onCancelClick = null;
  var _onInstallClick = null;
  var _manifests = null;

  this._box = $(document.createElement("div"));
  this._cancelButton = $(document.createElement("button"));
  this._installButton = $(document.createElement("button"));
  this._packages = $(document.createElement("table"));

  this._box.addClass("packages");
  this._cancelButton.addClass("cancel");
  this._installButton.addClass("regular");
  //this._installButton.attr("disabled", "disabled");
  this._cancelButton.bind("click", function(e) { if (_onCancelClick) { _onCancelClick(e); } } );
  this._installButton.bind("click", function(e) { if (_onInstallClick) { _onInstallClick(_manifests); } } );

  this._box.html("");
  this._cancelButton.html("Cancel");
  this._installButton.html("Continue");
  this._box.append(this._packages, this._cancelButton, this._installButton);

  function buildSelect(noaction, install, update, uninstall)
  {
    var s = "";
    var d = "";
    if (noaction)  { d = "no"; s += "<option class=\"no\">No action</option>"; }
    if (install)   { d = "add"; s += "<option class=\"add\" selected=\"selected\">Install</option>"; }
    if (update)    { d = "add"; s += "<option class=\"add\" selected=\"selected\">Update</option>"; }
    if (uninstall) { s += "<option class=\"rem\">Uninstall</option>"; }
    return "<select class=\"" + d + "\">" + s + "</select>";
  }

  PackageBox.prototype.setManifests = function(manifestList)
  {
    _manifests = manifestList;
    if (manifestList.length > 0)
    {
      var c = "<thead><tr><th class=\"packageCell\">Package</th><th class=\"statusCell\">Status</th><th class=\"actionCell\">Actions</th></tr></thead><tbody>";

      for (var i=0; i<manifestList.length; i++)
      {
        var m = manifestList[i];
        var noActionFlag = false;
        var installFlag = false;
        var updateFlag = false;
        var uninstallFlag = false;

        var statusText = "Unknown";
        var mandatory = (m.force) ? "&#160;<em class=\"force\" title=\"This package is required by the OfflineBible\">*</em>" : "";
        var installedVersion = m.current.major.toString() + "." +  m.current.minor.toString() + "." + m.current.schema.toString();
        var availableVersion = m.major.toString() + "." +  m.minor.toString() + "." + m.schema.toString();
        var comparison = (installedVersion == availableVersion) ? " = ": " &raquo; ";
        if (installedVersion == availableVersion && installedVersion == "0.0.0") { statusText = "Not yet available"; noActionFlag = true; }
        else if (installedVersion == availableVersion) { statusText = "Up to date"; noActionFlag = true; }
        else if (installedVersion == "0.0.0") { statusText = "Available"; installFlag = true; noActionFlag = !m.force; }
        else { statusText = "Update available"; updateFlag = true; noActionFlag = !m.force; }
        uninstallFlag = !m.force && updateFlag;
        c += "<tr><td class=\"packageCell\">" + m.name + mandatory + "</td><td class=\"statusCell\" title=\"" + installedVersion + comparison + availableVersion + "\">" + statusText + "</td><td class=\"actionCell\">" + buildSelect(noActionFlag, installFlag, updateFlag, uninstallFlag) + "</td></tr>";
      }
      c += "</tbody>";
    }
    else
    {
      c = "<tbody><tr><td>There are no packages available or you have disconnected from the internet.</td></tr></tbody>"
    }
    self._packages.html(c);
    self._packages.find("select").change(function(e) { var t = $(this); t.removeClass(); t.addClass(t.children(":selected").attr("class")); } );
  }

  PackageBox.prototype.getContents = function() { return this._box; }
  PackageBox.prototype.onInstallClick = function(callback) { _onInstallClick = callback; }
  PackageBox.prototype.onCancelClick = function(callback) { _onCancelClick = callback; }
}

function WelcomeBox()
{
  var _self = this;
  var _clicked = false;
  var _onPackagesClick = null;
  var _onReadClick = null;

  this._box = $(document.createElement("div"));
  this._packageButton = $(document.createElement("button"));
  this._readButton = $(document.createElement("button"));

  this._readButton.addClass("option read");
  this._packageButton.addClass("option packages");

  this._readButton.bind("click", function(e) { if (_onReadClick && !_self._clicked) { _self._readButton.addClass("active"); _self._clicked = true; window.setTimeout(_onReadClick, 25); } } );
  this._packageButton.bind("click", function(e) { if (_onPackagesClick) { _onPackagesClick(e); } } );

  this._readButton.html("<h2>Use the OfflineBible</h2><p>Skip any updates and go straight to the OfflineBible software.</p>");
  this._packageButton.html("<h2>Install new content</h2><p>Download new Bibles and lexicons, or update your installed content.</p>");

  this._box.append(this._readButton, this._packageButton);
  WelcomeBox.prototype.defaultAction = function() { this._readButton.click(); }
  WelcomeBox.prototype.getContents = function() { return this._box; }
  WelcomeBox.prototype.onReadClick = function(callback) { _onReadClick = callback; }
  WelcomeBox.prototype.onPackagesClick = function(callback) { _onPackagesClick = callback; }
}
