/**
 * Error handling global setup
 */
var errorObjs = [];
var removeErrors = function( slider, idx ) {
  errElem = slider.getErrorElement();
  if ( errElem ) { errElem.removeClassName( "error-highlight" ); }
  slider.destroy();
  errorObjs[idx] = null;
}

var ErrorSlider = Class.create({
  /**
   * Constructor
   * @param string position The position for the slider message. top or bottom.
   * @param string errId The element that caused the error.
   * @param boolean callActivate Indicates whether activate() should be called
   *                             on the error element.
   * @param string msg The error message.
   * @param string delContainer The location to place the error message after
   *                            the ErrorSlider is destroyed.
   */
  initialize: function( position, errId, callActivate, msg, delContainer ) {
    this.position = "top"; //position == "top" ? "top" : "bottom";
    this.errElem = $( errId );
    this.activateElem = callActivate;
    this.msg = msg;
    this.msgContainer = $( delContainer );
    this.fauxElem = null;
    this.dynamicError = null;
    this.fadeTimer = null;
    if ( this.msgContainer ) { this.msgContainer.update( "&nbsp;" ); }
  },
  
  /**
   * Returns the extended error element.
   */
  getErrorElement: function() {
    return this.errElem;
  },
  
  /**
   * Display the error, and setup the event handling and fade out.
   */
  displayError: function() {
    if ( this.activateElem ) {
      this.errElem.activate();
    }
    
    this.errElem.addClassName( "error-highlight" );
    
    var yLoc = this.errElem.cumulativeOffset();
    yLoc = yLoc[1];
    
    if ( this.position == "top" ) {
      yLoc = yLoc - 100;
    } else {
      yLoc = yLoc + 100;
    }
    
    $( document.body ).insert( { top: '<div id="faux-element"></div>' } );
    this.fauxElem = $( "faux-element" );
    this.fauxElem.setStyle({
      position: "absolute",
      top: yLoc + "px",
      left: "0"
    });
    this.fauxElem.scrollTo();
    
    $( document.body ).insert({
      top: '<div id="dynamic-error"><div id="dynamic-error-wrapper"><div>' +
           this.msg + '</div></div></div>'
    });
    this.dynamicError = $( "dynamic-error" );
    
    if ( this.position == "top" ) {
      var yLoc = this.fauxElem.cumulativeScrollOffset();
      
      this.dynamicError.setStyle({
        position: "absolute",
        top: ( yLoc[1] - 3 ) + "px",
        left: "0"
      });
      
      new Effect.SlideDown(
        this.dynamicError,
        {
          duration: .5,
          transition: Effect.Transitions.linear,
          beforeStart: function() {
            if ( this.msgContainer ) {
              this.msgContainer.update();
            }
          },
          afterFinish: function() {
            this.fadeTimer = setTimeout( this.fadeAndUpdate.bind( this ), 5000 );
          }.bind( this )
        }
      );
    }
    
    setTimeout( this._cancelOnScroll.bind( this ), 500 );
  },
  
  /**
   * Fade out the sliding error, and update the message container if provided.
   * Then destroy the faux and error elements.
   */
  fadeAndUpdate: function() {
    if ( this.msgContainer ) {
      this.msgContainer.update();
    }
    if ( this.dynamicError ) {
      new Effect.Fade(
        this.dynamicError,
        {
          afterFinish: function() {
            this.destroy();
          }.bind( this )
        }
      );
    }
  },
  
  /**
   * Clear out the fade timer, and destroy the faux and error elements.
   */
  destroy: function() {
    this.cancelTimer();
    if ( this.fauxElem ) {
      this.fauxElem.remove();
      this.fauxElem = null;
    }
    if ( this.dynamicError ) {
      this.dynamicError.remove();
      this.dynamicError = null;
    }
    if ( this.msgContainer ) {
      this.msgContainer.update( this.msg );
    }
  },
  
  cancelTimer: function() {
    if ( this.fadeTimer ) { clearTimeout( this.fadeTimer ); }
  },
  
  /**
   * Destroy the effect if the page is scrolled.
   */
  _cancelOnScroll: function() {
    Event.observe( window, "scroll", this.destroy.bind( this ) );
  }
});

var CharacterCounter = Class.create({
  /**
   * Constructor
   * @param string The id of the element to be counted.
   * @param string The id of the element to display the current character count.
   */
  initialize: function( elemId, displayId ) {
    this.elem = $( elemId );
    this.display = $( displayId );
    this.displayChars();
  },
  
  /**
   * Observe the keyup event, and update the display area with the current
   * total of characters.
   */
  displayChars: function() {
    Event.observe(
      this.elem,
      'keyup',
      function() {
        this.display.update( $F( this.elem ).length + " characters" );
      }.bindAsEventListener( this )
    );
  }
});
