YUI.add("inputex-inplaceedit", function(Y){

   var lang = Y.Lang;//, Event = YAHOO.util.Event, Dom = YAHOO.util.Dom, CSS_PREFIX = 'inputEx-InPlaceEdit-';

/**
 * Meta field providing in place editing (the editor appears when you click on the formatted value). 
 * @class inputEx.InPlaceEdit
 * @extends inputEx.Field
 * @constructor
 * @param {Object} options Added options:
 * <ul>
 *   <li>visu</li>
 *   <li>editorField</li>
 *   <li>animColors</li>
 * </ul>
 */
inputEx.InPlaceEdit = function(options) {
   inputEx.InPlaceEdit.superclass.constructor.call(this, options);
   this.publish('openEditor');
   this.publish('closeEditor');
};

lang.extend(inputEx.InPlaceEdit, inputEx.Field, {
   /**
    * Set the default values of the options
    * @param {Object} options Options object as passed to the constructor
    */
   setOptions: function(options) {
      inputEx.InPlaceEdit.superclass.setOptions.call(this, options);
      
      this.options.visu = options.visu;
      
      this.options.editorField = options.editorField;
      
      //this.options.buttonTypes = options.buttonTypes || {ok:"submit",cancel:"link"};
      
      this.options.buttonConfigs = options.buttonConfigs || [{
               type: "submit",
               value: inputEx.messages.okEditor,
               className: "inputEx-Button "+CSS_PREFIX+'OkButton',
               onClick: {fn: this.onOkEditor, scope:this}
            },{
               type: "link",
               value: inputEx.messages.cancelEditor,
               className: "inputEx-Button "+CSS_PREFIX+'CancelLink',
               onClick: {fn: this.onCancelEditor, scope:this}
            }];
      
      this.options.animColors = options.animColors || null;
   },  
   /**
    * Override renderComponent to create 2 divs: the visualization one, and the edit in place form
    */
   renderComponent: function() {
      this.renderVisuDiv();
     this.renderEditor();
   },
   
   /**
    * Render the editor
    */
   renderEditor: function() {
      
      this.editorContainer = inputEx.cn('div', {className: CSS_PREFIX+'editor'}, {display: 'none'});
      
      // Render the editor field
      this.editorField = inputEx(this.options.editorField,this);
      var editorFieldEl = this.editorField.getEl();
      
      this.editorContainer.appendChild( editorFieldEl );
      Y.one(editorFieldEl).addClass(CSS_PREFIX+'editorDiv');
      this.buttons = [];
      for (var i = 0; i < this.options.buttonConfigs.length ; i++){
        var config = this.options.buttonConfigs[i];
        config.parentEl = this.editorContainer;
        this.buttons.push(new inputEx.widget.Button(config));
      }
      
      // Line breaker ()
      this.editorContainer.appendChild( inputEx.cn('div',null, {clear: 'both'}) );
      
      this.fieldContainer.appendChild(this.editorContainer);
      
   },
   
   /**
    * Set the color when hovering the field
    * @param {Event} e The original mouseover event
    */
   onVisuMouseOver: function(e) {
      // to totally disable the visual effect on mouse enter, you should change css options inputEx-InPlaceEdit-visu:hover
      if(this.disabled) return;
      
      if(this.colorAnim) {
         this.colorAnim.stop(true);
      }
      inputEx.sn(this.formattedContainer, null, {backgroundColor: this.options.animColors.from });
   },
   
   /**
    * Start the color animation when hovering the field
    * @param {Event} e The original mouseout event
    */
   onVisuMouseOut: function(e) {
      var optionsAnim;
      if(this.disabled) return;
      
      // Start animation
      if(this.colorAnim) {
         this.colorAnim.stop(true);
      }
      if(!this.options.animColors) return;

      optionsAnim =  {
        node: Y.one(this.formattedContainer), 
      }
      if(this.options.animColors.from){
        optionsAnim.from = {
          backgroundColor : this.options.animColors.from
        }
      }
      if(this.options.animColors.from){
        optionsAnim.to = {
          backgroundColor : this.options.animColors.to
        }
      }
      this.colorAnim = new Y.Anim(optionsAnim);
      this.colorAnim.on("end",function() { 
        Y.one(this.formattedContainer).setStyle('background-color', ''); 
      });
      this.colorAnim.run();
      
   },
   
   /**
    * Create the div that will contain the visualization of the value
    */
   renderVisuDiv: function() {
      this.formattedContainer = inputEx.cn('div', {className: 'inputEx-InPlaceEdit-visu'});
      
      if( lang.isFunction(this.options.formatDom) ) {
         this.formattedContainer.appendChild( this.options.formatDom(this.options.value) );
      }
      else if( lang.isFunction(this.options.formatValue) ) {
         this.formattedContainer.innerHTML = this.options.formatValue(this.options.value);
      }
      else {
         this.formattedContainer.innerHTML = lang.isUndefined(this.options.value) ? inputEx.messages.emptyInPlaceEdit: this.options.value;
      }
      
      this.fieldContainer.appendChild(this.formattedContainer);
      
   },

   /**
    * Adds the events for the editor and color animations
    */
   initEvents: function() {  
      Y.one(this.formattedContainer).on("click", this.openEditor, this, true);
            
      // For color animation (if specified)
      if (this.options.animColors) {
         Y.one(this.formattedContainer).on('mouseover', this.onVisuMouseOver, this);
         Y.one(this.formattedContainer).on('mouseout', this.onVisuMouseOut, this);
      }
      
      if(this.editorField.el) {
         var that = this;
         // Register some listeners
         Y.on("key", function(){ that.onKeyUp },"#"+Y.one(this.editorField.el).get("id"),"up:");
         Y.on("key", function(){ that.onKeyDown },"#"+Y.one(this.editorField.el).get("id"),"down:" );
      }
   },
   
   /**
    * Handle some keys events to close the editor
    * @param {Event} e The original keyup event
    */
   onKeyUp: function(e) {
      // Enter
      if( e.keyCode == 13) {
         this.onOkEditor(e);
      }
      // Escape
      if( e.keyCode == 27) {
         this.onCancelEditor(e);
      }
   },
   
   /**
    * Handle the tabulation key to close the editor
    * @param {Event} e The original keydown event
    */
   onKeyDown: function(e) {
      // Tab
      if(e.keyCode == 9) {
         this.onOkEditor(e);
      }
   },
   
   /**
    * Validate the editor (ok button, enter key or tabulation key)
    */
   onOkEditor: function(e) {
      e.halt();
      
      var newValue = this.editorField.getValue();
      this.setValue(newValue);
      this.closeEditor();
      
      var that = this;
      setTimeout(function() {that.fire("updated",newValue);}, 50);      
   },

   
   /**
    * Close the editor on cancel (cancel button, blur event or escape key)
    * @param {Event} e The original event (click, blur or keydown)
    */
   onCancelEditor: function(e) {
      e.halt();
      this.closeEditor();
   },
   /**
    * Close the editor on cancel (cancel button, blur event or escape key)
    * @param {Event} e The original event (click, blur or keydown)
    */
   closeEditor: function() {
      this.editorContainer.style.display = 'none';
      this.formattedContainer.style.display = '';
      this.fire("closeEditor")
   },      
  /**
    * Override enable to Enable openEditor
    */
    enable: function(){
      this.disabled = false;
      inputEx.sn(this.formattedContainer, {className: 'inputEx-InPlaceEdit-visu'});
    },  
  /**
    * Override disable to Disable openEditor
    */   
    disable: function(){
      this.disabled = true;
      inputEx.sn(this.formattedContainer, {className: 'inputEx-InPlaceEdit-visu-disable'});
    },
   /**
    * Display the editor
    */
   openEditor: function() {
      if(this.disabled) return;
      var value = this.getValue();
      this.editorContainer.style.display = '';
      this.formattedContainer.style.display = 'none';
   
      if(!lang.isUndefined(value)) {
         this.editorField.setValue(value);   
      }
      
      // Set focus in the element !
      this.editorField.focus();
   
      // Select the content
      if(this.editorField.el && lang.isFunction(this.editorField.el.setSelectionRange) && (!!value && !!value.length)) {
         this.editorField.el.setSelectionRange(0,value.length);
      }
      this.fire("openEditor");
   },
   
   /**
    * Returned the previously stored value
    * @return {Any} The value of the subfield
    */
   getValue: function() {
      var editorOpened = (this.editorContainer.style.display == '');
     return editorOpened ? this.editorField.getValue() : this.value;
   },

   /**
    * Set the value and update the display
    * @param {Any} value The value to set
    * @param {boolean} [sendUpdatedEvt] (optional) Wether this setValue should fire the updatedEvt or not (default is true, pass false to NOT send the event)
    */
   setValue: function(value, sendUpdatedEvt) {   
      // Store the value
     this.value = value;
   
      if(lang.isUndefined(value) || value == "") {
         inputEx.renderVisu(this.options.visu, inputEx.messages.emptyInPlaceEdit, this.formattedContainer);
      }
      else {
         inputEx.renderVisu(this.options.visu, this.value, this.formattedContainer);
      }
      
      // If the editor is opened, update it 
      if(this.editorContainer.style.display == '') {
         this.editorField.setValue(value);
      }
      
      inputEx.InPlaceEdit.superclass.setValue.call(this, value, sendUpdatedEvt);
   },
   
   /**
    * Close the editor when calling the close function on this field
    */
   close: function() {
      this.editorContainer.style.display = 'none';
      this.formattedContainer.style.display = '';
      this.fire("openEditor");
  }

});
  
inputEx.messages.emptyInPlaceEdit = "(click to edit)";
inputEx.messages.cancelEditor = "cancel";
inputEx.messages.okEditor = "Ok";

// Register this class as "inplaceedit" type
inputEx.registerType("inplaceedit", inputEx.InPlaceEdit, [
   { type:'type', label: 'Editor', name: 'editorField'}
]);

}, '0.1.1', {
  requires:["anim","inputex-field","inputex-button"]
})
