const MAX_UNDO = 10;
const UNDO_FILE_PREFIX = "justSave";
var   UFID;
var dontStock = false;
const Cc = Components.classes;
const Ci = Components.interfaces;
var CS = Cc['@mozilla.org/consoleservice;1'].getService(Ci.nsIConsoleService);

function LOG(msg) { CS.logStringMessage(msg); }
function goStartup() { gTagger.startup(); } 
function goShutdown() { gTagger.shutdown(); }
function goCloseWindow() { return gTagger.closeWindow(); }

function goUpdateCommandset( commandset ) {
  for(var i = 0; i < commandset.childNodes.length; i++) {
    var commandNode = commandset.childNodes[i];
    goUpdateCommand(commandNode.id);
  }
}


// ------------------------------------------------------------------
// nsCommandTable
// ------------------------------------------------------------------

function nsCommandTable() {
  this._table = new Object();
}

nsCommandTable.prototype = {
  registerCommand : function (command, controller) {
    this._table[command] = controller;
  },

  registerCommands : function (commands) {
    for(var y in commands)
        this._table[y] = commands[y];
  },

  getCommand : function (command) {
   if(command in this._table)
     return  this._table[command];
   else
     return null;
  },

  // nsIController interface

  supportsCommand : function(command) {
    return (command in this._table);
  },
   
  isCommandEnabled: function(aCommand) {
    if(aCommand in this._table)
      return this._table[aCommand].isCommandEnabled(aCommand);
   else
     return null;
  },

  doCommand: function (aCommand) {
    if(aCommand in this._table) 
      this._table[aCommand].doCommand(aCommand);
  },

  doCommandWithParams: function (aCommand, params) {
    if(aCommand in this._table) 
      this._table[aCommand].doCommandWithParams(aCommand, params);
  }
};

// ------------------------------------------------------------------
// gTagger
// ------------------------------------------------------------------


var gTagger = {
  _commandTable :null,
  _ioservice: null,
  _stringBundle :null,
  _initialized : false,
  _modified: true,

	setTitle: function(val) {
    this._modified = true;
		document.getElementById("projectTitle").value = val; 
    pushNewUndoStep();
	},
	getTitle: function() {
		return document.getElementById("projectTitle").value;
	},
  startup : function() {
    UFID = Math.round(Math.random() * 10000);
    if (this._initialized)
      return;
		this.ready = false;
    gRegisterGlobalCommands(); 
    this.updateGlobalCommands();
    window.controllers.appendController(this.getCommandTable());
    this._initialized = true;
    this._ioservice = Cc["@mozilla.org/network/io-service;1"].
      getService(Ci.nsIIOService);
		this.sectionEditor = document.getElementById("sectionEditor");
		this.sectionEditor.init(this);
		this.sectionEditor.callBack = this;


		var observerService =
			Components.classes["@mozilla.org/observer-service;1"]
			.getService(Components.interfaces.nsIObserverService);
		observerService.addObserver(this,"AUDIO", false);



  },
    
  getIOService: function() {
    return this._ioservice;
  },
  closeWindow: function() {

    if (this.ready) {
  		var audioElt = document.getElementById("audioboard");
      if (audioElt._modified == true) {
        this._modified = true;
      }

      if (this._modified) {
        var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
        if (!prompts.confirm(window, "Quitter", "Certains éléments n'ont pas été sauvegardés. Voulez-vous réellement quitter l'application ?"))
          return false;
      }
    }
    removeTmpFiles();
    
    return true;
  },

  shutdown : function() {
  },

  customizeToolbars: function() {
    var toolbox = document.getElementById("toolbox_explorer");
		var menubar = document.getElementById("menubar_explorer");

		if(!("customizeDone" in toolbox))
			toolbox.customizeDone = function () {
				var menubar = document.getElementById("menubar_explorer");
				for (var i = 0; i < menubar.childNodes.length; ++i)
					menubar.childNodes[i].setAttribute("disabled", false);

				var cmd = document.getElementById("cmd_ShowToolbarsCustomizer");
				cmd.removeAttribute("disabled");
			};

		for (var i = 0; i < menubar.childNodes.length; ++i)
			menubar.childNodes[i].setAttribute("disabled", true);

		var cmd = document.getElementById("cmd_ShowToolbarsCustomizer");
		cmd.setAttribute("disabled", "true");

		window.openDialog("chrome://global/content/customizeToolbar.xul", "CustomizeToolbar", "chrome,all,dependent", toolbox);
	},

  getCommandTable : function () {
    if(this._commandTable == null) 
       this._commandTable = new nsCommandTable();

    return this._commandTable;
  },
  
  updateGlobalCommands : function() {
    goUpdateCommandset(document.getElementById("commandSet"));
  },
  
  getString : function(aString, argArray) {
    if (this._stringBundle == null) 
       this._stringBundle = document.getElementById("justStrings");

    if(argArray)
      return this._stringBundle.getFormattedString(aString, argArray);
    else 
      return this._stringBundle.getString(aString);
  },
	noteUpdated:	function() {
    this._modified = true;
		var audioElt = document.getElementById("audioboard");
		if (audioElt.focusedSegment) {
			audioElt.focusedSegment.note = this.sectionEditor.getNote();
		}
    pushNewUndoStep();
	},
	segGainFocus:	function(aSegment) {
		var tagSelector = document.getElementById("tagSelector");
		var tag = aSegment.getAttribute("tag");
		if (!tag) {
			tag = "undefined";
		}
		tagSelector.setTag(tag);
		if (aSegment.note) {
			this.sectionEditor.setNote(aSegment.note);
			this.sectionEditor.showEditor(true);
		} else {
			this.sectionEditor.showEditor(false);
			this.sectionEditor.setNote();
			aSegment.note = null;
		}
	},
	segUpdateBounds: function(aSegment, aSegments) {
    pushNewUndoStep();
	},
	segAskForCut: function (node, val) {
    this._modified = true;
		var audioElt = document.getElementById("audioboard");
		var newSection = audioElt.createSection();
		newSection.setAttribute("tag", node.getAttribute("tag"));
		newSection.note = node.note;
		node.parentSection.insertChildSection(newSection, node, this);
	},
	segLooseFocus: function(aSegment) {
		var tagSelector = document.getElementById("tagSelector");
		tagSelector.setTag(null);
	},
	
	setTag: function(tag) {
		var audioElt = document.getElementById("audioboard");
		if (!audioElt.focusedSegment) return;
        var oldTag = audioElt.focusedSegment.getAttribute("tag");
    if (tag) {
  		audioElt.focusedSegment.setAttribute("tag", tag);
  		var tagSelector = document.getElementById("tagSelector");
	  	audioElt.focusedSegment.setAttribute("color", tagSelector.getColorForTag(tag));
    }
		audioElt.updatePlot();
    if (!tag || oldTag == tag) {
      return;
    }
    pushNewUndoStep();
    this._modified = true;
	},
	
	
	togglePlay: function() {
		var button = document.getElementById("playButton");
		var audioElt = document.getElementById("audioboard");
		if (!button.checked) {
			audioElt.playFromCursor();
		} else {
			audioElt.stop();
		}
	},
	addSection:	function() {
    this._modified = true;
		var audioElt = document.getElementById("audioboard");
		audioElt.askForCutRequest();
    pushNewUndoStep();

	},
	removeSection: function() {
    this._modified = true;
		var audioElt = document.getElementById("audioboard");
		if (audioElt.focusedSegment)
			audioElt.removeSection(audioElt.focusedSegment);
    pushNewUndoStep();
	},
	save:	function() {

		var channel = this.getIOService().newChannelFromURI(this.fileURI);
		var DS = Components.classes["@mozilla.org/content/syncload-dom-service;1"].
			getService(Components.interfaces.nsISyncLoadDOMService);
		var doc = DS.loadDocumentAsXML(channel, null);
		var audioFileTag = doc.getElementsByTagName("audiofile")[0];
		while (audioFileTag.hasChildNodes()) {
			audioFileTag.removeChild(audioFileTag.firstChild);
		}

		var rootSectionElt = document.getElementById("segRoot");
		var rootSectionEltChilds = rootSectionElt.childNodes;
		for (var i = 0; i < rootSectionEltChilds.length; i++) {
      var currentNode;
			currentNode = rootSectionEltChilds[i];
			if (currentNode.localName != "section") continue;
			var cr = doc.createTextNode("\n");
			audioFileTag.appendChild(cr);
			var newSection = doc.createElement("section");
			if (currentNode.note) {
				var cdata = doc.createCDATASection(currentNode.note);
				newSection.appendChild(cdata);
			}
			newSection.setAttribute("tag", currentNode.getAttribute("tag"));
			newSection.setAttribute("start", currentNode.start_Second);
			audioFileTag.appendChild(newSection);
		}

		audioFileTag.setAttribute("title", this.getTitle());
		var XS = new XMLSerializer();
		var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
			.createInstance(Components.interfaces.nsIFileOutputStream);
		foStream.init(this.file, 0x02 | 0x08 | 0x20, 0664, 0);
		XS.serializeToStream(doc, foStream, "");
		foStream.close();

    this._modified = false;
		var audioElt = document.getElementById("audioboard");
    audioElt._modified = false;

	},
	fileOpened:	function(file) {
		var descFileURI = this.getIOService().newFileURI(file);
		this.file = file;
		this.fileURI = descFileURI;
		var channel = this.getIOService().newChannelFromURI(descFileURI);
		var DS = Components.classes["@mozilla.org/content/syncload-dom-service;1"].
			getService(Components.interfaces.nsISyncLoadDOMService);
		var doc = DS.loadDocumentAsXML(channel, null);
		
		var audiotag = doc.getElementsByTagName("audiofile")[0];
		this.setTitle(audiotag.getAttribute("title"));
		var audioFileUri = audiotag.getAttribute("src");
		var defFileUri = audiotag.getAttribute("def") + "?" + Math.random();
		var audioElt = document.getElementById("audioboard");
		var segmentSelector = document.getElementById("segmentSelector");
		var tagSelector = document.getElementById("tagSelector");
		segmentSelector.init(audioElt, tagSelector);
		tagSelector.init(defFileUri, this);
		var rootSectionElt = document.getElementById("segRoot");
		var sectionElts = doc.getElementsByTagName("section");
		for (var i = 0; i < sectionElts.length; i++) {
			var start = sectionElts[i].getAttribute("start");
			var tag = sectionElts[i].getAttribute("tag");
			var g = document.createElementNS("http://www.w3.org/2000/svg", "g");
			var section = document.createElementNS("http://www.w3.org/2000/svg", "section");
			section.appendChild(g);
			section.setAttribute("start", start);
			section.setAttribute("tag", tag);
			section.setAttribute("color", tagSelector.getColorForTag(tag));
			if (sectionElts[i].hasChildNodes() && sectionElts[i].firstChild.nodeType == sectionElts[i].firstChild.CDATA_SECTION_NODE)
				section.note = sectionElts[i].firstChild.nodeValue;
			section.segmentOwner = this;
			rootSectionElt.appendChild(section);
		}
		

		var fileProtocolHandler = Components.classes["@mozilla.org/network/protocol;1?name=file"].getService(Components.interfaces.nsIFileProtocolHandler);
		audioElt.init(fileProtocolHandler.getFileFromURLSpec(audioFileUri));
		//audioElt.setFocusOnSegment(rootSectionElt.firstChild);
		
		this.isReady(true);
    this._modified = false;
    audioElt._modified = false;

    removeTmpFiles();
    pushNewUndoStep();
	},

	observe: function(subject, topic, data) {
		var button = document.getElementById("playButton");
		if (data == "stop") {
			button.checked = false;
		} else if (data == "start") {
			button.checked = true;
		}
	},
	isReady: function(ready) {
		this.ready = ready;
    this.updateGlobalCommands();
	}
	
};


// ------------------------------------------------------------------
// Toolbars management
// ------------------------------------------------------------------

function goToolbarsPopupShowing(popup) {
  var i;

  // Empty the menu
  for (i = popup.childNodes.length-1; i >= 0; --i) {
    var deadItem = popup.childNodes[i];
    if (deadItem.hasAttribute("toolbarid"))
        popup.removeChild(deadItem);
  }

  var firstMenuItem = popup.firstChild;

  var toolbars = document.getElementsByTagName("toolbar");
  
  for (i = 0; i < toolbars.length; ++i) {
    var toolbar = toolbars[i];
    var toolbarName = toolbar.getAttribute("toolbarname");
    var type = toolbar.getAttribute("type");
    if (toolbarName && toolbar.id && type != "menubar") {
      var menuItem = document.createElement("menuitem");
      menuItem.setAttribute("toolbarid", toolbar.id);
      menuItem.setAttribute("type"     , "checkbox");
      menuItem.setAttribute("label"    , toolbarName);
      menuItem.setAttribute("accesskey", toolbar.getAttribute("accesskey"));
      menuItem.setAttribute("checked"  , toolbar.getAttribute("hidden") != "true");
      
      popup.insertBefore(menuItem, firstMenuItem);

      menuItem.addEventListener("command", doViewToolbar, false);
    }
    toolbar = toolbar.nextSibling;
  }
}

function doViewToolbar( event ) {
  var id      = event.originalTarget.getAttribute("toolbarid");
  var toolbar = document.getElementById(id);

  toolbar.hidden = !toolbar.hidden;
  document.persist(id, 'hidden');
}


// ------------------------------------------------------------------
// Open files
// ------------------------------------------------------------------

function goOpenFiles(title, openMultiple, preference, filters, aOpenMode) {
  const nsIFilePicker = Ci.nsIFilePicker;
  var prefs = Cc["@mozilla.org/preferences-service;1"]
    .getService(Ci.nsIPrefBranch);

  var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);

	var openMode;
	if (!aOpenMode)
		openMode = openMultiple ? nsIFilePicker.modeOpenMultiple : nsIFilePicker.modeOpen;
	else {
		openMode = aOpenMode;
		if (openMode == nsIFilePicker.modeSave) {
			fp.defaultString = "description.xml";
		}
	}

  fp.init(window, title, openMode);  

  if (filters) for (var i = 0; i < filters.length; i++) {
    fp.appendFilter(filters[i].name, filters[i].ext);
  }

  var dir   = null;
  try {
    dir = prefs.getComplexValue(preference, Ci.nsILocalFile);
  } catch (e) {}

  if(dir && dir.exists())
    fp.displayDirectory = dir;

  var ret = fp.show();
  if( ret == nsIFilePicker.returnOK || ret == nsIFilePicker.returnReplace) 
  {
    var results = [];    
    var nsILocalFile = Ci.nsILocalFile;

    dir = null;

    var file;

    if(openMultiple) 
    {
      var files = fp.files;
      while (files.hasMoreElements()) {
        file = files.getNext().QueryInterface(nsILocalFile);
        results.push(file);
      }
    } else {
      results.push(file = fp.file);

      var dir  = file.parent.QueryInterface(nsILocalFile);
      prefs.setComplexValue(preference, Ci.nsILocalFile, dir);
    }

    return results;         
  }
  return null;  
}


function goOpenFile(title, mode, preference, filters, mode) {
  var results = goOpenFiles(title, false, preference, filters, mode);
  if(results) 
    return results[0];

  return null;
}

// ------------------------------------------------------------------
// Misc
// ------------------------------------------------------------------

function goDoCommandParams(command, params) {
  var controller = gTagger.getCommandTable().getCommand(command);
  if (controller && controller.isCommandEnabled(command)) {
    controller.doCommandWithParams(command, params);
  }
}

// ------------------------------------------------------------------
// Temp files
// ------------------------------------------------------------------
function pushNewUndoStep() {
  if (dontStock) return;
  for (var i = (MAX_UNDO - 1); i >= 0; i--) {
    var file = getTmpDir();
    file.append(UNDO_FILE_PREFIX + "-" + UFID + "-" + i);
    if (file.exists()) {
      if (i == (MAX_UNDO - 1)) {
        file.remove(false);
      } else {
        file.moveTo(getTmpDir(), UNDO_FILE_PREFIX + "-" + UFID + "-" + (i + 1));
      }
    }
  }

  gTagger.fileURI.QueryInterface(Ci.nsIFileURL);
  gTagger.fileURI.file.copyTo(getTmpDir(), UNDO_FILE_PREFIX + "-" + UFID + "-0");
  var file = getTmpDir();
  file.append(UNDO_FILE_PREFIX + "-" + UFID + "-0");
  var channel = gTagger.getIOService().newChannelFromURI(gTagger.getIOService().newFileURI(file));
  var DS = Cc["@mozilla.org/content/syncload-dom-service;1"].
    getService(Ci.nsISyncLoadDOMService);
  var doc = DS.loadDocumentAsXML(channel, null);
  var audioFileTag = doc.getElementsByTagName("audiofile")[0];
  while (audioFileTag.hasChildNodes()) {
    audioFileTag.removeChild(audioFileTag.firstChild);
  }

  var rootSectionElt = document.getElementById("segRoot");
  var rootSectionEltChilds = rootSectionElt.childNodes;
  for (var i = 0; i < rootSectionEltChilds.length; i++) {
    var currentNode;
    currentNode = rootSectionEltChilds[i];
    if (currentNode.localName != "section") continue;
    var cr = doc.createTextNode("\n");
    audioFileTag.appendChild(cr);
    var newSection = doc.createElement("section");
    if (currentNode.note) {
      var cdata = doc.createCDATASection(currentNode.note);
      newSection.appendChild(cdata);
    }
    newSection.setAttribute("tag", currentNode.getAttribute("tag"));
    newSection.setAttribute("start", currentNode.start_Second);
    audioFileTag.appendChild(newSection);
  }

  audioFileTag.setAttribute("title", gTagger.getTitle());
  var XS = new XMLSerializer();
  var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
  foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0);
  XS.serializeToStream(doc, foStream, "");
  foStream.close();

  updateUndoStatus();
}

function canUndo() {
  var file = getTmpDir();
  file.append(UNDO_FILE_PREFIX + "-" + UFID + "-1");
  return file.exists();
}

function undo() {
  if (!canUndo()) return;
  dontStock = true;
  try {
  var file = getTmpDir();
  file.append(UNDO_FILE_PREFIX + "-" + UFID + "-1");
  var channel = gTagger.getIOService().newChannelFromURI(gTagger.getIOService().newFileURI(file));

  var DS = Components.classes["@mozilla.org/content/syncload-dom-service;1"].
    getService(Components.interfaces.nsISyncLoadDOMService);
  var doc = DS.loadDocumentAsXML(channel, null);

  var audiotag = doc.getElementsByTagName("audiofile")[0];
  gTagger.setTitle(audiotag.getAttribute("title"));
  var audioFileUri = audiotag.getAttribute("src");
  var defFileUri = audiotag.getAttribute("def") + "?" + Math.random();
  var audioElt = document.getElementById("audioboard");
  var segmentSelector = document.getElementById("segmentSelector");
  var tagSelector = document.getElementById("tagSelector");
  //segmentSelector.init(audioElt, tagSelector);
  //tagSelector.init(defFileUri, this);
  var rootSectionElt = document.getElementById("segRoot");
  while (rootSectionElt.hasChildNodes()) {
    rootSectionElt.removeChild(rootSectionElt.firstChild);
  }
  var sectionElts = doc.getElementsByTagName("section");
  for (var i = 0; i < sectionElts.length; i++) {
    var start = sectionElts[i].getAttribute("start");
    var tag = sectionElts[i].getAttribute("tag");
    var g = document.createElementNS("http://www.w3.org/2000/svg", "g");
    var section = document.createElementNS("http://www.w3.org/2000/svg", "section");
    section.appendChild(g);
    section.setAttribute("start", start);
    section.setAttribute("tag", tag);
    section.setAttribute("color", tagSelector.getColorForTag(tag));
    if (sectionElts[i].hasChildNodes() && sectionElts[i].firstChild.nodeType == sectionElts[i].firstChild.CDATA_SECTION_NODE)
      section.note = sectionElts[i].firstChild.nodeValue;
    section.segmentOwner = gTagger;
    rootSectionElt.appendChild(section);
  }
  audioElt.simpleUpdate();
  this._modified = true;
  audioElt._modified = true;



  var file0 = getTmpDir();
  file0.append(UNDO_FILE_PREFIX + "-" + UFID + "-0");
  file0.remove(false);
  for (var i = 1; i < MAX_UNDO; i++) {
    var file = getTmpDir();
    file.append(UNDO_FILE_PREFIX + "-" + UFID + "-" + i);
    if (file.exists())
      file.moveTo(getTmpDir(), UNDO_FILE_PREFIX + "-" + UFID + "-" + (i - 1));
  }
  } catch(e) {};
  dontStock = false;
  updateUndoStatus();
}


function getTmpDir() {
  var props = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
  return props.get("TmpD", Ci.nsIFile);
}

function removeTmpFiles() {
  for (var i = 0; i < MAX_UNDO; i++) {
    var file = getTmpDir();
    file.append(UNDO_FILE_PREFIX + "-" + UFID + "-" + i);
    if (file.exists()) {
      file.remove(false);
    }
  }
}

function updateUndoStatus() {
  var button = document.getElementById("undo");
  if (canUndo()) {
    button.removeAttribute("disabled");
  } else {
    button.setAttribute("disabled", true);
  }
}
