/**
 * GNU LibreJS - A browser add-on to block nonfree nontrivial JavaScript.
 * *
 * Copyright (C) 2011, 2012, 2013, 2014 Loic J. Duros
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see  <http://www.gnu.org/licenses/>.
 *
 */
/*jshint esnext: true */

const { Cc, Ci, Cu, components } = require("chrome");

var { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm");
var { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm");
var relationChecker = require("js_checker/relation_checker").relationChecker;
var rc = relationChecker(); // a dummy object for legacy module.
const AUTHOR_REASON = require("script_entries/free_libraries").AUTHOR_REASON;
var relationChecker = require("js_checker/relation_checker").relationChecker; 

const scriptsCached = require("script_entries/scripts_cache").scriptsCached;

let librejsStorage = {

  file: null,
  filename: 'librejs-whitelist.json',
  data: [],

  onLoad: function (callback) {
    // will read the json file.
    this.init();
    this.read(callback);
  },
  

  init: function () {
    // get the "librejs-whitelist.json" file in the profile directory
    this.file = FileUtils.getFile("ProfD", [this.filename]);
  },
  read: function (callback) {
    // Content type hint is useful on mobile platforms where the filesystem
    // would otherwise try to determine the content type.
    var channel = NetUtil.newChannel(this.file);
    var that = this;
    channel.contentType = "application/json";
    try {
      NetUtil.asyncFetch(channel, function(inputStream, status) {

        if (!components.isSuccessCode(status)) {
          require("script_entries/free_libraries").init();
          that.initialWrite();
        }
        
        var raw_data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
        // expand json file back to original contents.
        var re = new RegExp("[freelib]".replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g');
        raw_data = raw_data.replace(re, AUTHOR_REASON);
        console.debug("raw_data is ", raw_data);
        // The file data is contained within inputStream.
        // You can read it into a string with
        // get string into json also
        that.data = JSON.parse(raw_data);
        
        callback(that.data);
      });
    } catch (e) {
      that.initialWrite();
    }
  },
    
  initialWrite: function (callback) {
    console.debug("About to write free libraries");
    // our file is not populated with default contents.
    // use free_libraries.js to populate.
    require("script_entries/free_libraries").init();
    this.writeCacheToDB(callback);
  },
  /**
   * writes the contents of scriptsCached to the persistent
   * JSON file.
   */
  writeCacheToDB: function (callback) {
    console.debug("writing to db");
    data = scriptsCached.getCacheForWriting();
    json = JSON.stringify(data);

    // make json file smaller.
    var re = new RegExp(AUTHOR_REASON.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g');
    json = json.replace(re, "[freelib]");
    
    var rc = JSON.stringify(relationChecker());
    re = new RegExp(rc.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g');    
    json = json.replace(re, "\"[rl]\"");
    console.debug("this.data is now", this.data);
    this.write(callback, json);
  },
  generateCacheFromDB: function (callback) {
    if (callback === undefined) {
      callback = function () {
        // nothing to do.
      };
    }
    this.read(function (data) {
      scriptsCached.bulkImportCache(data);
    });
  },
  write: function (onDataWritten, json) {

    this.init();
    var str;
    if (json === undefined) {
      str = JSON.stringify(this.data);
    } else {
      // we are passing json already formatted.
      str = json;
    }
    var ostream = FileUtils.openSafeFileOutputStream(this.file);
    var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
    converter.charset = "UTF-8";
    var istream = converter.convertToInputStream(str);
    // The last argument (the callback) is optional.
    NetUtil.asyncCopy(istream, ostream, function(status) {
      if (!components.isSuccessCode(status)) {
        // Handle error!
        return;
      }
      if (!onDataWritten) {
        console.debug("onDataWritten is not defined");
        onDataWritten = function () {
          console.debug("onDataWritten dummy callback triggered");
        };
      }
      // Data has been written to the file.
      onDataWritten();
    });
  },

  /**
   *  getEntry -- Returns a storage entry if it is present.
   */
  getEntry: function (hash) {
    var entry = this.data[hash];
    if (entry) {
      if (entry.result == "[freelib]") {
        entry.result = { "type": 4, "reason": "this script has been tagged as free software by LibreJS authors" };
      }
      entry.relationChecker = rc;
      return entry;
    }
    return false;
  }
};

exports.librejsStorage = librejsStorage;
