/**
* @class AddAnother
* Add another field implementation
* @constructor
*
*
*
*
* Creates the following markup :
*   <div class='add-another'>
*       <input type='text' id='' name='$name' class='add-another-item' value='$value' />
*       <span class='add-another-remove'></span>
*   </div>
*/

function AddAnother ( container, maxlength ) {
    this.container = YAHOO.util.Dom.get( container );
    this.maxlength = maxlength || 10;
    
    this.currentInputCount = 0;
    this._setup();
}

AddAnother.counter = 1;

AddAnother.prototype = {
    
    /* Static variables */
    ITEM_CLASS_NAME : 'add-another-item',
    CONT_CLASS_NAME : 'add-another',
    DEL_CLASS_NAME  : 'add-another-remove',
    
    _setup : function () {
        var S = YAHOO.util.Selector;

        var elements = S.query( 'div.add-another', this.container );

        AddAnother.counter = elements.length;
        this.currentInputCount = elements.length;
    },

    add : function ( attr ) {
        var ctr = ++AddAnother.counter;

        if ( this.currentInputCount >= this.maxlength ) {
            return this;
        }

        var element = this.createNamedElement( attr.type, attr.name );
        element.setAttribute( 'type', 'text' );

        YAHOO.util.Dom.addClass( element, this.ITEM_CLASS_NAME );

        //delete name and type from 'attr'
        delete attr.type;
        delete attr.name;
        
        for ( var key in attr ) {
            element.setAttribute( key, attr[key] );
        }

        this.lastElement = element;
        
        //create container div
        var cont = document.createElement( 'div' );
        cont.className = 'add-another';
        cont.id = 'add-another-cont-' + ctr;
        
        //create remove indicator span
        var span = document.createElement( 'span' );
        span.className = 'add-another-remove';
        span.innerHTML = 'X';
        span.setAttribute( 'title', 'Remove' );

        span.id = 'remove-span-' + ctr;

        YAHOO.util.Event.on( span.id, 'click', this.remove, cont.id, this );

        cont.appendChild( element );
        cont.appendChild( span );

        this.container.appendChild( cont );

        this.currentInputCount++;

        return this;
    },
    
    addClass : function ( class_name ) {
        YAHOO.util.Dom.addClass( this.lastElement, class_name );
        return this;
    },
    
    setStyle : function ( prop, value ) {
        YAHOO.util.Dom.setStyle( this.lastElement, prop, value );
        return this;
    },
    
    on : function ( type, fn, scope, data ) {
        YAHOO.util.Event.on( this.lastElement, type, fn, data, scope );
        return this;
    },

    getEl : function () {
        return this.lastElement;
    },
    
    remove : function ( e, id ) {
        YAHOO.util.Event.removeListener( YAHOO.util.Event.getTarget( e ).id, 'click', arguments.callee );

        var el = YAHOO.util.Dom.get( id );
        el.parentNode.removeChild( el );

        this.currentInputCount--;
    },

    createNamedElement : function ( type, name ) {
        var element = null;

        // try IE way where IE doesn't add 'name' attribute to dynamically created form elements
        try {
            element = document.createElement( '<' + type + ' name="' + name + '">' );
        }catch (e) { }

        // standard way
        if ( !element ) {
            element = document.createElement( type );
            element.setAttribute( 'name', name );
        }

        return element;
    }
}




/**
* @class ErrorTip
* Displays error tip
* @constructor
*/
var ErrorTip = function () {
    
    /**
    * @property error_tip_el
    * reference to error HTML element
    */
    var error_tip_el,

    /**
    * @property anim
    * Stores animation object
    */
    anim,
    
    /**
    * @property isIE
    * Internet Explorer check
    */
    isIE = YAHOO.env.ua.ie,

    /**
    * @Private
    * Resets the opacity of the HTML element
    * @return {void}
    */
    resetOpacity = function () {
        YAHOO.util.Dom.setStyle( error_tip_el, 'opacity', '0' );
    };

    YAHOO.util.Event.onDOMReady( function () {
        // get the element
        error_tip_el = YAHOO.util.Dom.get( 'error_tip' );
        
        //reset opacity
        if( !isIE ) resetOpacity();

        // initialize animation
        anim = new YAHOO.util.Anim( error_tip_el, { opacity : { to : 1 } }, 0.5 );
        YAHOO.util.Event.on(error_tip_el, 'click', ErrorTip.hide, null, ErrorTip);
    });

    
    return {
        
        /**
        * Shows the Tip, beside the particular element
        * @param {String|HTMLElement} el
        * @param {String} text
        * @return {void}
        */
        show : function ( el, text ) {
            el = YAHOO.util.Dom.get( el );

            // get coords
            var xy = YAHOO.util.Dom.getXY( el ),
                body = YAHOO.util.Selector.query( "div.tip-body p", error_tip_el, true);

            if( body ) {
                body.innerHTML = text;
            } 
            
            YAHOO.util.Dom.setStyle( error_tip_el, "display", "block" );

            //calculate position
            xy[0] = xy[0] + el.offsetWidth + 10;
            xy[1] = xy[1] - 15;
            
            YAHOO.util.Dom.setXY( error_tip_el, xy ); 
            
            //start animate
            if( !isIE ) anim.animate();

            el.focus();
            el.scrollIntoView();

            return false;
        },
        
        /**
        * Hides the tip
        * @return {void}
        */
        hide : function () {
            YAHOO.util.Dom.setStyle( error_tip_el, "display", "none" );
            if( !isIE ) resetOpacity();

            return true;
        }
    };


}();






function ImageOptionGroup( container, tipEl ) {
    this.container = YAHOO.util.Dom.get( container );

    this.anchors = YAHOO.util.Selector.query( 'a', this.container );

    this.tipEl = YAHOO.util.Dom.get( tipEl );

    this.ie = YAHOO.env.ua.ie;
    
    if( !this.ie ) this.resetOpacity();

    this.anim = new YAHOO.util.Anim( this.tipEl, { opacity : { to : 1 } }, 0.5 );
    
    MouseEvent.on( this.anchors, 'mouseenter', this.showTip, this, true);
    MouseEvent.on( this.anchors, 'mouseleave', this.hideTip, this, true);
    YAHOO.util.Event.on( this.anchors, 'click', this.handleClick, this, true );

    // import block header element
    this.header = YAHOO.util.Selector.query( '#import_contacts .import-step-two .import-section-title', null, true );

    //select the first element
    this.selectEl( this.anchors[0] );    
}

ImageOptionGroup.prototype.resetOpacity = function () {
    YAHOO.util.Dom.setStyle( this.tipEl, 'opacity', '0' );
}

ImageOptionGroup.prototype.showTip = function ( e ) {
    var el = YAHOO.util.Event.getTarget( e );
    
    // get coords
    var xy = YAHOO.util.Dom.getXY( el ),
        body = YAHOO.util.Selector.query( "div.tip-body p", this.tipEl, true);

    if( body ) {
        var txt = this.getText( el );

        if ( !txt ) {
            return;
        }

        body.innerHTML = txt;
    } 
    
    YAHOO.util.Dom.setStyle( this.tipEl, "display", "block" );

    //calculate position
    xy[0] = xy[0] - Math.floor( this.tipEl.offsetWidth / 2 ) + Math.floor( el.offsetWidth / 2 );
    xy[1] = xy[1] + el.offsetHeight;
    
    YAHOO.util.Dom.setXY( this.tipEl, xy ); 
    
    if ( !this.ie ) {
        //start animate
        this.anim.animate();
    }
}

ImageOptionGroup.prototype.getText = function ( el ) {
    var cls = el.className;
    
    var msg;

    switch ( cls.toLowerCase() ) {
        case 'gtalk':
            msg = 'Import from GTalk';
            break;
        case 'yahoo':
            msg = 'Import from YAHOO!';
            break;
        case 'msn':
            msg = 'Import from MSN';
            break;
        case 'aim':
            msg = 'Import from AIM';
            break;
        case 'plaxo':
            msg = 'Import from Plaxo';
            break;
        case 'outlook':
            msg = 'Import CSV';
    }

    return msg;
}

ImageOptionGroup.prototype.hideTip = function ( el ) {
    YAHOO.util.Dom.setStyle( this.tipEl, "display", "none" );
    
    if ( !this.ie ) this.resetOpacity();
}

ImageOptionGroup.prototype.handleClick = function ( e ) {
    YAHOO.util.Event.stopEvent( e );

    var el = YAHOO.util.Event.getTarget( e );

    if ( el.tagName.toLowerCase() !== 'a' ) {
        el = YAHOO.util.Dom.getAncestorByTagName( el, 'a' );
    }
    
    this.selectEl( el );
}


ImageOptionGroup.prototype.selectEl = function ( el ) {
    var cls = el.className;

    if ( this.selected ) {
        YAHOO.util.Dom.setStyle( this.selected, 'display', 'none' );
        if ( this.selectedImg ) {
            YAHOO.util.Dom.setStyle( this.selectedImg, 'background', '#fff' );
        }      
    }

    YAHOO.util.Dom.setStyle( cls + '-import', 'display', 'block' );
    YAHOO.util.Dom.setStyle( el, 'cssText', 'background: url(/ab/images/line_top.gif) no-repeat center 0;' );
    this.selected = cls + '-import';
    this.selectedImg = el;

    this.header.innerHTML = this.getText( el );
}











/**
 * @class MouseEvent
 * Implemented some special MouseEvent a.k.a 'mouseenter' and 'mouseleave' event for non-IE browsers
 * this is definitely not a perfect solution as it requires 2 method calls but it certainly does the right thing.
 * No Event Delegation possible in this scenario as these two events don't bubble
 * 
 * @static
 * @module
 */    
var MouseEvent = function () {
    
    /**
    * Method checks for whether a given node is a child of another node
    * @param {HTMLElement} _paren - Possible parent node
    * @param {HTMLElement} _child - Possible child node
    * @return {Boolean}
    */
    var isChildNode = function (_paren, _child) {
        if(_paren === _child) { return false; }

        while (_child && _child !== _paren && _child !== document.body) {
            _child = _child.parentNode;
        }

        return (_child === _paren);
    };

    return {

        /**
        * Method adds the specified events with the element, uses YAHOO.util.Event under the hood 
        * to achieve the desired result.
        * @public
        * @param {String|HTMLElement|Array} el
        * @param {String} sType
        * @param {Function} fn
        * @param {Object} obj
        * @param {Object|Boolean} override
        *
        * @return {void}
        */
        on : function (el, sType, fn, obj, override) {
            // IE already support this, so if IE then use normal way
            if (YAHOO.env.ua.ie) {
                YAHOO.util.Event.on(el, sType, fn, obj, override);
                return;
            }

            // for other browsers
            switch (sType.toLowerCase()) {
                case 'mouseenter':
                    YAHOO.util.Event.on(el, 'mouseover', this._bind(fn, obj, override, 'mouseenter'));
                    break;
                case 'mouseleave':
                    YAHOO.util.Event.on(el, 'mouseout', this._bind(fn, obj, override, 'mouseleave'));
                    break;                
            }
        },
        
        /**
        * Method used to act as a wrapper for the original event handler, actually handles the event 
        * and checks for proper conditions if true then delegates the call to the specified handler
        *
        * @public
        * @param {String|HTMLElement|Array} el
        * @param {String} sType
        * @param {Function} fn
        * @param {Object} obj
        * @param {Object|Boolean} override
        *
        * @return {void}
        */
        _bind : function (fn, obj, override, type) {
            
           return function (e) {
               var relTarg = YAHOO.util.Event.getRelatedTarget(e);

               //check whether the related target is a child node of the target node
               if (relTarg === this || isChildNode(this, relTarg)) { return; }

               //convert the arguments array into a proper array
               args = Array.prototype.slice.call(arguments);

               //add event type as the last argument to the handler
               args.push(type);

               if (override) {
                   fn.apply(obj || this, args);
               }else {
                   fn.apply(this, args);
               }                       
           }
        }
    };
}();
// ---------------- End MouseEvent -----------------






/**
* @class Wait
*/
var Wait = function () {
    
    var wait_dlg = new YAHOO.widget.Panel( 'wait-please', 
        { width: '280px',
          fixedcenter : true,
          modal : true,
          close : false,
          draggable : false,
          visible : false
        } 
    );

    wait_dlg.setHeader( '' );
    wait_dlg.setBody( 'Loading, please wait... &nbsp;&nbsp;<img id="wait-spinner" src="/ab/images/wait.gif" />' ); 

    YAHOO.util.Event.onDOMReady( function () { wait_dlg.render( document.body ); } );

    return {
        
        show : function ( txt ) {
            if ( txt ) {
                wait_dlg.setBody( txt + ' &nbsp;&nbsp;<img id="wait-spinner" src="/ab/images/wait.gif" />' ); 
            }

            wait_dlg.show();
        },
        
        hide : function () {
            wait_dlg.hide();
        }
    }

}();




/**
* Function to show Addresbook Import status box
* @param {Object} stats
* @return {void}
*/
function abImportStatsBox( stats ) {
    var merged = stats.merged,
            total  = stats.total,
            felix  = stats.felix;
    
    var olay = new YAHOO.widget.Overlay('fetch_results', {
                                                       fixedcenter: true,                                                           
                                                       constraintviewport : true,
                                                       visible : true,
                                                       modal : true,
                                                       width : "auto",
                                                       zIndex : 1000 });
       
   // main container
   var div = document.createElement( 'div' );
   div.className = 'fetch_results_inner';

   domBuilder( div )
       .div().addClass( 'addr_results_cont' )
           .div().addClass( 'fetch_header' ).text( 'Adressbook Import Status' ).end()
           .div().addClass( 'fetch_body' )
               .div().addClass( 'stats-container' )
                    .h5().text( 'Summary' ).end()
                   .ul()
                       .li().text( 'Total contact' + ( total > 0 ? 's' : '' ) + ' fetched = <strong>' + total + '</strong>' ).end()
                       .li().text( merged > 0 ? 'Duplicates removed = <strong>' + merged + '</strong>' : 'No duplicates found' ).end()
                       .li( { style : 'display:' + ( felix > 0 ? 'block' : 'none' ) } )
                           .text( felix > 0 ? 'Fetched contacts who are already Address Bee users = <strong>' + felix + '</strong>' : '&nbsp;' ).end()
                    .end()
                .end()               
           .div().addClass( 'fetch_footer clearfix' )
               .img( { src : '/ab/images/close_box.gif', title : 'Close Box' } ).on( 'click', olay.hide, null, olay ).end()
               .append( document.createTextNode( ' ' ) ).end()
               .img( { src : '/ab/images/view_contacts.gif', title : 'View Contacts', style : 'float:left' } )
                   .on( 'click', function () { 
                                    window.location.href = '/addressbook';
                                } ).end()
    
   olay.setBody( div );

   olay.render( document.body );
}




/**
* Function to show Invitation success status box
* @param {Object} stats
* @return {void}
*/
function abInviteStatsBox( stats ) {
    var total  = stats.total,
        message  = stats.message;
    
    var olay = new YAHOO.widget.Overlay('invite_results', {
                                                       fixedcenter: true,                                                           
                                                       constraintviewport : true,
                                                       visible : true,
                                                       modal : true,
                                                       width : "auto",
                                                       zIndex : 1000 });
       
   // main container
   var div = document.createElement( 'div' );
   div.className = 'fetch_results_inner';

   domBuilder( div )
       .div().addClass( 'addr_results_cont' )
           .div().addClass( 'fetch_header' ).text( 'Invitation Status' ).end()
           .div().addClass( 'fetch_body' )
               .div().addClass( 'stats-container' )
                    .h5().text( 'Summary' ).end()
                   .ul()
                       .li().text( 'Total invite' + ( total > 0 ? 's' : '' ) + ' sent = <strong>' + total + '</strong>' ).end()
                   .end()
                   .p().text( message ).end() 
                .end()               
           .div().addClass( 'fetch_footer clearfix' )
               .img( { src : '/ab/images/close_box.gif', title : 'Close Box' } ).on( 'click', olay.hide, null, olay ).end()
           .end()
    
   olay.setBody( div );

   olay.render( document.body );
}




/**
* @class Placeholder
* Manages placeholder text in input text boxes, requires 'placeholder' attribute in the element
* @constructor
* @param {String|HTMLElement} container
*/
function Placeholder( container ) {
    this.container = YAHOO.util.Dom.get( container );
    this._setup();
}

/**
* @private
* Method sets up the class
* @return {void}
*/
Placeholder.prototype._setup = function (dontAddListener) {
    var inputs = YAHOO.util.Selector.query( 'input[type=text][placeholder]', this.container );
    
    var el;
    for ( var i = 0; el = inputs[i]; ++i ) {

        if ( this.isBlank( el ) && ( el !== document.activeElement ) ) {
            this.setValue( el, el.getAttribute( 'placeholder' ) );
            //remove 'focus' class if present
            this.removeClass( el, 'focus' );
        } else {
            this.addClass( el, 'focus' );
        }

        if ( !dontAddListener ) {
            YAHOO.util.Event.addBlurListener( el, this.blur, null, this );
            YAHOO.util.Event.addFocusListener( el, this.focus, null, this );
        }
    }

    this.inputs = inputs;
}

Placeholder.prototype.reset = function() {
    this._setup(true); //Don't add listener again
}

/**
* Blur event handler
* @param {Event} e
* @return {void}
*/
Placeholder.prototype.blur = function ( e ) {
    var t = YAHOO.util.Event.getTarget( e );

    if ( this.isBlank( t ) ) {
        this.setValue( t, t.getAttribute( 'placeholder' ) );
        this.removeClass( t );
    }
}

/**
* Focus event handler
* @param {Event} e
* @return {void}
*/
Placeholder.prototype.focus = function ( e ) {
    var t = YAHOO.util.Event.getTarget( e );
    var val = this.getValue( t );

    if ( this.compare( t.getAttribute( 'placeholder' ), val ) ) {
        this.setValue( t, '' );
    }

    this.addClass( t );
}

/**
* Adds the 'focus' class to the specified element
* @param {HTMLElement|String} el
* @return {void}
*/
Placeholder.prototype.addClass = function ( el ) {
    YAHOO.util.Dom.addClass( el, 'focus' );
}

/**
* Removes the 'focus' class to the specified element
* @param {HTMLElement|String} el
* @return {void}
*/
Placeholder.prototype.removeClass = function ( el ) {
    YAHOO.util.Dom.removeClass( el, 'focus' );
}

/**
* Compare the values passed
* @param {String} value1
* @param {String} value2
* @return {Boolean}
*/
Placeholder.prototype.compare = function ( value1, value2 ) {
    return ( value1 == value2 );
}

/**
* Checks whether the value of the specified field is blank or not
* @param {HTMLElement} el
* @return {Boolean}
*/
Placeholder.prototype.isBlank = function ( el ) {
    return YAHOO.lang.trim( el.value ).length == 0;
}

/**
* Returns the value of the specified textbox
* @param {HTMLELement} el
* @return {String}
*/
Placeholder.prototype.getValue = function ( el ) {
    return el.value;
}

/**
* Sets specified value to the textbox
* @param {HTMLElement} el
* @param {String} value
* @return {void}
*/
Placeholder.prototype.setValue = function ( el, value ) {
    el.value = value;
}

/**
* Clears the placeholder texts from the input boxes,
* this method normally gets called before to 'submit',
* so be careful when using this component reason is that not clearing
* placeholder values can cause these values to get submitted to server. It also
* accepts one single element for clearing.
*
* @param {String|HTMLElement} el
* @return {void}
*/
Placeholder.prototype.clear = function ( el ) {
    el = YAHOO.util.Dom.get( el );

    if ( el ) {
        if ( this.compare( el.getAttribute( 'placeholder' ), this.getValue( el ) ) ) {
            this.setValue( el, '' );
        }
    } else {
        
        for ( var i = 0, len = this.inputs.length; i < len; ++i ) {
            el = this.inputs[i];

            if ( this.compare( el.getAttribute( 'placeholder' ), this.getValue( el ) ) ) {
                this.setValue( el, '' );
            }
        }
    }
}
