/**************************************

  deskDo -- todolist on your desktop

  (c) 2005 Pixel-Apes.

 **************************************/


function deskDoEditable( desk, id ) 
{ 
  this.desk = desk;
  this.id = id;
}

deskDoEditable.prototype = 
{
    dummy : false, // if true, then this editable do not exist from now on. Used for removal

    siblings : [], // editables spawned by incoming data, including this one
    wrapper : false,

    _data : "",
    _html : "",
    _compiled : false,
    _wakaTree : [],

    _readOnly : false,

    preset : "default", // waka31 formatter preset

    // model
    getData : function()
    {
      if (this.dummy) return "";
      return this._data;
    },
    getDataForEdit : function()
    {
      if (this.dummy) return "";
      return this.getData();
    },
    setData : function( data )
    {
      this._data = data;
      this._compiled = false;
      this._wakaTree = this.desk.wf.buildTree( this._data, this.preset );
      this.siblings = [ this ]; // no siblings for now
    },
    setTree : function( tree )
    {
      this._data = "[to be supplied.]";
      this._compiled = false;
      this._wakaTree = tree;
      this.siblings = [ this ];
    },
    getHtml : function()
    {
      if (!this._compiled) this._buildHtml();
      return this._html;
    },
    _buildHtml : function()
    {
      this._html = this.desk.wf.formatTree(this._wakaTree);
      this._compiled = true;
    },
    bindWakaTree : function( subTree )
    {
      if (subTree === this.undef())
      {
        this.rebindWrapper();
        subTree = this._wakaTree;
        if (this._data._tree !== this.undef())
          this.bindWakaTree( this._data._tree );
      }
      // 2. bind childs
      for (var i in subTree) 
      {
        if (subTree[i]._editable)
          subTree[i]._editable.bindWakaTree();
        else
          this.bindWakaTree( subTree[i]._tree, "noDataTree" );
      }
    },

    // read only stuff
    setReadonly : function( value )
    {
      this._readOnly = value;
      this._setReadonly( value );
      this._setReadonlyTree( this._wakaTree, value );
    },
    _setReadonlyTree : function( subTree, value )
    {
      if (subTree === this.undef()) return;
      for (var i in subTree)
      {
        if (subTree[i]._editable) subTree[i]._editable.setReadonly( value );
        this._setReadonlyTree( subTree[i]._tree, value );
      }
    },
    _setReadonly : function( value ) { },
    //

    
    remove : function()
    {
      this.dummy = true;
      if (!this.wrapper) alert("no wrapper!");
      
      var selector = document.getElementById( this.id + "_selector" );
      if (selector) selector.style.display     = "none";
      else          this.wrapper.style.display = "none";
    },
    removeIfCompleted : function()
    { 
      this._removeIfCompletedSubtree( this._wakaTree );
    },
    _removeIfCompletedSubtree : function( tree )
    {
      for (var i=0; i<tree.length; i++)
      {
        if (tree[i]._editable) tree[i]._editable.removeIfCompleted();
        this._removeIfCompletedSubtree( tree[i]._tree );
      }
    },

    // view
    drawWrapper : function()
    {
      this.wrapper = document.createElement("div");
      this.wrapper.id = this.id + "_wrapper";
      this.wrapper._editable = this;

      return this.wrapper;
    },
    buildWrapper : function( wrapperContent )
    { 
      return (this._data._leadingBr?"<br />":"")+
             "<div class='wrapper-' onclick='this._editable.onWrapperClick();' "+
                 " id='"+this.id + "_wrapper'>"+wrapperContent+"</div>";
    },
    rebindWrapper : function()
    {
      this.wrapper = document.getElementById(this.id + "_wrapper");
      this.wrapper._editable = this;
      return this.wrapper;
    },
    buildViewMode : function()
    {
      var html = this.getHtml();
      html = '<div >'+ html+'</div>';
      return html;

    },
    defaultColor : "#000000", // default properties of <textarea>
    defaultText  : "",
    buildEditMode : function()
    {
      var height =  this._textareaHeight;
      if (this.wrapper)
        if (this.wrapper.offsetHeight > this._textareaHeight)
          height = this.wrapper.offsetHeight;

      var html = '<div id="'+this.id+'_hook"></div>'+
                 '<textarea name="'+this.id+'_data" id="'+this.id+'_ta" style="color:'+this.defaultColor+';height:'+height+'px" '+
                      ' onclick="this._editable.desk.skipNextOnClick();" class="textarea-" '+
                      ' onfocus="this._editable.onTextareaFocus();" '+
                      ' onblur ="this._editable.onTextareaBlur();" '+
                      '>'+this.defaultText+
                 '</textarea>';
      return html;
    },
    drawViewMode : function()
    {
      if (!this.wrapper) 
      {
        alert( "no wrapper" );
        return;
      }
      this.wrapper.innerHTML = this.buildViewMode();
      this.bindWakaTree();
    },
    drawEditMode : function()
    {
      if (!this.wrapper) 
      {
        alert( "no wrapper" );
        return;
      }
      // 1. html
      this.wrapper.innerHTML = this.buildEditMode();
      // 2. bindings
      this._bindEditMode();

      // WOW. there is TWO lines with "this.t.focus". They are launched one after another.
      // but if you remove any one of them, textarea will not receive a focus
      this.t.focus(); 
    },

    _bindEditMode : function()
    {
      this.inplace = new MozillaInplace( this.id+"_ta", this.id+"_hook" );
      this.t = document.getElementById( this.id+"_ta" );
      this.t.value = this.getDataForEdit();
      this.t._editable = this;
      this._resizeArea();

      if (this.inplace.isMZ)
      {
        this.t.addEventListener("keypress", function(ev) { this._editable.onKeyPress(ev) }, true);
        this.t.addEventListener("keyup",    function(ev) { this._editable.onKeyUp(ev) }, true);
      }
      else
      {
        this.t.onkeyup    = function() { this._editable.onKeyUp(event); this._editable.onKeyPress(event) };
      }
      // wikiedit
      this.wikiedit = new WikiEdit();
      this.wikiedit._editable = this;
      this.wikiedit.hideToolbar = true; 
      this.wikiedit.init(this.id+'_ta', "", "", "wikiedit/"); // !!!! todo: abstract from path
    },

    _textareaHeight : 50,
    textareaHeight : 50,
    _resizeArea : function ()
    {
      var height;
      var text_height = this.inplace.getHeight()  + 20;

      height = text_height;
      if (text_height < this.textareaHeight) height = this.textareaHeight;

      this.t.style.height = height + "px";
    },

    importDataFromEditMode : function()
    {
      if (!this.wrapper) return;
      return document.getElementById( this.id+"_ta" ).value;
    },


    // controller
    selectionExpireTimeout : 10000,
    doSelect : function()
    {
      if (!this.wrapper) alert ("nowrapper!");
      if (this._readOnly) return;

      var selector = document.getElementById( this.id + "_selector" );
      if (selector) selector.className = selector.className.replace(/selector-$/,"selector-selected-");
      else          this.wrapper.className = 'wrapper-selected-';

      this.desk.selectedEditable = this;

      window.clearTimeout( this.expireTimeout );
      this.expireTimeout = window.setTimeout( "var d=document.getElementById('"+this.id+"_wrapper'); if (d) d._editable.doDeselect();",
                                              this.selectionExpireTimeout );
    },
    doDeselect : function()
    {
      if (!this.wrapper) alert ("nowrapper!");
      if (this._editMode) return;

      var selector = document.getElementById( this.id + "_selector" );
      if (selector) selector.className = selector.className.replace(/-(selected-)+$/,"-");
      else          this.wrapper.className = 'wrapper-';
   
      if (this.desk.selectedEditable == this) this.desk.selectedEditable = false;
    },


    _editMode : false,
    doEdit : function()
    {
      if (this._readOnly) return;
      if (this.desk.currentEditable)
        this.desk.currentEditable.doSave();

      this.desk.currentEditable = this;
      if (!this.desk.editAllMode) this.desk.wrapper.hideEditAllFacility();

      // do not expire selection if start editing
      window.clearTimeout( this.expireTimeout );

      this._editMode = true;
      this.drawEditMode();

      // next line is kinda bizarre. Look above about this, near another "this.t.focus" line
      this.t.focus();
    },
    doSave : function()
    {
      if (!this._editMode) return;
      if (this.desk.editAllMode) return this.desk.doSaveAll();
      this._editMode = false;
      this.setData( this.importDataFromEditMode() );

      if (this._needRebuildHierarchy())
      {
        this.desk.currentEditable = false;
        this.desk.buildFromScratch( this.desk.prepareDataForEdit() );
        this.desk.doInitView();
        this.desk.doViewAll();
      }
      else
      {
        this.drawViewMode();
        this.desk.currentEditable = false;
      }

      if (!this.dontSave) this.desk.save();
      this.doDeselect();
      this.desk.wrapper.showEditAllFacility();
    },
    doView : function()
    {
      if (this.desk.editAllMode) return this.desk.doCancelAll();

      this.desk.currentEditable = false;
      this._editMode = false;
      this.drawViewMode();
      this.desk.wrapper.showEditAllFacility();
    },
    _needRebuildHierarchy : function()
    { return false; },

    // event handlers
    _timeout : false,
    _timeoutDuration : 100,
    onKeyPress : function ( e )
    {
      if (!this._editMode) return;
      if (this._timeout) window.clearTimeout( this._timeout );
      this._timeout = window.setTimeout( "if (document.getElementById('"+this.id+"_ta')) document.getElementById('"+this.id+"_ta')._editable.onTimeout()", this._timeoutDuration );
    },
    onKeyUp : function ( e ) { },
    onTimeout : function()
    {
      if (!this._editMode) return;
      this._resizeArea();
      if (this._timeout) window.clearTimeout( this._timeout );
      this._timeout = window.setTimeout( "if (document.getElementById('"+this.id+"_ta')) document.getElementById('"+this.id+"_ta')._editable.onTimeout()", this._timeoutDuration );
    },
    onTextareaFocus : function () { },
    onTextareaBlur  : function () { },

    onWrapperClick  : function (event)
    {
      if (this.desk.skipClickSequence) return;

      // if clicked on an empty editable
      if (this.desk.selectedEditable == this)
        if ((this._data === "") || ((this._data.inner != this.undef()) && (this._data.inner === "")))
        {
          this.onContentClick(event);
          this.desk._skipNextOnClick = true;
          this.desk.skipClickSequence = true;
          return;
        }
      
      this.desk.skipClickSequence = true;

      if (this.desk.selectedEditable)
        this.desk.selectedEditable.doDeselect();
      this.doSelect();
    },
    onContentClick : function(event)
    {
      if (this.desk.skipClickSequence) return;

      if (!this._editMode && (this.desk.selectedEditable == this))
        this.doEdit();
    },

    onRemove : function()
    {
      // hack to evade popping "javascript:;" window
      deskDoWrapper.prototype._surfaceClickReturnFalse = true;
      this.desk.skipClickSequence = true;

      if (confirm("Remove this task?"))
      {
        this.remove();
        this.desk.save();
      }
      return false;
    },



    // NOT USED YET
    // storage helpers
    serializeData : function()
    {
      return this.getData();
    },
    deserializeData : function( serialized )
    {
      this.setData( this._deserializeData(serialized) );
    },
    _deserializeData : function( serialized )
    {
      return serialized;
    },


    // simple function to end the class definition.
    undef : function( param ) { return param; }


}




