var EXPORTED_SYMBOLS = ["YOONO_LOG"];

try {

// Vars
const YOONO_DIR = "yoono";
const YOONO_DEBUG_PREF = "extensions.yoono.debug.level";
const YOONO_DEBUG_WRITE_PREF = "extensions.yoono.debug.write";

const LOGFILE_CREATE_PERMISSIONS = 0600;
const LOGFILE_FILE_FLAGS = 0x02 | 0x08 | 0x10; // WRONLY | CREATE_FILE | APPEND

// Globals
const CI = Components.interfaces;
const CL = Components.classes;

const PREFBRANCH = CL['@mozilla.org/preferences-service;1'].getService(CI.nsIPrefBranch);
const PREFSSERVICE = CL["@mozilla.org/preferences-service;1"].getService(CI.nsIPrefService);
const PREFS = PREFSSERVICE.getBranch("extensions.yoono.");
const CONSOLESERVICE = CL["@mozilla.org/consoleservice;1"].getService(CI.nsIConsoleService);
const DIRSERVICE = CL['@mozilla.org/file/directory_service;1'].getService(CI.nsIProperties);


function Log() {

	this.wrappedJSObject=this;
	
	var lvl=PREFSSERVICE.QueryInterface(CI.nsIPrefBranch).getIntPref(YOONO_DEBUG_PREF);
	if (lvl && lvl>=0)
		this.level = lvl;
	else
		this.level = 2;
	
	PREFSSERVICE.QueryInterface(CI.nsIPrefBranch2).addObserver(YOONO_DEBUG_PREF, this, false);
	this.logFile = DIRSERVICE.get('ProfDS', CI.nsIFile);
	this.logFile.append(YOONO_DIR);
	try {
		this.logFile.create(CI.nsIFile.DIRECTORY_TYPE,0700);
	} catch(e) {}
	this.logFile.append('yoono.log');
	
}
// with the top <try catch>, we must set constructor after his declaration
const SERVICE_CONSTRUCTOR = Log;

Log.prototype.init = function (y) {
  this.rotateLogs();
  var _self = this;
  this.writeLog('################################################################################\n');
	this.dumpDebugInfo(y);
}


// Logs general debug info
Log.prototype.dumpDebugInfo = function(aYoono) {
  var aDebugInfo = '###################### PLATFORM INFORMATION #########################\n';

  var appInfo = CL["@mozilla.org/xre/app-info;1"].getService(CI.nsIXULAppInfo);
  aDebugInfo = aDebugInfo+'firefox version                 : '+appInfo.version+'\n';
  aDebugInfo = aDebugInfo+'firefox build id                : '+appInfo.appBuildID+'\n';
  aDebugInfo = aDebugInfo+'yoono extension version         : '+aYoono.main.getExtensionVersion()+'\n';
  try { aDebugInfo = aDebugInfo+'general.useragent.extra.firefox : '+PREFBRANCH.getCharPref('general.useragent.extra.firefox')+'\n'; } catch(e) {};
  try { aDebugInfo = aDebugInfo+'general.useragent.locale        : '+PREFBRANCH.getCharPref('general.useragent.locale')+'\n' } catch(e) {};
  try { aDebugInfo = aDebugInfo+'intl.accept_languages           : '+PREFBRANCH.getCharPref('intl.accept_languages')+'\n' } catch(e) {};

  // Affiche le chemin du r�pertoire profile
  try {aDebugInfo = aDebugInfo+'Profile directory               : '+DIRSERVICE.get("ProfD",CI.nsIFile).path+'\n' } catch(e) {};

  // Liste les preferences yoono
  aDebugInfo = aDebugInfo+'\nYoono preferences :\n';
  var yoonoPrefChildren = PREFS.getChildList("", {});
  for(var i in yoonoPrefChildren) {
    if (yoonoPrefChildren[i] == "userid"){
      aDebugInfo = aDebugInfo+'extensions.yoono.'+yoonoPrefChildren[i]+' : **********************\n';
    }
    else {
      switch(PREFBRANCH.getPrefType('extensions.yoono.'+yoonoPrefChildren[i])) {
      case CI.nsIPrefBranch.PREF_STRING: // PREF_STRING = 32
        aDebugInfo = aDebugInfo+'extensions.yoono.'+yoonoPrefChildren[i]+' : '+PREFBRANCH.getCharPref('extensions.yoono.'+yoonoPrefChildren[i])+'\n';
        break;
      case CI.nsIPrefBranch.PREF_INT: // PREF_INT    = 64
        aDebugInfo = aDebugInfo+'extensions.yoono.'+yoonoPrefChildren[i]+' : '+PREFBRANCH.getIntPref('extensions.yoono.'+yoonoPrefChildren[i])+'\n';
        break;
      case CI.nsIPrefBranch.PREF_BOOL: // PREF_BOOL    = 128
        aDebugInfo = aDebugInfo+'extensions.yoono.'+yoonoPrefChildren[i]+' : '+PREFBRANCH.getBoolPref('extensions.yoono.'+yoonoPrefChildren[i])+'\n';
        break;
      }
    }
  }
  var plugins = "\n\nInstalled plugins (FF4 only):\n";
  var themes = "\n\nInstalled themes :\n";
  aDebugInfo += '\nInstalled extensions :\n';

  for(var id in aYoono.main.addOns) {
    var addOn = aYoono.main.addOns[id];
    var info = ' ' +addOn.name+', version='+addOn.version+'\n' ;
    switch(addOn.type) {
      case 2:   // FF3
      case 'extension':  // FF4
        aDebugInfo += info;
        break;
      case 'plugin':
        plugins += info;
        break;
      case 4:  // FF3
      case 'theme':  // FF4
        themes += info;
        break;
    }
  }
  aDebugInfo += plugins + themes + "\n";
  this.writeLog(aDebugInfo);
}


Log.prototype.rotateLogs = function() {
  // Rotation des logs
  var chemin = null;
  try {
    chemin = DIRSERVICE.get('ProfDS', CI.nsIFile);
    chemin.append(YOONO_DIR);
    if(!chemin.exists()) {
      chemin.create(CI.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
    }
    var aFile = chemin;
    // Suppression du log le plus ancien
    aFile.append('yoono.log.003');
    if( aFile.exists() ) aFile.remove(true);
    // Rotation
    for(var i=2 ; i>=0 ; i--) {
      chemin = DIRSERVICE.get('ProfDS', CI.nsIFile);
      chemin.append(YOONO_DIR);
      if(0 == i) {
        chemin.append('yoono.log');
      } else {
        chemin.append('yoono.log.00' + i);
      }
      if(chemin.exists()) {
        var newFile = DIRSERVICE.get('ProfDS', CI.nsIFile);
        newFile.append(YOONO_DIR);
        chemin.moveTo(newFile,'yoono.log.00' + (i + 1));
      }
    }
  } catch(err) {CONSOLESERVICE.logStringMessage('Rotation ' + err)}
}
Log.prototype.observe = function(aSubject, aTopic, aData) {
	
    if (aTopic != "nsPref:changed" || aData != YOONO_DEBUG_PREF )
		return;
    this.level = PREFSSERVICE.getIntPref(YOONO_DEBUG_PREF);
	
}

Log.prototype.writeLog = function(aOutput){
	if (this.logFile) {
		try {
			var fileOutputStream = CL['@mozilla.org/network/file-output-stream;1'].createInstance(CI.nsIFileOutputStream);
			fileOutputStream.init(this.logFile, LOGFILE_FILE_FLAGS, LOGFILE_CREATE_PERMISSIONS, 0);
			var converter = CL['@mozilla.org/intl/converter-output-stream;1'].createInstance(CI.nsIConverterOutputStream);
			converter.init(fileOutputStream, 'UTF-8', 1024, '-');
			converter.writeString(aOutput);
			converter.flush();
			fileOutputStream.close();
		} catch(err) {CONSOLESERVICE.logStringMessage('Ouverture log "' + this.logFile.path+'" :: '+err)}
	}
	
}

var gDate = (new Date()).getTime();

Log.prototype.log = function(type, message, file, line) {
	
	// write message in log file
	var msg = ((new Date()).getTime() - gDate) + 'ms, ' + message + "\n";
	// Pretty print file which send this log line
	var location="?";
	if (file) {
		file=file.replace(/\.js$/,"");
    if (file.match(/^chrome:\/\/yoonosb\/content\/js\/services\//)) {
      var file = file.replace(/^chrome:\/\/yoonosb\/content\/js\/services\/(src\/)?/,"");
      location="YServices."+file.split(/\//).join(".");
    } else if (file.match(/^chrome:\/\/yoonosb\/content\/js\//)) {
      var file = file.replace(/^chrome:\/\/yoonosb\/content\/js\//,"");
      //var t = file.split(/\//);
      location="sb::"+file;
    } else if (file.match(/^chrome:\/\/yoonosb\/content\//)) {
      var file = file.replace(/^chrome:\/\/yoonosb\/content\//,"");
      location="widget::"+file;
		} else if (file.match(/^chrome:\/\/yoono/)) {
      var file = file.replace(/^chrome:\/\/yoono\/content\//,"");
			//var t=file.split(/\//);
			location="ext::"+file;
		} else if (file.match(/^file:/)) {
			location="xpcom::"+file.replace(/yoono/,"").replace(/^file.*\//,"");
		} else {
			location=file;
		}
	}
	YOONO_LOG.writeLog(type+','+location+':'+line+','+(new Date().toLocaleString())+","+msg);
	return (type+" ["+location+"@"+line+"] "+msg);
}
function stack2string(stack) {
	if (!stack) return "";
	return " - "+stack.filename+"@"+stack.lineNumber+" : \n"+stack2string(stack.caller);
}
Log.prototype.backtrace = function(msg) {
	var caller=Components.stack.caller;
	var message=msg+"\n"+stack2string(caller);
	CONSOLESERVICE.logStringMessage(YOONO_LOG.log('debug', message, caller.filename, caller.lineNumber));
}
Log.prototype.debug = function(message, stack) {
try {
	var caller=stack?stack:Components.stack.caller;
	if (YOONO_LOG.level>=6) {
		var scriptError = CL["@mozilla.org/scripterror;1"].createInstance(CI.nsIScriptError);
		scriptError.init(YOONO_LOG.log('debug', message, caller.filename, caller.lineNumber), caller.filename, null, caller.lineNumber+1, null, scriptError.warningFlag, "");
		CONSOLESERVICE.logMessage(scriptError);
	} else if (YOONO_LOG.level>=5) {
		CONSOLESERVICE.logStringMessage(YOONO_LOG.log('debug', message, caller.filename, caller.lineNumber));
	}
} catch(e){
	Components.utils.reportError("debug error : "+e);
}
}
Log.prototype.info = function(message, stack) {
	var caller=stack?stack:Components.stack.caller;
	if (YOONO_LOG.level>=4) {
		CONSOLESERVICE.logStringMessage(YOONO_LOG.log('info', message, caller.filename, caller.lineNumber));
	}
}
Log.prototype.warn = function(message, stack) {
	var caller=stack?stack:Components.stack.caller;
	if (YOONO_LOG.level>=3) {
		var scriptError = CL["@mozilla.org/scripterror;1"].createInstance(CI.nsIScriptError);
		scriptError.init(YOONO_LOG.log('warning', message, caller.filename, caller.lineNumber), caller.filename, null, caller.lineNumber+1, null, scriptError.warningFlag, "");
		CONSOLESERVICE.logMessage(scriptError);
	}
}
Log.prototype.error = function(message, stack) {
	var caller=stack?stack:Components.stack.caller;
	if (YOONO_LOG.level>=2) {
		var scriptError = CL["@mozilla.org/scripterror;1"].createInstance(CI.nsIScriptError);
		scriptError.init(YOONO_LOG.log('error', message, caller.filename, caller.lineNumber), caller.filename, null, caller.lineNumber+1, null, scriptError.errorFlag, "");
		CONSOLESERVICE.logMessage(scriptError);
	}
}
Log.prototype.exception = function(exception) {
  var aString = 
                (typeof exception == "string" ? "message : " + exception + "\n\r\n\r" : "") +
                (exception.message != null ? "message : " + exception.message + "\n\r\n\r" : "") +
                (exception.name != null ? "name : " + exception.name + "\n\r\n\r" : "") +
                (exception.description != null ? "description : " + exception.description + "\n\r\n\r" : "") +
                ("stack : "+(exception.stack != null ? exception.stack + "\n\r\n\r" : stack2string(Components.stack.caller)) + "\n\r\n\r" );
	var filename=(exception && exception.fileName)?exception.fileName:Components.stack.caller.filename;
	var lineNumber=(exception && exception.lineNumber)?exception.lineNumber:Components.stack.caller.lineNumber;
	if (YOONO_LOG.level>=2) {
		var scriptError = CL["@mozilla.org/scripterror;1"].createInstance(CI.nsIScriptError);
		scriptError.init(YOONO_LOG.log('exception', aString, filename, lineNumber), filename, null, lineNumber+1, null, scriptError.errorFlag, "");
		CONSOLESERVICE.logMessage(scriptError);
	}
}
Log.prototype.fatal = function(message, stack) {
	var caller=stack?stack:Components.stack.caller;
	if (YOONO_LOG.level>=1) {
		var scriptError = CL["@mozilla.org/scripterror;1"].createInstance(CI.nsIScriptError);
		scriptError.init(YOONO_LOG.log('fatal', message, caller.filename, caller.lineNumber), caller.filename, null, caller.lineNumber+1, null, scriptError.errorFlag, "");
		CONSOLESERVICE.logMessage(scriptError);
	}
}

/**
 * return if Error level is active
 * @method isErrorEnabled
 * @return {Boolean}
 * @type Boolean
 */
Log.prototype.isErrorEnabled = function() {
  return YOONO_LOG.level >= 2;
}

/**
 * return if warn level is active
 * @method isWarnEnabled
 * @return {Boolean}
 * @type Boolean
 */
Log.prototype.isWarnEnabled = function() {
  return YOONO_LOG.level >= 3;
}

/**
 * return if info level is active
 * @method isInfoEnabled
 * @return {Boolean}
 * @type Boolean
 */
Log.prototype.isInfoEnabled = function() {
  return YOONO_LOG.level >= 4;

}

/**
 * return if debug level is active
 * @method isDebugEnabled
 * @return {Boolean}
 * @type Boolean
 */
Log.prototype.isDebugEnabled = function() {
  return YOONO_LOG.level >= 5;
}


var YOONO_LOG = new Log();

} catch(e) {
	Components.utils.reportError("javascript error in xpcom : "+e);
}
