/* ***** 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 Verbosio Text Document Wrapper.
 *
 * The Initial Developer of the Original Code is
 * Alexander J. Vincent <ajvincent@gmail.com>.
 * Portions created by the Initial Developer are Copyright (C) 2007
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * 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 ***** */

// Get JS modules.
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource://app/modules/ArrayConverter.jsm");
Components.utils.import("resource://app/modules/ecma-debug.jsm");

// Utility function.
function ERROR_FAILURE() {
  throw Components.results.NS_ERROR_ERROR_FAILURE;
}

// Utility function.
function NOT_IMPLEMENTED() {
  throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
}

var C_i = Components.interfaces;

const xeIDocumentFile             = C_i.xeIDocumentFile;
const xeIXMLDocumentWrapper       = C_i.xeIXMLDocumentWrapper;
const xeITextDocumentWrapper      = C_i.xeITextDocumentWrapper;
const xeIDocumentWrapper          = C_i.xeIDocumentWrapper;
const xeIVirtualFile              = C_i.xeIVirtualFile;
const xeIBaseURIMap               = C_i.xeIBaseURIMap;
const nsITransactionManager       = C_i.nsITransactionManager;
const mozIJSSubScriptLoader       = C_i.mozIJSSubScriptLoader;
const nsIScriptError              = C_i.nsIScriptError;
const nsIProgrammingLanguage      = C_i.nsIProgrammingLanguage;
const nsISecurityCheckedComponent = C_i.nsISecurityCheckedComponent;
const nsIClassInfo                = C_i.nsIClassInfo;
const nsISupports                 = C_i.nsISupports;

function TextDocumentWrapper() {
  this._docFileObj     = null;
  this._txmgr          = null;
  this._pendingAction  = null;

  // xeITextDocumentWrapper
  this.selectionStartIndex = 0;

  // xeITextDocumentWrapper
  this.selectionEndIndex = 0;

  // xeIDocumentWrapper
  this.baseURIMap = null;

  // xeIDocumentWrapper
  this.pathToDocument = null;

  // xeIDocumentWrapper
  this.descendantIndexes = {};

  // xeIDocumentWrapper
  this.baseURIMap = null;

  this._isInitialized = false;
}
TextDocumentWrapper.prototype = {
  // xeITextDocumentWrapper
  reparseSource: function reparseSource(aSource) {
    if (!this._isInitialized) {
      throw new Error("Document wrapper not initialized!");
    }
    this._docFileObj.contents = aSource;
  },

  // xeIDocumentWrapper
  get rootLanguageType() {
    // This is a generic text file.
    return "text";
  },

  // xeIDocumentWrapper
  get txmgr() {
    return this._txmgr;
  },

  // xeIDocumentWrapper
  get pendingAction() {
    return this._pendingAction;
  },

  // xeIDocumentWrapper
  set pendingAction(aPendingAction) {
    /* XXX ajvincent When this document is part of a document pack, the
     * pending action will have an ownerWrapper property that isn't this.
     */
    this._pendingAction = aPendingAction;
  },

  // xeIDocumentWrapper
  get txlistener() {
    return null;
  },

  // xeIDocumentWrapper
  get defaultViewerID() {
    return "source-edit@viewers.verbosio.mozdev.org";
  },

  // xeIDocumentWrapper
  get preconditionLocalId() {
    return null;
  },

  // xeIDocumentWrapper
  initializeByPrecondition: function initBy(aPrecondition) {
    if (this._isInitialized) {
      throw new Error("Document wrapper was already initialized!");
    }

    NOT_IMPLEMENTED();

    this._isInitialized = true;
  },

  // xeIDocumentWrapper
  initializeByFile: function initializeByFile(aLocalPath, aBaseURI) {
    NOT_IMPLEMENTED(); // Many things to fix here first, from updated API's.
    if (this._isInitialized) {
      throw new Error("Document wrapper was already initialized!");
    }

    var docFileClass = "@verbosio.mozdev.org/document-file;1?contentType=";
    var docFileObj = Components.classes[docFileClass + "text/plain"]
                               .createInstance(xeIDocumentFile);
    docFileObj.init(aLocalPath, "text/plain");
    docFileObj.read();

    this._docFileObj = docFileObj;

    const nsITxMgrCID = "@mozilla.org/transactionmanager;1";
    var txmgrClass = Components.classes[nsITxMgrCID];
    this._txmgr = txmgrClass.createInstance(nsITransactionManager);

    // xeIDocumentWrapper
    this.descendantIndexes = {};

    // xeIDocumentWrapper
    if (aBaseURI) {
      this.baseURIMap = aBaseURI;
    } else {
      this.baseURIMap = Components.classes["@verbosio.mozdev.org/base-uri-map;1"]
                                  .createInstance(xeIBaseURIMap);
    }

    // Base URI map will take care of pathToDocument.
    this.baseURIMap.registerWrapper(this);
    this._isInitialized = true;
  },

  // xeIDocumentWrapper
  save: function save(aLocalPath) {
    var docFileObj = null;
    if (aLocalPath) {
      var docFileClass = "@verbosio.mozdev.org/document-file;1?contentType=";
      docFileObj = Components.classes[docFileClass + "text/plain"]
                             .createInstance(xeIDocumentFile);
      docFileObj.init(aLocalPath, "text/plain");
      docFileObj.contents = this.contents;
    } else {
      docFileObj = this._docFileObj;
    }

    docFileObj.write(docFileObj.contents);

    if (aLocalPath) {
      this.baseURIMap.unregisterWrapper(this);
    }

    this._docFileObj = docFileObj;

    if (aLocalPath) {
      this.baseURIMap.registerWrapper(this);
    }

    this.txmgr.clear();
  },

  // xeIVirtualFile
  get wrappedSource() {
    return (this._docFileObj) ? this._docFileObj.contents : "";
  },

  // xeIVirtualFile
  get contentType() {
    return "text/plain";
  },

  // xeIVirtualFile
  get publicURI() {
    return (this._docFileObj) ? this._docFileObj.location : null;
  },

  _interfaces: [xeITextDocumentWrapper,
                xeIDocumentWrapper,
                xeIVirtualFile,
                nsIClassInfo],

  // nsIClassInfo
  getInterfaces: ArrayConverter.xpcomArrayMethod("_interfaces"),

  // nsIClassInfo
  getHelperForLanguage: function getHelperForLanguage(aLanguage) {
    return null;
  },

  // nsIClassInfo
  contractID: "@verbosio.mozdev.org/document-wrappers/generic-text;1",

  // nsIClassInfo
  classDescription: "xeITextDocumentWrapper",

  // nsIClassInfo
  classID: Components.ID("{348fa230-2f9b-4d49-a983-8e59af182744}"),

  // nsIClassInfo
  implementationLanguage: Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,

  // nsIClassInfo
  flags: 0,

  // nsISupports
  QueryInterface: function QueryInterface(aIID)
  {
    for (var j = 0; j < this._interfaces.length; j++) {
      if (aIID.equals(this._interfaces[j])) {
        return this;
      }
    }

    if (aIID.equals(nsISupports))
      return this;

    if (aIID.equals(xeIXMLDocumentWrapper)) {
      // We know about this; don't look it up.
      throw Components.results.NS_ERROR_NO_INTERFACE;
      return null;
    }

    // Discover what interfaces we need
    var i = Components.interfaces;
    var found = false;
    for (var prop in i) {
      if (aIID.equals(i[prop])) {
        found = true;
        dump("QUERYINTERFACE TextDocumentWrapper: " + prop + "\n");
        break;
      }
    }
    if (!found) {
      dump("QUERYINTERFACE TextDocumentWrapper: Unknown\n");
    }

    throw Components.results.NS_ERROR_NO_INTERFACE;
    return null;
  }
}

var NSGetModule = XPCOMUtils.generateNSGetModule([
  TextDocumentWrapper
], null, null);
