/**
 * @fileOverview Classes, functions for UI
 * 
 * @author Whl Member 
 */

/**
* @namespace Whl.Combo Contains functions, class for manipulating with combobox, listbox
*/
Whl.Combo = {};
/**
* Extend more functions for this namespace
*/
Object.extend(Whl.Combo, {
    /**
    * Append a list of functions for the combo control and return the current combo control
    * @memberOf Whl.Combo
    * @param {String} elmId Combo control id
    * @returns {DOM Element} Combo control
    */
    get: function(elmId) {
        var elm = Object.isString(elmId) ? document.getElementById(elmId) : elmId;
        if (!Object.isObject(elm)) return null;
        else if (Object.isFunction(elm.addItem)) return elm;
        Object.extend(elm, {
            /**
            * Add Item Option
            * @param {Object} item             Object contain text, value
            * @param {String} item.text        Text of the option
            * @param {String} item.value       Value of the option
            * @param {Boolean} item.selected   Item is selected or not
            * @returns {Dom Element} Combo Control
            */
            addItem: function(item) {
                if (Object.isUndefined(item.selected)) {
                    this.options.add(new Option(item.text, item.value));
                } else {
                    this.options.add(new Option(item.text, item.value, item.selected));
                }
                return this;
            },
            /**
            * Remove an item option
            * @param {Number} index      Seleted item index
            * @returns {Dom Element} Combo Control
            */
            removeItem: function(index) {
                this.options[index]  = null;
                return this;
            },
            /**
            * Select first item from Combobox
            * @returns {Dom Element} Combo Control
            */
            deselectAll: function() {
                for(var i=0; i<this.options.length; i++) {
                    this.options[i].selected = false;
                }
                return this;
            },
            /**
            * Select all items from Combobox
            * @returns {Dom Element} Combo Control
            */
            selectAll: function() {
                for(var i=0; i<this.options.length; i++) {
                    this.options[i].selected = true;
                }
                return this;
            },
            /**
            * Remove all item
            * @returns {Dom Element} Combo Control
            */
            removeAll: function() {
                this.length = 0;
                return this;
            },
            /**
            * Check if exists items
            * @returns {Dom Element} Combo Control
            */
            hasItem: function() {
                return (this.options.length > 0) ? true : false ;
            },
            /**
            * Remove all the selected items
            *
            * @returns {Dom Element} Combo Control
            */
            removeSelected: function() {
                for (var i=this.options.length-1; i>=0; i--) {
                    if (this.options[i].selected) {
                        this.removeItem(i);
                    }
                }
                return this;
            },
            /**
            * Get Value from the combobox and return a list of object include of text and value
            * Can remove the option which get value or not, default is not allowed to remove.
            *
            * @param {Boolean} all     True: Get all optons
            * @param {Boolean} remove  True: Remove the option
            * @param {Array}
            */
            getObjValue: function(all, remove) {
                var selected = all;
                var remove = remove || false;
                var obj = [];
                for (var i=this.options.length-1; i>=0; i--) {
                    var option = this.options[i];
                    var item = null;
                    if (selected) {
                        if (option.selected) {
                            item = {'text': option.text, 'value': option.value};
                        }
                    } else {
                        item = {'text': option.text, 'value': option.value};
                    }
                    if (item != null) {
                        obj.push(item);
                        if (remove) {
                            this.removeItem(i);
                        }
                    }
                }
                return obj;
            },
           /**
            * Add items to combobox
            * @param {Array} Array of object : {text: '', value: '', selected: true}
            * @param {Array} Array of value that exclude from the items
            * @returns {DOM Element} Combo control
            */
            addItems: function(items, excludedItems) {
                for(var key in items) {
                    var item = items[key];
                    if (!Object.isUndefined(excludedItems)) {
                        var exclude = false;
                        for (var i=0, length=excludedItems.length; i < length; i++) {
                            if (excludedItems[i] == item.value) {
                                exclude = true;
                                break;
                            }
                        }
                        if (!exclude) this.addItem(item);
                    } else {
                        this.addItem(item);
                    }
                }
                return this;
            },
            /**
             * Add Group items to combobox
             * 
             * @param {Array} grpItems
             * @returns {DOM Element} Combo control
             */
            addGroupItems: function(grpItems, option) {
                for (var k in grpItems) {
                    var grp = grpItems[k];
                    if (1 == option) {
                        var optGroup = $('<optgroup label="'+ grp.text +'"/>');
                        for(var key in grp.value) {
                            var item = grp.value[key];
                            $('<option value="'+ item.value +'">' + item.text + '</option>').appendTo(optGroup);
                        }
                        optGroup.appendTo($(this));
                    } else {
                        $('<option value="'+ grp.other_value +'">' + grp.text + '</option>').appendTo($(this));
                        for(var key in grp.value) {
                            var item = grp.value[key];
                            $('<option value="'+ item.value +'">..... ' + item.text + '</option>').appendTo($(this));
                        }
                    }
                }
                return this;
            },
            addItemObj: function(items, text, value, selectedItems) {
                for (var idx in items) {
                    var obj = items[idx];
                    var item = {text: '', value: ''};
                    for (var member in obj) {
                        if (member == text) {
                            item.text = obj[member];
                        } else if (member == value) {
                            item.value = obj[member];
                        }
                    }
                    this.addItem(item);
                }
                this.setSelectedItems(selectedItems);
                return this;
            },
            getItemObj: function(idx) {
                idx = idx || 0;
                var opt = this.options[idx];
                if (opt != null) return {'text': opt.text, 'value': opt.value};
                else return null;
            },
            /**
            * Get values of the control
            * @param {Boolean} all Get all options' value
            * @returns {String} A string of value
            */
            getValues: function(all) {
                var selected = all || false;
                var values = '';
                for (var i=0, length = this.options.length; i < length; i++) {
                    var option = this.options[i];
                    if (!selected) {
                        if (option.selected) {
                            values += (values ? ',' : '') + option.value;
                        }
                    } else {
                        values += (values ? ',' : '') + option.value;
                    }
                }
                return values;
            },
            /**
            * Set selected items for the combobox
            *
            * @param {Object} items
            * @returns {Element DOM}
            */
            setSelectedItems: function(items) {
                if (Object.isArray(items)) {
                    for (var key in items) {
                        for (var i=0, length = this.options.length; i < length; i++) {
                            if (items[key] == this.options[i].value) {
                                this.options[i].selected = true;
                                break;
                            }
                        }
                    }
                }
                return this;
            },
            /**
            * Get current selected value
            *
            * @returns {String}
            */
            getValue: function() {
                if (this.selectedIndex != -1) return this.options[this.selectedIndex].value;
                else return null;
            },
            /**
             * Get length
             * 
             * @returns {Number}
             */
            getLength: function() {
                return this.options.length;
            }
        });
        return elm;
    }
    //add more func
});
/**
* A control for manipulating with double combobox: Change the first combo, the second combobox will change data.
*
* @class Double combobox
* @param {String} srcId Source combobox id
* @param {String} destId Target combobox id
* @param {String|Object} url
*/
Whl.Combo.Double = function(srcId, destId, url, opt) {
    this.src = Whl.Combo.get(srcId);
    this.dest = Whl.Combo.get(destId);
    this._data = null;
    this._url = null;
    if (Object.isObject(url)) this._data = url;
    else if (Object.isString(url)) this._url = url;
    
    this.opt = {
        param: {},
        excludeElm: null,
        paramId: [],
        defaultItems: [],
        beforeStart: null,
        complete: null,
        sepValue: false,  // Value of src is sepertate by ','. It has two value: first is key and other.
        defaultDest: this.dest.getItemObj(),
        grpOption: 0,
        useDefaultDest: false
    };
    opt = opt || {};
    Object.extend(this.opt, opt);
    if (this.opt.useDefaultDest) this.opt.defaultItems.push(this.opt.defaultDest);
    this._initialize();
};
Whl.Combo.Double.prototype = {
    /**
    * Initialize the control
    *
    * @returns {void}
    */
    _initialize: function() {
        
        if (this._url != null) {
            $(this.src).change(this.getData.bind(this, null));
        } else {
            $(this.src).change(this.load2.bind(this));
        }
    },
    /**
     * Create an query string
     * 
     * @returns {String}
     */
    _makeParam: function() {
        var param = '';
        for (var key in this.opt.param) {
            param += (param ? '&' : '') + key + '=' +  this.opt.param[key];
        }
        for (var key in this.opt.paramId) {
            param += (param ? '&' : '') + this.opt.paramId[key] + '=' +  $('#' + this.opt.paramId[key]).val();
        }
        return param;
    },
    /**
    * Get the data from the url
    *
    * @returns {void}
    */
    getData: function() {
        var param = this._makeParam();
        param += (param ? '&' : '') + Whl.getToken() + '&' + $.param($(this.src));
        if (Object.isFunction(this.opt.beforeStart)) {
            this.opt.beforeStart();
        }
        var option = {
            type: 'POST',
            url: this._url,
            dataType: 'json',
            data: param,
            success:  this.load.bind(this),
            error: function(XMLHttpRequest, textStatus, errorThrown) {
                Whl.Dialog.error({msg: textStatus});
            }
        };
        $.ajax(option);
    },
    /**
    * Load data for the second dialog
    *
    * @param {Array} data
    * @param {String} statusText
    * @returns {void}
    */
    load: function(data, statusText) {
        this.dest.removeAll();
        if (0 < this.opt.defaultItems.length) {
            for (var key in this.opt.defaultItems) {
                this.dest.addItem(this.opt.defaultItems[key]);
            }
        }
        if (this.opt.excludeElm) {
            var excludedItems = Whl.Combo.get(this.opt.excludeElm).getValues(true);
            this.dest.addItems(data, excludedItems.split(','));
        } else {
            this.dest.addItems(data);
        }
        if (Object.isFunction(this.opt.complete)) {
            this.opt.complete(this);
        }
    },
    /**
     * Append data for the destaination combobox
     * 
     * @returns {void}
     */
    load2: function() {
        if (Object.isFunction(this.opt.beforeStart)) {
            this.opt.beforeStart();
        }
        this.dest.removeAll();
        var srcValue = $(this.src).val();
        if (this.opt.sepValue) {
            srcValue = srcValue.split(',');
            srcValue = srcValue[0];
        }        
        if (0 < this.opt.defaultItems.length) {
            for (var key in this.opt.defaultItems) {
                this.dest.addItem(this.opt.defaultItems[key]);
            }
        }
        if (!Object.isUndefined(this._data[srcValue])) {
            var items = this._data[srcValue];
            if (this.opt.grpOption > 0) this.dest.addGroupItems(items, this.opt.grpOption);
            else this.dest.addItems(items);
        }
        if (Object.isFunction(this.opt.complete)) {
            this.opt.complete(this);
        }
    }
};

/**
* @namespace Dialog Contains functions, class for manipulating with the model dialog
*/
Whl.Dialog = {};

Object.extend(Whl.Dialog, {
    /**
    * Display an model dialog: message/confirm/error/... dialog, default is message dialog
    *
    * @memberOf Whl.Dialog
    * @param {Object} option
    * @param {String} option.title Title of the dialog
    * @param {String} option.msg Contain of the dialog
    * @param {String} option.id Id of the dialog
    * @param {String} option.icon Icon view to display more information
    * @param {String} option.contCss Css for the contain in dialog
    * @param {String} option.container Container that contains the dialog
    * @param {Object} option.buttons Buttons for dialog
    * @param {Boolean} option.hideClose Hide the Close button of dialog
    * @param {Boolean} option.remove Remove the dialog from the form after close event occur
    * @returns {void}
    */
    show: function(option) {
        var opt = {title: Message.Dlg.title, msg: Message.Dlg.loading, id: 'msg', icon: 'ui-icon-info', contCss: '', container: 'body', buttons: {}, hideClose: false, remove: false, dlgOpt: {}, callback: function() {}};
        if (!Object.isUndefined(option) && Object.isObject(option)) Object.extend(opt, option);
        var dl = '<div id="{id}_dlg" title="">'+
        '<p id="{id}_cont" style="margin-top: 15px; border:0px">'+
        '<span id="{id}_icon" class="ui-icon" style="float:left; margin:0px 7px 50px 0px;"></span>'+
        '<span id="{id}_text"></span>'+
        '</p>'+
        '</div>';
        //Append to body/container if not has yet
        dl = dl.replace(/{id}/g, opt.id);
        var container = $(opt.container + ' #' + opt.id + '_dlg');
        if (0 == container.size()) {
            $(opt.container).append(dl);
        } else if (1 < container.size()) {
            throw 'Invalid';
        }
        //Append text for dialog
        dl = $(opt.container + ' #' + opt.id + '_dlg').attr('title', opt.title);
        if (opt.contCss != '') $(opt.container + ' #' + opt.id + '_cont').addClass(opt.contCss);
        $(opt.container + ' #' + opt.id + '_icon').addClass(opt.icon);
        $(opt.container + ' #' + opt.id + '_text').html(opt.msg);
        //Setting for dialog
        var options = {bgiframe: true,autoOpen: false,closeOnEscape: false,width:'auto',height:'auto',minHeight:100,resizable:true,modal:true};
        //Remove dialog while close the dialog
        options.close = function() {
            opt.callback();
            if (opt.remove) {
                $(this).dialog('destroy').remove();
            }
        };
        //Focus on the first button
        options.open = function() {
            var btn = $(this).siblings().find('button');
            if (btn.length == 2) {
                $(btn[1]).focus();
            }
        };
        Object.extend(options, {buttons: opt.buttons});
        Object.extend(options, opt.dlgOpt);
        dl.dialog(options);
        //Hide the close button of dialog
        if (opt.hideClose) dl.parents(".ui-dialog").find(".ui-dialog-titlebar-close").hide();
        if (!dl.dialog('isOpen')) dl.dialog('open');
    },
    /**
     * Show a message dialog
     * 
     * @param (Object} option (Referece to show function)
     * @returns {void}
     */
    msg: function(option) {
        var opt = {hideClose: false, dlgOpt:{resizable: false}, buttons: {Close: function() { $(this).dialog('close');}}};
        if (!Object.isUndefined(option) && Object.isObject(option)) Object.extend(opt, option);
        this.show(opt);
    },
    /**
    * Show a confirm dialog
    *
    * @param (Object} option (Referece to show function)
    * @returns {void}
    */
    confirm: function(option) {
        var opt = {
            icon: 'ui-icon-info',
            contCss: 'ui-state-highlight'
        };
        if (!Object.isUndefined(option) && Object.isObject(option)) Object.extend(opt, option);
        this.show(opt);
    },
    /**
    * Show a delete confirm dialog
    *
    * @param {Function} callback
    * @param (Object} option (Referece to show function)
    * @returns {void}
    */
    del: function(callback, option) {
        var opt = {
            title: 'Delete data',
            msg: 'Do you want to delete this item.?',
            id: 'delete',
            buttons: {
                Cancel: function() {
                    $(this).dialog('close');
                },
                Ok: function() {
                    $(this).dialog('close');
                    callback();
                }
            }
        };
        if (!Object.isUndefined(option) && Object.isObject(option)) Object.extend(opt, option);
        this.confirm(opt);
    },
    /**
    * Show a error dialog
    *
    * @param (Object} option (Referece to show function)
    * @returns {void}
    */
    error: function(option) {
        option = option || {};
        var opt = {
            title: 'Error occurs',
            icon: 'ui-icon-alert',
            contCss: 'ui-state-error',
            id: 'err',
            buttons: {
                Close: function() {
                    $(this).dialog('close');
                }
            },
            dlgOpt: {resizable: false,maxWidth: 300, height:'auto',maxHeight: 300}
        };
        if (Whl.isErrReq(option.msg)) {
            option.msg = option.msg.substring(4);
        }
        Object.extend(opt, option);
        this.show(opt);
    },
    /**
    * Close the model dialog
    *
    * @param {String} id
    * @param {Boolean} remove Remove the dialog
    */
    close: function(id) {
        $('#' + id + '_dlg').dialog('close');
    },
    /**
    * Close the message dialog
    *
    * @param {Boolean} remove Remove the dialog
    */
    closeMsg: function() {
        this.close('msg');
    }
});

/**
* @namespace Image Contains functions, class for manipulating with the image
*/
Whl.Image = {};

/**
 * 
 * @class Whl.Image.Rotator
 * @param {Array} imgData           The array of image
 * @param {String} imgId            The img id
 * @param {String|null} pathData    
 */
Whl.Image.Rotator = function(imgData, imgId, pathData)
{
    this._path = pathData || '';
    this._imgData = imgData;
    this._elmImg = $('#' + imgId);
    this.initialize();
};
Whl.Image.Rotator.prototype = {
    /**
     * Init the control
     * 
     * @returns {void}
     */
    initialize: function() {
        if (this._elmImg.length == 0 || this._imgData.length == 1) return;
        var images = this._preloadImages(this._path);
        if (images.length > 0) {
            setInterval(this.run.bind(this, images), 5000);
        }
    },
    /**
     * View Image random
     * 
     * @param {Array} images A array of images that loaded
     * @returns {void}
     */
    run: function(images) {
        var randImg = Whl.rand(this._imgData.length - 1);
        this._elmImg.attr('src', images[randImg].src);
    },
    /**
     * Load the images to the client for showing image quickly
     * 
     * @returns {void}
     */
    _preloadImages: function(path) {
        var images = [];
        $.each(this._imgData, function(i) {
            images[i] = new Image();
            images[i].src = path + this;
        });
        return images;
    }
};

Object.extend(Whl.Image, {
    loadImages: function(ids, images, path, idPrefix) {
        for (var i=0; i<ids.length; i++){
            for(var j=0; j<document.images.length; j++){
                if(document.images[j].id == idPrefix + ids[i]){
                    if (images[i] && images[i] != '')
                        document.images[j].src = path + images[i];
                    else document.images[j].src = '/images/en/no_photo.gif';
                }
            }
        }
    }
});

