/**
 * Class Fields
 *
 * Class to observe and interpret the objects returned in every request
 * To then be able to draw the form,
 * depending on the types of fields returned in every object
 */

TrueWizard.Fields = new TrueWizard.Class(function()
{
    /**
     * Class initializator
     * It takes as its parameter object json returned in the request
     * What travels and creates the appropriate fields
     *
     * @param  Object fields = object fields which draw
     * @return Object TrueWizard.Fields
     */
    this.init = function( fields )
    {
        this.output = [];

        for ( var i = 0, len = fields.length; i < len; i++ ) {
            if ( fields[ i ] instanceof Array ) {
                this.output.push( this.createGroup( fields[ i ] ) );
                this.output.push( TrueWizard.Create('div', {'class':'clear'}) );
            }
            else {
                this.output.push( this.createField( fields[ i ] ) );
            }
        }

        return this;
    };

    /**
     * Create a group of fields, which will be shown on the same line
     *
     * @param  Object groupFields = Object that contains the group of fields
     * @return HTMLElement ul
     */
    this.createGroup = function( groupFields )
    {
        var ul = TrueWizard.Create('ul', {'class':'fields'});

        for ( var i = 0; i < groupFields.length; i++ ) {

            var attr = { 'class' : 'medium' };

            if ( i == 0 ) {
                attr['class'] += ' first';
            }

            var li = TrueWizard.Create( 'li', attr );
                li.appendChild( this.createField( groupFields[ i ] ) );

            ul.appendChild( li );
        }

        return ul;
    };

    /**
     * Create a field from an object
     * depending on the type, creating the desired item
     *
     * @param  Object field = generic object that contains the specifications of the field type
     * @return HTMLElement fieldWrap
     */
    this.createField = function( field )
    {
        //console.dir( field );

        if ( field.label ) {
            var label = TrueWizard.Create( 'label', { 'for' : field.name, 'id' : 'lbl-' + field.name }, field.label );
        }

        var type  = null;
        var input = null;

        switch ( field.type ) {

            case TrueWizard.FIELD_TYPE_TEXT:
            case TrueWizard.FIELD_TYPE_EMAIL:
                type  = 'text';
            break;

            case TrueWizard.FIELD_TYPE_HIDDEN:
            case TrueWizard.FIELD_TYPE_IP:
                type  = 'hidden';
            break;

            case TrueWizard.FIELD_TYPE_RADIO:
                input = this.createOptionsRadio( field );
            break;

            case TrueWizard.FIELD_TYPE_CHECKBOX:
                type  = 'checkbox';
            break;

            case TrueWizard.FIELD_TYPE_SELECT:
                input = this.createSelect( field );
            break;

            case TrueWizard.FIELD_TYPE_CALENDAR:
            case TrueWizard.FIELD_TYPE_AGE:
                input = this.createDatePicker( field );
            break;

            case TrueWizard.FIELD_TYPE_PHONE:
                input = this.createInputPhone( field );
            break;
            
            case TrueWizard.FIELD_TYPE_TEXTAREA:
                input = this.createTextArea( field );
            break;
        }

        if ( null === input ) {
            var attributes = { 'name' : field.name, 'id': field.name, 'type' : type };

            if ( typeof field.value != 'undefined' ) {
                attributes.value = field.value;
            }

            if ( typeof field.max != 'undefined' ) {
                attributes.maxlength = field.max;
            }

            input = TrueWizard.Create( 'input', attributes );

            if ( typeof field.width != 'undefined' ) {
                input.style.width = field.width + 'px';
            }

            if ( field.accept && field.type == TrueWizard.FIELD_TYPE_TEXT ) {
                TrueWizard.$( input ).Accept( field.accept );
            }
        }

        var fieldClass = TrueWizard.getClassByType( field.type );
        var fieldWrap  = TrueWizard.Create('div', { 'class' : 'field ' + fieldClass } );

        if ( document.all ) {
            TrueWizard.$( fieldWrap ).addClass( 'IE' );
        }

        if ( input.nodeType ) {
            var div   = TrueWizard.Create( 'div' );
                div.appendChild( input );
        }

        if ( field.type == TrueWizard.FIELD_TYPE_CHECKBOX ) {
            fieldWrap.appendChild( div );
            fieldWrap.appendChild( label );
            fieldWrap.appendChild( TrueWizard.Create('div',{'class':'clear'}) );
        }

        else if ( input instanceof Array ) {
            for ( var i = 0, len = input.length; i < len; i++ ) {
                fieldWrap.appendChild( input[ i ] );
            }
        }

        else {
            if ( field.label ) {
                fieldWrap.appendChild( label );
            }
            fieldWrap.appendChild( div );
        }

        return fieldWrap;
    };

    /**
     * Create inputs of type "radio"
     * the group and stored in an array
     *
     * @param  Object field = properties of the field to create
     * @return Array inputs
     */

    this.createOptionsRadio = function( field )
    {
        var inputs = [];

        if ( field.items instanceof Object ) {
            for ( var key in field.items ) {

                var fieldWrap = TrueWizard.Create( 'div' );

                var attrs  = { 'type' : 'radio', 'id' : field.name + '_' + key, 'value' : key, 'name': field.name };

                if ( field.value == key ) {
                    attrs.checked = 'checked';
                }

                var option = TrueWizard.Create( 'input', attrs );
                var label  = TrueWizard.Create( 'label', { 'for' : field.name + '_' + key }, field.items[ key ] );

                fieldWrap.appendChild( option );
                fieldWrap.appendChild( label );
                fieldWrap.appendChild( TrueWizard.Create('div',{'class':'clear'})  );

                inputs.push( fieldWrap );
            }
        }

        return inputs;
    };

    /**
     * Create a field type <select>
     * Added that if the items are specified
     * and select a default if the property is defined "value"
     *
     * @param  Object field = generic object to the specifications of the field
     * @return HTMLElement select
     */
    this.createSelect = function( field )
    {
        var select = TrueWizard.Create( 'select', { 'name' : field.name, 'id' : field.name } );

        if ( typeof field.width != 'undefined' ) {
            select.style.width = field.width + 'px';
        }

        var i = 0;

        if ( !( 'value' in field ) ) {
            select.appendChild(
                TrueWizard.Create( 'option', { 'value' : -1 }, 'Select One' )
            );
        }

        if ( field.items instanceof Object && !( field.items instanceof Array ) ) {
            for ( var key in field.items ) {
                select.appendChild(
                    TrueWizard.Create( 'option', { 'value' : key }, field.items[ key ] )
                );

                if ( field.value == key ) {
                    select.selectedIndex = i;
                }
                i++;
            }
        }

        return select;
    };

    /**
     * Create a field type <textarea>
     *
     * @param  Object field = generic object to the specifications of the field
     * @return HTMLElement textarea
     */
    this.createTextArea = function( field )
    {
        return TrueWizard.Create( 'textarea', { 'name' : field.name, 'id' : field.name, 'rows' : 2 } );
    };

    /**
     * Create a field of type Phone
     * Three text fields on the same line, separating the second from third with a hyphen
     *
     * @param  Object field = generic object to the specifications of the field
     * @return Array
     */

    this.createInputPhone = function( field )
    {
        if ( !field.items ) {
            var items = [ null, 1, 2, 3 ];
        }
        else {
            var items = field.items;
                items.unshift( null );
        }

        var label  = Twd.Create('label', { 'id': 'lbl-' + field.name, 'for' : field.name + '-' + items[ 1 ] }, field.label );
        var ul     = Twd.Create('ul', {'class' : 'phones'});
        var maxLen = [ null, 3, 3, 4 ];

        for ( var i = 1, x = 1; i < 5; i++, x++ ) {
            var li = Twd.Create('li');
            if ( 3 == i ){

                var dash = Twd.Create('span', null, '-');

                if ( document.all ) {
                    Twd.$( dash ).addClass('IE');
                }
                li.appendChild( dash );
                x--;
            }
            else {

                var input = Twd.Create('input', { 'class' : 'phone' + x, 'name' : field.name + '-' + items[ x ], 'id' : field.name + '-' + items[ x ], 'maxlength' : maxLen[ x ], 'type' : 'text' });
                    input.field = field.type;

                if ( field.items ) {
                    input.items = field.items;
                }

                if ( field.accept ) {
                    Twd.$( input ).Accept( field.accept );
                }

                if ( x < 3 ) {
                    Twd.$( input ).addEvent('keyup', function()
                    {
                        if ( this.value().length == 3 ) {

                            var nextLi = this.parent().next();
                            var input  = nextLi.first().element;

                            if ( null != input && input.tagName.toLowerCase() == 'input' ) {
                                input.focus();
                            }
                            else {
                                input = nextLi.next().first().element;
                                if ( null != input && input.tagName.toLowerCase() == 'input' ) {
                                    input.focus();
                                }
                            }
                        }
                    });
                }

                li.appendChild( input );
            }
            ul.appendChild( li );
        }

        return [ label, ul ];
    };
    
    /**
     * Create a field for the selection of dates
     * three <select> elements are on the same line
     *
     * @param  Object field = generic object to the specifications of the field
     * @return Array
     */
    this.createDatePicker = function( field )
    {
        var formatNum = function( num )
        {
            if ( 0 != num && String( num ).length == 1 ) {
                return '0' + String( num );
            }

            return num;
        };

        field.dateFormat = field.dateFormat.replace(/yyyy/ig, 'Y').replace(/mm/ig, 'm').replace(/dd/ig, 'd');

        var first = field.dateFormat ? field.dateFormat.substr(0, 1) : '';

        var label = Twd.Create( 'label', { 'id' : 'lbl-' + field.name, 'for' : field.name + '-' + first }, field.label );
        var ul    = Twd.Create( 'ul', { 'class' : 'date' } );

        var months  = ['Month', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
        var selectm = Twd.Create( 'select', { 'id' : field.name + '-m', 'name' : field.name + '-m' } );
            selectm.field = field.type;

        for ( var i = 0, len = months.length; i < len; i++ ) {
            selectm.appendChild(
                Twd.Create( 'option', { 'value' : formatNum( i ) }, months[ i ] )
            );
        }

        var updateDays = function()
        {
            var year  = parseInt( Twd.$( selectY ).value() );
            var month = parseInt( Twd.$( selectm ).value() );

            var monthDayRelation = [ null, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; 

            if ( year > 0 && ( year % 4 == 0 ) && ( ( year % 100 != 0 ) || ( year % 400 == 0 ) ) ) {
                monthDayRelation[ 2 ] = 29;
            }

            if ( month > 0 ) {
                var savedIndex = selectd.selectedIndex;

                Twd.$( selectd ).empty(function( i )
                {
                    return i > 1;
                });

                for ( var i = 1; i <= monthDayRelation[ month ]; i++ ) {
                    selectd.appendChild(
                        Twd.Create( 'option', { 'value' : formatNum( i ) }, i )
                    );
                }

                try {
                    selectd.selectedIndex = savedIndex;
                }
                catch( e ) {
                    selectd.selectedIndex = 0;
                }
            }
        };

        Twd.$( selectm ).addEvent( 'change', updateDays );

        var selectd = Twd.Create('select', { 'id' : field.name + '-d', 'name' : field.name + '-d' });
            selectd.field = field.type;
            selectd.appendChild(
                Twd.Create( 'option', { 'value' : 0 }, 'Day' )
            );

        for ( var i = 1; i <= 31; i++) {
            selectd.appendChild(
                Twd.Create( 'option', { 'value' : formatNum( i ) }, i )
            );
        }

        var year    = (new Date()).getFullYear() + 1;
        var selectY = Twd.Create('select', { 'id' : field.name + '-Y', 'name' : field.name + '-Y' });
            selectY.field = field.type;
            selectY.appendChild( Twd.Create('option', {'value' : 0}, 'Year') );

        for ( var i = year; i >= ( year - 80 ); i-- ) {
            selectY.appendChild(
                Twd.Create( 'option', { 'value' : i }, i )
            );
        }

        Twd.$( selectY ).addEvent( 'change', updateDays );

        if ( field.dateFormat ) {

            var dateFormat = field.dateFormat.toLowerCase().split('');

            for ( var i = 0; i < dateFormat.length; i++ ){

                var li = Twd.Create('li');

                switch ( dateFormat[ i ] ) {
                    case 'd':
                        li.appendChild( selectd );
                    break;
                    case 'm':
                        li.appendChild( selectm );
                    break;
                    case 'y':
                        li.appendChild( selectY );
                    break;
                    default:
                        var l = Twd.$( li ).addClass('sep');
                        if ( document.all ) {
                            l.addClass('IE');
                        }
                        li.appendChild(
                            document.createTextNode( dateFormat[ i ] )
                        );
                    break;
                }
                ul.appendChild( li );
            }
        }

        return [ label, ul, Twd.Create('div', {'class' : 'clear'}) ];
    };

    /**
     * Add the fields generated to the form and returns
     *
     * @param  String formId = id of the form that will connect the fields
     * @return void
     */
    this.toForm = function( formId, empty )
    {
        var form = TrueWizard.$( formId );

        if ( empty ) {
            form.empty();
        }

        var errors = TrueWizard.$( 'step2-errors' ).element;

        if ( null != errors ) {
            errors.parentNode.removeChild( errors );
        }

        for ( var i = 0, len = this.output.length; i < len; i++ ){
            form.append( this.output[ i ] );
        }
    }
});