(function() {


  // YUI Libraries
  var Dom           = YAHOO.util.Dom;
  var Event         = YAHOO.util.Event;
  var Lang          = YAHOO.lang;
  var $             = YAHOO.util.Selector.query;
  var CustomEvent   = YAHOO.util.CustomEvent;
  
  
  // TIME Libraries
  var XSSTransport = TIME.util.XSSTransport;
  
  
  
  /**
   * 
   *
   * @method CommentAppForm
   * @static
   * @param  {type} form  Parameter description
   * @param  {type} config  Parameter description
   */
  var CommentAppForm = function(form, config) {
        
    form = Dom.get(form);
    
    if (Lang.isNull(form)) {
      throw new Error('Unable to initialize CommentAppForm');
    }
    
    config = Lang.merge(CommentAppForm.config, config || {});
    
    this._init(form, config);
  };


  CommentAppForm.prototype = {
    
    /**
     * Handles initialization for the CommentAppForm
     *
     * @method _init
     * @static
     * @param  {type} form  Parameter description
     * @param  {type} config  Parameter description
     */
    _init: function(form, config) {

      this.form = form;
      this.config = config;

      this._inputs = $('input, textarea', form);
      this._errors = $('div.form-errors', form, true);      

      this._alerted = false;
      
      this._initEvents();
      this._initCustomEvents();
      this._initMaxLengthCounter();
    },
    
    
    /**
     * 
     *
     * @method _initEvents
     * @static
     */
    _initEvents: function() {
      Event.on(this.form, 'submit', this._handleSubmit, this, true);
      Event.on(this.form, 'reset',  this._handleReset,  this, true);
    },
    
    
    /**
     * 
     *
     * @method _initCustomEvents
     * @static
     */
    _initCustomEvents: function() {
      this.onSubmit  = new CustomEvent('onSubmit',  this, true, CustomEvent.FLAT);
      this.onCancel  = new CustomEvent('onCancel',  this, true, CustomEvent.FLAT);
      this.onSuccess = new CustomEvent('onSuccess', this, true, CustomEvent.FLAT);
      this.onError   = new CustomEvent('onError',   this, true, CustomEvent.FLAT);
      this.onFailure = new CustomEvent('onFailure', this, true, CustomEvent.FLAT);
    },
    
    
    /**
     * 
     *
     * @method _initMaxLengthCounter
     * @static
     */
    _initMaxLengthCounter: function() {
      
      this._commentBodyInput  = $('textarea', this.form, true);
      this._commentBodyStatus = $('div.body-status', this.form, true);
      this._commentBodyCount  = $('span.body-count', this.form, true);
      this._commentBodyError  = $('span.body-error', this.form, true);

      this._commentBodyMaxLength = parseInt(this._commentBodyInput.getAttribute('maxlength'), 10);

      Event.on(this._commentBodyInput, 'keyup',  this._handleEditCommentBody,  this, true);
      Event.on(this._commentBodyInput, 'paste',  this._handleEditCommentBody,  this, true);
    },
    
    
    /**
     * 
     *
     * @method _handleEditCommentBody
     * @static
     * @param  {type} evt  Parameter description
     */
    _handleEditCommentBody: function(evt) {

      var input  = this._commentBodyInput;
      var status = this._commentBodyStatus;
      var count  = this._commentBodyCount;
      var error  = this._commentBodyError;

      var maxLength = this._commentBodyMaxLength;
      var commentLength = input.value.length;
      
      // Update counter
      count.innerHTML = Math.max(maxLength - commentLength, 0);

      // Comment exceeds maximum length
      if (commentLength > maxLength) {

        Dom.addClass(input, 'maxlength');

        // Only trigger the alert once using a class as a flag
        if (!this._alerted) {
          alert('Your comment may not exceed ' + maxLength + ' characters');
          this._alerted = true;
        }
        
        var diff = commentLength - maxLength;
        var s = (diff > 1) ? 's' : '';        
        error.innerHTML = ['&nbsp;/&nbsp;Limit exceeded by ', diff, ' character', s].join('');
        
      } else {
        
        Dom.removeClass(input, 'maxlength');
        error.innerHTML = '';
      }

    },


    /**
     * 
     *
     * @method _handleSubmit
     * @static
     * @param  {type} evt  Parameter description
     */
    _handleSubmit: function(evt) {

      Event.stopEvent(evt);

      var uri = this.form.action;
      var data = {};

      // Parse form data
      Dom.batch(this._inputs, function(input) {
        data[input.name] = input.value;
      });

      var callback = {

        // Handle success
        success: function(html) {      

          if (this.config.commentRegExp.test(html)) {
            this.onSuccess.fire(html);
            this.form.reset();
          } else {
            this._errors.innerHTML = html;
            this.onError.fire(html);
          }
        },

        // Handle failure
        failure: function(error) {
          this.onFailure.fire(error);
        }
      };

      // Execute XSS post
      XSSTransport.postRequest(uri, data, callback, this);
      
      this.onSubmit.fire(evt);
    },


    /**
     * Resets form elements, such as errors and maxlength counter,
     * and fires the onCancel event
     *
     * @method _handleReset
     * @static
     * @param  {type} evt  Parameter description
     */
    _handleReset: function(evt) {
      
      this._errors.innerHTML = '';
      
      Dom.removeClass(this._commentBodyInput, 'maxlength');
      this._commentBodyCount.innerHTML = this._commentBodyMaxLength;
      this._commentBodyError.innerHTML = '';
      
      this.onCancel.fire(evt);
    },
    
    
    /**
     * 
     *
     * @method destroy
     * @static
     */
    destroy: function() {

      // Remove event handlers
      Event.removeListener(this.form, 'submit', this._handleSubmit, this, true);
      Event.removeListener(this.form, 'reset',  this._handleReset,  this, true);
      Event.removeListener(this._commentBodyInput, 'keyup',  this._handleEditCommentBody);
      Event.removeListener(this._commentBodyInput, 'paste',  this._handleEditCommentBody);
      
      // TODO: Remove custom event handlers 
      
      
      this._inputs = null;
      delete this._inputs;

      this._errors = null;
      delete this._errors;

      this._commentBodyInput = null;
      delete this._commentBodyInput;
      
      this._commentBodyStatus = null;
      delete this._commentBodyStatus;
      
      this._commentBodyCount = null;
      delete this._commentBodyCount;
      
      this._commentBodyError = null;
      delete this._commentBodyError;      

      this.form = null;
      delete this.form;
    }
  };
  
  /**
   *  
   */
  CommentAppForm.config = {
    commentRegExp: /\<a name="?comment-(\d+)"?\>\<\/a\>/i
  };


  // Add CommentAppForm to TIME.widget namespace
  window.TIME = window.TIME || YAHOO.namespace('TIME');
  YAHOO.namespace('TIME.widget');
  TIME.widget.CommentAppForm = CommentAppForm;
  
  
})();
