var logBox,
    LogLevel   = 0,
    Log        = {},
    LogBox     = Class.create(),
    LogNames   = [ [ 'Debug', 'black', 'normal' ],
                   [ 'Error', 'red',   'normal' ],
                   [ 'Fatal', 'red',   'bold' ] ];

Log.write = function(text, e){
  if ( ! logBox ) logBox = new LogBox();
  logBox.write( 0, text, e );
}

Log.logDebug = function(text, e){
  if ( ! logBox ) logBox = new LogBox();
  logBox.write( 0, text, e );
}
Log.logError = function(text, e){
  if ( ! logBox ) logBox = new LogBox();
  logBox.write( 1, text, e );
}
Log.logFatal = function(text, e){
  if ( ! logBox ) logBox = new LogBox();
  logBox.write( 2, text, e );
}

LogBox.prototype = {
  initialize: function() {
    var box     = document.createElement( 'div' ),
        table   = document.createElement( 'table' ),
        tbody   = document.createElement( 'tbody' ),
        trmenu  = document.createElement( 'tr' ),
        tdcotit = document.createElement( 'td' ),
        tdcount = document.createElement( 'td' ),
        tdmove  = document.createElement( 'td' ),
        tdclear = document.createElement( 'td' ),
        tdclose = document.createElement( 'td' ),
        log     = document.createElement( 'div' ),
        status  = document.createElement( 'div' ),
        body    = document.body;

    if ( ! body )
      return;

    this.counter = 1;
    this.move    = false;

    this.count   = tdcount;
    this.box     = box;
    this.log     = log;

    tdcotit.innerHTML = '&#160; #';
    tdmove.innerHTML  = 'Debug console';

    trmenu.appendChild( tdcotit );
    trmenu.appendChild( tdcount );
    trmenu.appendChild( tdmove  );
    trmenu.appendChild( tdclear );
    trmenu.appendChild( tdclose );

    this._mouseDown = this.mouseDown.bindAsEventListener(this);
    this._mouseMove = this.mouseMove.bindAsEventListener(this);
    this._mouseUp   = this.mouseUp.bindAsEventListener(this);
    this._clear     = this.clear.bindAsEventListener(this);
    this._close     = this.close.bindAsEventListener(this);

    Event.observe( trmenu,                   'mousedown', this._mouseDown, false );
    Event.observe( tdclear,                  'click',     this._clear,     false );
    Event.observe( tdclose,                  'click',     this._close,     false );

    tdclear.title = 'Clear';
    tdclose.title = 'Close';

    if ( navigator.appVersion.match(/\bMSIE\b/) ){
      tdclose.innerHTML = '&#114;';
      tdclear.innerHTML = '&#113;';
      Element.setStyle( tdclose, { cursor:          'pointer',
                                   fontFamily:      'webdings' } );
      Element.setStyle( tdclear, { cursor:          'pointer',
                                   fontFamily:      'webdings' } );
    } else {
      var imgclose = new Image(),
          imgclear = new Image();

      imgclose.src = 'data:image/gif;base64,' +
                     'iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAFcp1ZSAAAADFBMVEX///8MQZr/' +
                     'AAD/AADqa4V5AAAAWUlEQVQImT1KsQ3AIAyzeg5XIkauqJiQJ05g5BTExAFIaQKo' + 
                     'cew4TrDQ0DHxKpq3FvBi0KPHQ/MiFWRFShU5qndn2m65cZAs6I6hYITsVPPDX3dy' +
                     'r/tTtOYHhbxDShDFH1IAAAAASUVORK5CYII=';
      imgclear.src = 'data:image/gif;base64,' +
                     'iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAFcp1ZSAAAADFBMVEX///8MQZr/' +
                     'AAD/AADqa4V5AAAAWklEQVQImT2KsQ2AMAwEX5SMkilTewrkyvqKETILFUqVASIZ' +
                     'JwT8+vf5ZXTcoQbgwJVRMxwKCRGVUehysHsBWWCpQPl63JS1w5Xk+aXaSJkstk9O' +
                     'kbb9Px7THqrQROrI09tMAAAAAElFTkSuQmCC';
      Element.setStyle( imgclose, { border: '0px', verticalAlign: 'top' } );
      Element.setStyle( imgclear, { border: '0px', verticalAlign: 'top' } );
      tdclose.appendChild( imgclose );
      tdclear.appendChild( imgclear );
      Element.setStyle( tdclear, { textAlign:       'right' } );
      Element.setStyle( tdclose, { textAlign:       'right' } );
    }

    tbody.appendChild( trmenu );
    table.appendChild( tbody );
    box.appendChild( table );
    box.appendChild( log );
    box.appendChild( status );

    Element.setStyle( table,   { borderCollapse:  'collapse',
                                 tableLayout:     'fixed',
                                 width:           '600px',
                                 margin:          '0px',
                                 padding:         '0px',
                                 borderBottom:    '1px solid black' } );
    Element.setStyle( trmenu,  { backgroundColor: '#cccccc',
                                 color:           'black',
                                 verticalAlign:   'middle',
                                 height:          '18px',
                                 cursor:          'move' } );
    Element.setStyle( tdcotit, { width:           '20px',
                                 height:          '18px',
                                 textAlign:       'right',
                                 paddingRight:    '5px' } );
    Element.setStyle( tdcount, { width:           '40px',
                                 height:          '18px' } );
    Element.setStyle( tdmove,  { width:           '492px',
                                 height:          '18px',
                                 backgroundColor: '#cccccc' } );
    Element.setStyle( tdclear, { cursor:          'pointer',
                                 height:          '18px',
                                 width:           '19px' } );
    Element.setStyle( tdclose, { cursor:          'pointer',
                                 height:          '18px',
                                 width:           '19px' } );
    Element.setStyle( log,     { backgroundColor: 'white',
                                 color:           'black',
                                 paddingLeft:     '5px',
                                 paddingRight:    '5px',
                                 height:          '262px',
                                 overflow:        'auto' } );
    Element.setStyle( status,  { backgroundColor: '#cccccc',
                                 color:           'black',
                                 paddingLeft:     '5px',
                                 paddingRight:    '5px',
                                 height:          '18px',
                                 overflow:        'auto',
                                 borderTop:       '1px solid black' } );
    Element.setStyle( box,     { border:          '1px solid black',
                                 position:        'absolute',
                                 bottom:          '10px',
                                 right:           '10px',
                                 width:           '600px',
                                 height:          '300px',
                                 zIndex:          1000000 } );

    Element.hide( box );

    body.appendChild( box );
  },
  write: function( level, text, error ){
    if ( level < LogLevel ){

    } else if ( ! this.box ){
      alert( "!!!LOG!!!\n" + text );
    } else {
      var div   = document.createElement( 'div' ),
          line1 = document.createElement( 'div' ),
          line2 = document.createElement( 'div' ),
          date  = new Date(),
          conf  = LogNames[ level ],
          msg1  = "[%s&nbsp;#%04d&nbsp;%02d:%02d:%02d.%03d]".sprintf(
                       conf[0], this.counter,
                       date.getHours(), date.getMinutes(),
                       date.getSeconds(), date.getMilliseconds() ),
          msg2  = text;

      this.counter++;
      this.count.innerHTML = this.counter;

      if ( error ){
        var stack = error.stack;
        msg2 += error + "\n";
        try {
          msg2 += " [Line: %d / File: %s / Name: %s]<br />Stack: %s".sprintf(
                    error.lineNumber, error.fileName, error.name, stack );
        } catch( e ) { }
      }

      Element.setStyle( div, { borderBottom:    '1px solid #cccccc',
                               backgroundColor: 'white' } );
      Element.setStyle( line1, { color:         conf[1],
                                 fontWeight:    conf[2],
                                 fontSize:      '10px' } );
      Element.setStyle( line2, { fontSize:      '12px',
                                 paddingLeft:   '20px' } );

      line1.innerHTML = msg1;
      line2.innerHTML = msg2;
      div.appendChild( line1 );
      div.appendChild( line2 );

      if ( this.log.firstChild )
        this.log.insertBefore( div, this.log.firstChild );
      else 
        this.log.appendChild( div );

      Element.show( this.box );
    } 
  },
  close: function( event ) {
    Element.hide( this.box );
    Event.stop( event );
  },
  clear: function( event ) {
    this.log.innerHTML = '';
    Event.stop( event );
  },
  mouseDown: function( event ){
    if ( Event.isLeftClick( event ) ){
      var offset = Position.cumulativeOffset( this.box );
      this.move   = true;
      this.mousex = Event.pointerX( event ) - offset[0];
      this.mousey = Event.pointerY( event ) - offset[1];
      Event.observe( document.body.parentNode, 'mousemove', this._mouseMove, false );
      Event.observe( document.body.parentNode, 'mouseup',   this._mouseUp,   false );
      Event.stop( event );
    }
  },
  mouseMove: function( event ){
    if ( this.move ){
      var mousex = Event.pointerX( event ),
          mousey = Event.pointerY( event ),
          diffx  = mousex - this.mousex,
          diffy  = mousey - this.mousey;
      var offset = Position.cumulativeOffset( this.box );

      Element.setStyle( this.box, { top:    diffy + 'px',
                                    left:   diffx + 'px' } );
      Event.stop( event );
    }
  },
  mouseUp: function( event ){
    this.move = false;
    Event.stopObserving( document.body.parentNode, 'mousemove', this._mouseMove, false );
    Event.stopObserving( document.body.parentNode, 'mouseup',   this._mouseUp,   false );
    Event.stop( event );
  }
}


