//
// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2008
// http://flock.com
//
// This file may be used under the terms of the
// GNU General Public License Version 2 or later (the "GPL"),
// http://www.gnu.org/licenses/gpl.html
//
// 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.
//
// END FLOCK GPL
//

const CC = Components.classes;
const CI = Components.interfaces;
const CR = Components.results;

Components.utils.import("resource:///modules/FlockXPCOMUtils.jsm");
FlockXPCOMUtils.debug = false;

const MODULE_NAME = "Flock Logging File Writer";

const CLASS_NAME = "Flock Logging File Writer";
const CLASS_ID = Components.ID("{b2045e5e-c742-4dbc-8fae-233f428bc9c0}");
const CONTRACT_ID = "@flock.com/logging-file-writer;1";

const LOGGER_FILENAME = "log.txt";

/* from nspr's prio.h */
const PR_RDONLY      = 0x01;
const PR_WRONLY      = 0x02;
const PR_RDWR        = 0x04;
const PR_CREATE_FILE = 0x08;
const PR_APPEND      = 0x10;
const PR_TRUNCATE    = 0x20;
const PR_SYNC        = 0x40;
const PR_EXCL        = 0x80;

/**************************************************************************
 * Component: Flock Logging File Writer
 **************************************************************************/

// Constructor.
function flockLoggingFileWriter()
{
  this._initialized = false;

  // Note: This observer is required for the life of the application.
  //       Not removing it anywhere looks like a leak, but in fact it
  //       does not leak until the application exits, at which
  //       point it becomes moot.
  var obs = CC["@mozilla.org/observer-service;1"]
            .getService(CI.nsIObserverService);
  obs.addObserver(this, "profile-after-change", false);
}

/**************************************************************************
 * Flock Logging File Writer: XPCOM Component Creation
 **************************************************************************/

flockLoggingFileWriter.prototype = new FlockXPCOMUtils.genericComponent(
  CLASS_NAME,
  CLASS_ID,
  CONTRACT_ID,
  flockLoggingFileWriter,
  CI.nsIClassInfo.SINGLETON,
  [
    CI.flockILoggingObserver,
    CI.nsIObserver
  ]
);

// FlockXPCOMUtils.genericModule() categories
flockLoggingFileWriter.prototype._xpcom_categories = [
  { category: "flockILoggingObserver" }
];

/**************************************************************************
 * Flock Logging File Writer: Private Data and Functions
 **************************************************************************/

// Member variables.
flockLoggingFileWriter.prototype._initialized = null;
flockLoggingFileWriter.prototype._converter = null;
flockLoggingFileWriter.prototype._outputStream = null;

flockLoggingFileWriter.prototype._initFile =
function LogFileWriter__initFile() {
  // Prepare the log file for the requested module
  var dirService = CC["@mozilla.org/file/directory_service;1"]
                   .getService(CI.nsIProperties);
  var profileDir = dirService.get("ProfD", CI.nsILocalFile);
  var file = CC["@mozilla.org/file/local;1"].createInstance(CI.nsILocalFile);
  file.initWithPath(profileDir.path);
  file.append(LOGGER_FILENAME);
  if (!file.exists()) {
    // 0600 = -rw------- permissions
    file.createUnique(CI.nsILocalFile.NORMAL_FILE_TYPE, 0600);
  }

  var transport = CC["@mozilla.org/network/file-output-stream;1"]
                  .createInstance(CI.nsIFileOutputStream);
  // 0640 = -rw-r----- permissions
  transport.init(file, PR_RDWR | PR_CREATE_FILE | PR_APPEND, 0640, 0);

  this._converter = CC["@mozilla.org/intl/scriptableunicodeconverter"]
                    .createInstance(CI.nsIScriptableUnicodeConverter);
  this._converter.charset = "UTF-8";

  this._outputStream = CC["@mozilla.org/network/buffered-output-stream;1"]
                       .createInstance(CI.nsIBufferedOutputStream);
  this._outputStream.init(transport, 65536 * 4);  // 256k buffer

  this._initialized = true;
}

flockLoggingFileWriter.prototype._pad =
function LogFileWriter__pad(aNumber, aPlaces) {
  var numberString = aNumber + "";
  while (numberString.length < aPlaces) {
    numberString = "0" + numberString;
  }
  return numberString;
}


/**************************************************************************
 * Flock Logging File Writer: flockILoggingService Implementation
 **************************************************************************/

flockLoggingFileWriter.prototype.emit =
function LogFileWriter_emit(aDate, aLevel, aContext, aMessage) {
  if (this._initialized) {
    var levels = ["all", "debug", "info", "warn", "error", "fatal"];
    var date = new Date(aDate);
    var dateString = date.toLocaleFormat("%Y-%m-%d %H:%M:%S.")
                   + this._pad(date.getMilliseconds(), 3);
    var content = "[" + dateString + " " + aContext
                + ":" + levels[aLevel] + "] " + aMessage
                + "\n";
    var inputStream = this._converter.convertToInputStream(content);
    this._outputStream.writeFrom(inputStream, inputStream.available());
    this._outputStream.flush();
  }
}

/**************************************************************************
 * Flock Logging File Writer: nsIObserver Implementation
 **************************************************************************/

flockLoggingFileWriter.prototype.observe =
function LogFileWriter_observe(subject, topic, state) {
  switch (topic) {
    case "profile-after-change":
      // init log file
      this._initFile();
      break;
  }
}

/**************************************************************************
 * END Flock Logging File Writer
 **************************************************************************/


/**************************************************************************
 * XPCOM Support - Module Construction
 **************************************************************************/

// Create array of components.
var gComponentsArray = [flockLoggingFileWriter];

// Generate a module for XPCOM to find.
var NSGetModule = FlockXPCOMUtils.generateNSGetModule(MODULE_NAME,
                                                      gComponentsArray);
