/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * 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.
 *
 * The Original Code is Test Pilot.
 *
 * The Initial Developer of the Original Code is Mozilla.
 * Portions created by the Initial Developer are Copyright (C) 2007
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Jono X <jono@mozilla.com>
 *   Raymond Lee <raymond@appcoast.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

const PAGE_TYPE_STATUS = 0;
const PAGE_TYPE_QUIT = 1;
var stringBundle;

  function showRawData(experimentId) {
    window.openDialog(
      "chrome://testpilot/content/raw-data-dialog.xul",
      "TestPilotRawDataDialog", "chrome,centerscreen,resizable,scrollbars",
      experimentId);
  }

  function getUrlParam(name) {
    // from http://www.netlobo.com/url_query_string_javascript.html
    name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
    var regexS = "[\\?&]"+name+"=([^&#]*)";
    var regex = new RegExp(regexS);
    var results = regex.exec(window.location.href);
    if( results == null )
      return "";
    else
      return results[1];
  }

  function uploadData() {
    Components.utils.import("resource://testpilot/modules/setup.js");
    let eid = getUrlParam("eid");
    let task = TestPilotSetup.getTaskById(eid);

    // If always-submit-checkbox is checked, set the pref
    if (task._recursAutomatically) {
      let checkBox = document.getElementById("always-submit-checkbox");
      if (checkBox && checkBox.checked) {
        task.setRecurPref(TaskConstants.ALWAYS_SUBMIT);
      }
    }

    // Study web content must provide an element with id 'upload-status'.
    // Fill it first with a message about data being uploaded; if there's
    // an error, replace it with the error message.
    let uploadStatus = document.getElementById("upload-status");
    uploadStatus.innerHTML =
      stringBundle.GetStringFromName("testpilot.statusPage.uploadingData");
    task.upload( function(success) {
      if (success) {
        window.location =
	  "chrome://testpilot/content/status.html?eid=" + eid;
      } else {
        // Replace 'now uploading' message
        let errorParagraph = document.createElement("p");
        errorParagraph.innerHTML = stringBundle.GetStringFromName("testpilot.statusPage.uploadErrorMsg");
        let willRetryParagraph = document.createElement("p");
        willRetryParagraph.innerHTML = stringBundle.GetStringFromName("testpilot.statusPage.willRetry");
        uploadStatus.innerHTML = "";
        uploadStatus.appendChild(errorParagraph);
        uploadStatus.appendChild(willRetryParagraph);
      }
    });
  }

  function deleteData() {
    Components.utils.import("resource://testpilot/modules/setup.js");
    Components.utils.import("resource://testpilot/modules/tasks.js");
    let eid = getUrlParam("eid");
    let task = TestPilotSetup.getTaskById(eid);
    task.dataStore.wipeAllData();
    // reload the URL after wiping all data.
    window.location = "chrome://testpilot/content/status.html?eid=" + eid;
  }

  function saveCanvas(canvas) {
    const nsIFilePicker = Components.interfaces.nsIFilePicker;
    let filePicker = Components.classes["@mozilla.org/filepicker;1"].
      createInstance(nsIFilePicker);
    filePicker.init(window, null, nsIFilePicker.modeSave);
    filePicker.appendFilters(
	nsIFilePicker.filterImages | nsIFilePicker.filterAll);
    filePicker.defaultString = "canvas.png";

    let response = filePicker.show();
    if (response == nsIFilePicker.returnOK ||
	response == nsIFilePicker.returnReplace) {
      const nsIWebBrowserPersist = Components.interfaces.nsIWebBrowserPersist;
      let file = filePicker.file;

      // create a data url from the canvas and then create URIs of the source
      // and targets
      let io = Components.classes["@mozilla.org/network/io-service;1"].
	getService(Components.interfaces.nsIIOService);
      let source = io.newURI(canvas.toDataURL("image/png", ""), "UTF8", null);
      let target = io.newFileURI(file);

      // prepare to save the canvas data
      let persist = Components.classes[
	"@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].
	  createInstance(nsIWebBrowserPersist);
      persist.persistFlags = nsIWebBrowserPersist.
	PERSIST_FLAGS_REPLACE_EXISTING_FILES;
      persist.persistFlags |= nsIWebBrowserPersist.
        PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;

      // displays a download dialog (remove these 3 lines for silent download)
      let xfer = Components.classes["@mozilla.org/transfer;1"].
	createInstance(Components.interfaces.nsITransfer);
      xfer.init(source, target, "", null, null, null, persist);
      persist.progressListener = xfer;

      // save the canvas data to the file
      persist.saveURI(source, null, null, null, null, file);
    }
  }

  function exportData() {
    const nsIFilePicker = Components.interfaces.nsIFilePicker;
    let filePicker = Components.classes["@mozilla.org/filepicker;1"].
      createInstance(nsIFilePicker);
    let eid = getUrlParam("eid");
    let task = TestPilotSetup.getTaskById(eid);

    filePicker.init(window, null, nsIFilePicker.modeSave);
    filePicker.appendFilters(
	nsIFilePicker.filterImages | nsIFilePicker.filterAll);
    filePicker.defaultString = task.title + ".csv";

    let response = filePicker.show();
    if (response == nsIFilePicker.returnOK ||
	response == nsIFilePicker.returnReplace) {
      const nsIWebBrowserPersist = Components.interfaces.nsIWebBrowserPersist;
      let foStream =
        Components.classes["@mozilla.org/network/file-output-stream;1"].
	  createInstance(Components.interfaces.nsIFileOutputStream);
      let converter =
        Components.classes["@mozilla.org/intl/converter-output-stream;1"].
	  createInstance(Components.interfaces.nsIConverterOutputStream);
      let file = filePicker.file;
      let dataStore = task.dataStore;
      let columnNames = dataStore.getHumanReadableColumnNames();
      let propertyNames = dataStore.getPropertyNames();
      let csvString = "";

      // titles
      for (let i = 0; i < columnNames.length; i++) {
	csvString += "\"" + columnNames[i] + "\",";
      }
      if (csvString.length > 0) {
	csvString = csvString.substring(0, (csvString.length - 1));
        csvString += "\n";
      }

      dataStore.getAllDataAsJSON(true, function(rawData) {
        // data
        for (let i = 0; i < rawData.length; i++) {
          for (let j = 0; j < columnNames.length; j++) {
	    csvString += "\"" + rawData[i][propertyNames[j]] + "\",";
          }
	  csvString = csvString.substring(0, (csvString.length - 1));
          csvString += "\n";
        }

        // write, create, truncate
        foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0);
        converter.init(foStream, "UTF-8", 0, 0);
        converter.writeString(csvString);
        converter.close();
      });
    }
  }

  function openLink(url) {
    // open the link in the chromeless window
    let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
                       .getService(Components.interfaces.nsIWindowMediator);
    let recentWindow = wm.getMostRecentWindow("navigator:browser");

    if (recentWindow) {
      recentWindow.TestPilotWindowUtils.openInTab(url);
    } else {
      window.open(url);
    }
  }

  function getTestEndingDate(experimentId) {
    Components.utils.import("resource://testpilot/modules/setup.js");
    var task = TestPilotSetup.getTaskById(experimentId);
    var endDate = new Date(task.endDate);
    var diff = (endDate - Date.now());
    var span = document.getElementById("test-end-time");
    if (!span) {
      return;
    }
    if (diff < 0) {
      span.innerHTML =
        stringBundle.GetStringFromName("testpilot.statusPage.endedAlready");
      return;
    }
    var hours = diff / (60 * 60 * 1000);
    if (hours < 24) {
      span.innerHTML =
        stringBundle.formatStringFromName(
	  "testpilot.statusPage.todayAt", [endDate.toLocaleTimeString()], 1);
    } else {
      span.innerHTML =
        stringBundle.formatStringFromName(
	  "testpilot.statusPage.endOn", [endDate.toLocaleString()], 1);
    }
  }

  function showMetaData() {
    Components.utils.import("resource://testpilot/modules/metadata.js");
    Components.utils.import("resource://gre/modules/PluralForm.jsm");
    MetadataCollector.getMetadata(function(md) {
      var mdLocale = document.getElementById("md-locale");
      if (mdLocale)
        mdLocale.innerHTML = md.location;
      var mdVersion = document.getElementById("md-version");
      if (mdVersion)
        mdVersion.innerHTML = md.version;
      var mdOs = document.getElementById("md-os");
      if (mdOs)
        mdOs.innerHTML = md.operatingSystem;
      var mdNumExt = document.getElementById("md-num-ext");
      if (mdNumExt) {
        // This computes the correctly localized singular or plural string
        // of the number of extensions, e.g. "1 extension", "2 extensions", etc.
        let str = stringBundle.GetStringFromName("testpilot.statusPage.numExtensions");
        var numExt = md.extensions.length;
        mdNumExt.innerHTML = PluralForm.get(numExt, str).replace("#1", numExt);
      }
    });
  }

  function onQuitPageLoad() {
    Components.utils.import("resource://testpilot/modules/setup.js");
    setStrings(PAGE_TYPE_QUIT);
    let eid = getUrlParam("eid");
    let task = TestPilotSetup.getTaskById(eid);
    let header = document.getElementById("about-quit-title");
    header.innerHTML =
      stringBundle.formatStringFromName(
	"testpilot.quitPage.aboutToQuit", [task.title], 1);

    if (task._recursAutomatically) {
      document.getElementById("recur-options").setAttribute("style", "");
      document.getElementById("recur-checkbox-container").
        setAttribute("style", "");
    }
  }

  function quitExperiment() {
    Components.utils.import("resource://testpilot/modules/setup.js");
    Components.utils.import("resource://testpilot/modules/tasks.js");
    let eid = getUrlParam("eid");
    let reason = document.getElementById("reason-for-quit").value;
    let task = TestPilotSetup.getTaskById(eid);
    task.optOut(reason, function(success) {
      // load the you-are-canceleed page.
      window.location = "chrome://testpilot/content/status.html?eid=" + eid;
    });

    // If opt-out-forever checkbox is checked, opt out forever!
    if (task._recursAutomatically) {
      let checkBox = document.getElementById("opt-out-forever");
      if (checkBox.checked) {
        task.setRecurPref(TaskConstants.NEVER_SUBMIT);
      }
      // quit test so rescheduling
      task._reschedule();
    }
  }

  function updateRecurSettings() {
    Components.utils.import("resource://testpilot/modules/setup.js");
    let eid = getUrlParam("eid");
    let experiment = TestPilotSetup.getTaskById(eid);
    let recurSelector = document.getElementById("recur-selector");
    let newValue = recurSelector.options[recurSelector.selectedIndex].value;
    experiment.setRecurPref(parseInt(newValue));
  }

  function showRecurControls(experiment) {
    Components.utils.import("resource://testpilot/modules/tasks.js");
    let recurPrefSpan = document.getElementById("recur-pref");
    if (!recurPrefSpan) {
      return;
    }
    let days = experiment._recurrenceInterval;
    recurPrefSpan.innerHTML =
      stringBundle.formatStringFromName(
	"testpilot.statusPage.recursEveryNumberOfDays", [days], 1);

    let controls = document.getElementById("recur-controls");
    let selector = document.createElement("select");
    controls.appendChild(selector);
    selector.setAttribute("onchange", "updateRecurSettings();");
    selector.setAttribute("id", "recur-selector");

    let option = document.createElement("option");
    option.setAttribute("value", TaskConstants.ASK_EACH_TIME);
    if (experiment.recurPref == TaskConstants.ASK_EACH_TIME) {
      option.setAttribute("selected", "true");
    }
    option.innerHTML =
      stringBundle.GetStringFromName(
	"testpilot.statusPage.askMeBeforeSubmitData");
    selector.appendChild(option);

    option = document.createElement("option");
    option.setAttribute("value", TaskConstants.ALWAYS_SUBMIT);
    if (experiment.recurPref == TaskConstants.ALWAYS_SUBMIT) {
      option.setAttribute("selected", "true");
    }
    option.innerHTML =
      stringBundle.GetStringFromName(
	"testpilot.statusPage.alwaysSubmitData");
    selector.appendChild(option);

    option = document.createElement("option");
    option.setAttribute("value", TaskConstants.NEVER_SUBMIT);
    if (experiment.recurPref == TaskConstants.NEVER_SUBMIT) {
      option.setAttribute("selected", "true");
    }
    option.innerHTML =
      stringBundle.GetStringFromName(
	"testpilot.statusPage.neverSubmitData");
    selector.appendChild(option);
  }

  function loadExperimentPage() {
    Components.utils.import("resource://testpilot/modules/setup.js");
    Components.utils.import("resource://testpilot/modules/tasks.js");
    var contentDiv = document.getElementById("experiment-specific-text");
    var dataPrivacyDiv = document.getElementById("data-privacy-text");
    // Get experimentID from the GET args of page
    var eid = getUrlParam("eid");
    var experiment = TestPilotSetup.getTaskById(eid);
    if (!experiment) {
      // Possible that experiments aren't done loading yet.  Try again in
      // a few seconds.
      contentDiv.innerHTML =
        stringBundle.GetStringFromName("testpilot.statusPage.loading");
      window.setTimeout(function() { loadExperimentPage(); }, 2000);
      return;
    }

    // Let the experiment fill in its web content (asynchronous)
    experiment.getWebContent(function(webContent) {
      contentDiv.innerHTML = webContent;

      // Metadata and start/end date should be filled in for every experiment:
      showMetaData();
      getTestEndingDate(eid);
      if (experiment._recursAutomatically &&
        experiment.status != TaskConstants.STATUS_FINISHED) {
        showRecurControls(experiment);
      }

      // Do whatever the experiment's web content wants done on load
      // (Usually drawing a graph) - must be done after innerHTML is set.
      experiment.webContent.onPageLoad(experiment, document, jQuery);
    });

    experiment.getDataPrivacyContent(function(dataPrivacyContent) {
      if (dataPrivacyContent && dataPrivacyContent.length > 0) {
        dataPrivacyDiv.innerHTML = dataPrivacyContent;
        dataPrivacyDiv.removeAttribute("hidden");
      }
    });
  }

  function onStatusPageLoad() {
    setStrings(PAGE_TYPE_STATUS);
    /* If an experiment ID (eid) is provided in the url params, show status
     * for that experiment.  If not, show the main menu with status for all
     * installed experiments. */
    let eidString = getUrlParam("eid");
    if (eidString == "") {
      showStatusMenuPage();
    } else {
      loadExperimentPage();
    }
  }

  function setStrings(pageType) {
    stringBundle =
      Components.classes["@mozilla.org/intl/stringbundle;1"].
        getService(Components.interfaces.nsIStringBundleService).
	  createBundle("chrome://testpilot/locale/main.properties");
    let map;
    let mapLength;

    if (pageType == PAGE_TYPE_STATUS) {
      map = [
	{ id: "page-title", stringKey: "testpilot.fullBrandName" },
	{ id: "comments-and-discussions-link",
	  stringKey: "testpilot.page.commentsAndDiscussions" },
	{ id: "propose-test-link",
	  stringKey: "testpilot.page.proposeATest" },
	{ id: "testpilot-twitter-link",
	  stringKey: "testpilot.page.testpilotOnTwitter" }
      ];
    } else if (pageType == PAGE_TYPE_QUIT) {
      map = [
	{ id: "page-title", stringKey: "testpilot.fullBrandName" },
	{ id: "comments-and-discussions-link",
	  stringKey: "testpilot.page.commentsAndDiscussions" },
	{ id: "propose-test-link",
	  stringKey: "testpilot.page.proposeATest" },
	{ id: "testpilot-twitter-link",
	  stringKey: "testpilot.page.testpilotOnTwitter" },
	{ id: "optional-message",
	  stringKey: "testpilot.quitPage.optionalMessage" },
	{ id: "reason-text",
	  stringKey: "testpilot.quitPage.reason" },
	{ id: "recur-options",
	  stringKey: "testpilot.quitPage.recurringStudy" },
	{ id: "quit-forever-text",
	  stringKey: "testpilot.quitPage.quitForever" },
	{ id: "quit-study-link",
	  stringKey: "testpilot.quitPage.quitStudy" }
      ];
    }
    mapLength = map.length;
    for (let i = 0; i < mapLength; i++) {
      let entry = map[i];
      document.getElementById(entry.id).innerHTML =
        stringBundle.GetStringFromName(entry.stringKey);
    }
  }
