﻿//<using>
//  nui/nui.js
//  nui/prototype.js
//  nui/lang.js
//  nui/util.js
//  nui/widget.js
//</using>

/**
 * All kinds of Inputs in NUI
 * Copyright 2007, NetRanking.cn
 *
 * IMPORTANT : It is necessory to import "widget/button.js", "widget/panel.js" first
 */
NUI.Widget.Input = {
    Base : function() {},
    
    Options : function(vOptHtmls, vFunc, vAttributes) {},
    Matrix : function(vRoptHtmls, vCoptHtmls, vFunc, vAttributes) {},
    MatrixInput : function(vRoptHtmls, vCoptHtmls, vFunc, vAttributes) {},
    TextInputType : {
        STRING : {
            id : 1,
            value : "String",
            text : "字符串"
        },
        INT : {
            id : 2,
            value : "Int",
            text : "整数"
        },
        FLOAT : {
            id : 3,
            value : "Float",
            text : "浮点数"
        },
        EMAIL : {
            id : 4,
            value : "Email",
            text : "邮箱"
        }
    },
    TextInput : function(vType, vMin, vMax, vFunc) {},
    RankBarType : {
        apple0 : 0,
        apple1 : 1,
        apple2 : 2,
        apple3 : 3,
        sun0 : 4,
        sun1 : 5,
        moon0 : 6,
        moon1 : 7,
        cloud0 : 8,
        cloud1 : 9,
        snow : 10,
        rain : 11,
        butterfly : 12,
        fire : 13,
        heart : 14,
        leaf_green : 15,
        leaf_red : 16,
        music : 17,
        pine : 18,
        star0 : 19,
        star1 : 20,
        umbrella : 21
    },
    RankBar : function() {},
    SortPanel : function() {},
    ArrangeType : {
        horizontal : 0,
        vertical : 1
    },
    ConstBarType : {
        blue : 0,
        yellow : 1,
        green : 2,
        pink : 3,
        orange : 4,
        purple : 5,
        red : 6,
        gray : 7
    },
    ConstBar : function() {},
    Location : function() {}
};

/**
 * The base class of input
 */
NUI.Widget.Input.Base = (function(){
    var g_dom = NUI.Util.DomService,
        g_ht = NUI.Util.DataStructure.HashTable;
        
    return function(vSecret) {
        var m_secret = vSecret || {},
            that = NUI.Widget.Base(m_secret);
            
        NUI.Util.ObjectService.annex(m_secret, {
            /**
             * Dom cache
             */
            domCache : new g_ht(),
            
            /**
             * Get the dom ref. If the dom ref is in cache, get it from the cache       CHANGE TO getChild!!!!!!!!
             * @param vId {int}
             */
            getDom : function(vId) {
                var obj =  m_secret.domCache.getValue(vId);
                if(obj == null) {
                    obj = g_dom.getNode(vId, {
                        root : that.nodeEntity
                    });
                    if(obj == null) {
                        obj = g_dom.getNode(vId);
                    }
                    m_secret.domCache.setValue(vId, obj);
                }
                return obj;
            },
            
            /**
             * The basic frame of input dom
             */
            node : (function() {
                var retval = g_dom.createNode("div", {
                        className : "inputCon"
                    }),
                    innerHTML = "<div class=\"info\">" + 
                        "<span class=\"msg hide\" id=\"" + m_secret.id + "_msg\"></span>" + 
                        "<span class=\"note\" id=\"" + m_secret.id + "_note\"></span>" + 
                        "</div>";
                g_dom.setInnerHTML(retval, innerHTML);
                return retval;
            })(),
            
            /**
             * Set the message
             */
            showMsg : function(vMsg) {
                if(vMsg == null) {
                    return;
                }
                var obj = m_secret.getDom(m_secret.id + "_msg");
                if(obj != null) {
                    obj.innerHTML = vMsg;
                    if(vMsg.trim() == "") {
                        g_dom.hide(obj);
                    } else {
                        g_dom.show(obj);
                    }
                }
            },
            
            /**
             * Set the note
             */
            setNote : function(vNote) {
                if(vNote == null) {
                    return;
                }
                var obj = m_secret.getDom(m_secret.id + "_note");
                if(obj != null) {
                    obj.innerHTML = vNote;
                }
            } 
        });
        
        NUI.Util.ObjectService.annex(that, {});
        
        return that;
    };
})();

/**
 * Options. How to use ?
 *  var node = NUI.Widget.Input.Options(["a", "b", "c", "d", "e"], 
 *      function(vIndexs, vOtherValue) {alert(vIndexs + vOtherValue)}, 
 *      {min:1, max: 3, column:2});
 *  node.appendTo("conId");
 */
NUI.Widget.Input.Options = (function() {
    var g_lang = NUI.Lang,
        g_dom = NUI.Util.DomService,
        g_sb = NUI.Util.StringService.StringBuilder,
        g_incrChar = NUI.Util.StringService.increaseChar,
        g_ht = NUI.Util.DataStructure.HashTable;
    
    /**
     * @class NUI.Widget.Input.Options 
     * @param vOptHtmls {string}. The html of options.
     * @param vFunc(vOptIndexes, vOtherValue) {function}. The onclick event handler
     *  ATTENTION : If vFunc is null. The options does not check the answer automatically
     * @param vAttributes {object}.
     *      vAttributes = {
     *          id : {string},
     *          min : {int},
     *          max : {int},
     *          column : {int},
     *          hasOther : {boolean},
     *          initIndexes ; {array},
     *          initOtherValue : {string},
     *          random : {boolean}
     *      }
     */
    return function(vOptHtmls, vFunc, vAttributes) {
        var m_optHtmls = NUI.Util.ObjectService.clone(vOptHtmls),
            m_min = 1,
            m_max = 1,
            m_column = 1,
            m_other = false,
            m_func = vFunc ? vFunc : function() {},
            m_resultIndexes = (function() {
                var retval = [],
                    len = m_optHtmls ? m_optHtmls.length : 0;
                for(var i=0; i<len; i++) {
                    retval[i] = 0;
                }
                if(m_other) {
                    retval[retval.length] = 0;
                }
                return retval;
            })(),
            m_resultOtherValue = "",
            m_random = false,
            m_secret = {};
        if(vAttributes) {
            if(vAttributes.id != null) {
                m_secret.id = vAttributes.id;
            }
            if(vAttributes.min > 0) {
                m_min = vAttributes.min;
            }
            if(vAttributes.max > 0) {
                m_max = vAttributes.max;
            }
            if(vAttributes.column > 0) {
                m_column = vAttributes.column;
            }
            if(vAttributes.hasOther) {
                m_other = true;
            }
            if(vAttributes.initIndexes != null) {
                m_resultIndexes = vAttributes.initIndexes;
            }
            if(vAttributes.initOtherValue != null) {
                m_resultOtherValue = vAttributes.initOtherValue;
            }
            m_random = (vAttributes.random ? true : false);
        }
        var that = NUI.Widget.Input.Base(m_secret),
            m_id = m_secret.id;
        
        if(m_other) {
            var isSelected = m_resultIndexes[m_resultIndexes.length-1] > 0;
            m_optHtmls[m_optHtmls.length] = "<input id=\"" + m_id + "_other\" type=\"text\" " + 
                "value=\"" + ((isSelected) ? m_resultOtherValue : "其他(请填写)") + "\" disabled=\"" + 
                ((isSelected) ? "false" : "true") + "\" class=\"" + ((isSelected) ? "enabled" : "disabled") + "\" />";
        }
        var m_isRadio = (m_min==1 && m_max==1),
            m_optTmplt = "<div><label style=\"cursor:pointer;\"><input type=\"{OPT_TYPE}\" name=\"" + 
                m_id + "_opt\" id=\"{OPT_ID}\" style=\"cursor:pointer;\" {OPT_ADDITIONAL} />" + 
                "<span class=\"optTag\">{OPT_INDEX}.&nbsp;</span>" + "<div id=\"{OPT_ID}_CNT\" style=\"display:inline;\">{OPT_HTML}</div></label></div>";
        
        /**
         * Get a option's id;
         */
        function _getOptId(vIndex) {
            return m_id + "_opt_" + vIndex;
        }
        
        /**
         * Get the selected value
         */
        function _setupResult() {
            /**
             * Get the user's input for the "other option"
             */
            function __getOtherValue() {
                if(!m_other) {
                    return null;
                }
                var ipt = m_secret.getDom(m_id + "_other");
                if(ipt) {
                    return ipt.value;
                }
                return null;
            }
        
            var opts = [],
                len = m_optHtmls.length;
            for(var i=0; i<len; i++) {
                var opt = m_secret.getDom(_getOptId(i));
                opts[i] = (opt != null && opt.checked) ? 1 : 0;
            }
            m_resultIndexes = opts;
            m_resultOtherValue = __getOtherValue();
        }
        
        /**
         * The click event
         */
        var _clickEvent = m_isRadio ? function() {
            var src = event.srcElement;
            if(src) {
                if(g_dom.isRadio(src)) {
                    if(m_other) {
                        var other = m_secret.getDom(m_id + "_other");
                        if(other != null) {
                            if(src.id.controlId() == m_optHtmls.length-1) {
                                other.disabled = false;
                                other.focus();
                                g_dom.setCssClass(other, "enabled");
                            } else {
                                other.disabled = true;
                                g_dom.setCssClass(other, "disabled");
                            }
                        }
                    }
                    _setupResult();
                    if(m_func != null) {
                        m_func(m_resultIndexes, m_resultOtherValue);
                    }
                }
            }
        } : function() {
            var src = event.srcElement;
            if(src) {
                if(g_dom.isCheckBox(src)) {
                    if(m_other) {
                        var other = m_secret.getDom(m_id + "_other");
                        if(other != null) {
                            if(src.id.controlId() == m_optHtmls.length-1) {
                                if(src.checked) {
                                    other.disabled = false;
                                    other.focus();
                                    g_dom.setCssClass(other, "enabled");
                                } else {
                                    other.disabled = true;
                                    g_dom.setCssClass(other, "disabled");
                                }
                            }
                        }
                    }
                    _setupResult();
                    var msg = "";
                    if(src.checked) {
                        msg = _checkMax(m_resultIndexes);
                        if(msg != "") {
                            m_secret.showMsg(msg);
                            src.checked = false;
                            return;
                        }
                    }
                    m_secret.showMsg(msg);
                    if(m_func != null) {
                        m_func(m_resultIndexes, m_resultOtherValue);
                    }
                }
            }
        };
        function _checkMax(vOptIdxes) {
            if(vOptIdxes == null) {
                return "选项值有误";
            }
            var count = 0,
                len = vOptIdxes.length;
            for(var i=0; i<len; i++) {
                if(vOptIdxes[i] == 1) {
                    count++;
                }
            }
            return (count > m_max) ? "最多只能选择" + m_max + "个选项" : "";
        }
        function _checkMin(vOptIdxes) {
            if(vOptIdxes == null) {
                return "选项值有误";
            }
            var count = 0,
                len = vOptIdxes.length;
            for(var i=0; i<len; i++) {
                if(vOptIdxes[i] == 1) {
                    count++;
                }
            }
            return (count < m_min) ? "最少必须选择" + m_min + "个选项" : "";
        }
        
        var m_node = (function() {
            var retval = m_secret.node,
                opts = g_dom.createNode("div", {
                    id : m_id,
                    className : "choice",
                    onclick : _clickEvent
                });
                
            var idxUsed = new g_ht();
            function _getRandomIdx() {
                var count = m_optHtmls.length;
                if(idxUsed.count() >= count) {
                    return -1;
                }
                var retval = Math.floor(Math.random() * count);
                while(true) {
                    if(retval < 0 || retval >= count) {
                        retval = 0;
                    } else if(idxUsed.exist(retval)) {
                        retval ++;
                    } else {
                        idxUsed.setValue(retval, true);
                        return retval;
                    }
                }
            }
           
            var sb = new g_sb(),
                rCount = Math.ceil(m_optHtmls.length/m_column),
                count = rCount*m_column,
                optType = m_isRadio ? "radio" : "checkbox";
            sb.append("<table cellpadding=\"0\" cellspacing=\"0\" >");
            for(var r=0; r<rCount; r++) {
                sb.append("<tr>");
                for(var c=0; c<m_column; c++) {
                    sb.append("<td>");
                    var idx = m_random ? _getRandomIdx() : (r*m_column + c);
                        html = m_optHtmls[idx];
                    if(html!=null) {
                        sb.append(m_optTmplt.supplant({
                            OPT_TYPE : optType,
                            OPT_ID : _getOptId(idx),
                            OPT_INDEX : r * m_column + c + 1 + "",
//                            OPT_INDEX : g_incrChar("A", r*m_column + c),
                            OPT_HTML : html,
                            OPT_ADDITIONAL : (m_resultIndexes[idx] > 0) ? "checked=\"true\"" : ""
                        }));
                    }
                    sb.append("</td>");
                }
                sb.append("</tr>");
            }
            sb.append("</table>");
            
            g_dom.setInnerHTML(opts, sb.toString());
            g_dom.appendNode(retval, opts);
            return retval;
        })();
        
        NUI.Util.ObjectService.annex(that, { 
            nodeEntity : m_node,
            
            /** 
             * Reset the onclick event
             */
            resetEvent : function(vFunc) {
                m_func = vFunc;
            },
            
            /**
             * Get the div container of the input ref of an option
             * @param vIndex {int} The index of the option
             */
            getOptDivDom : function(vIndex) {
                var opt = m_secret.getDom(_getOptId(vIndex) + "_CNT");
                return opt;
            }
        });
        
        //SET the event handler of other-input
        NUI.Util.EventService.attachEventHandler(m_secret.getDom(m_id + "_other"), "onblur", function() {
            _setupResult();
            if(m_func != null) {
                m_func(m_resultIndexes, m_resultOtherValue);
            }
        });
        
        /**
         * Set note
         */
        (function() {
            var html = "";
            if(m_min==1 && m_max==1) {
                html = "";
            } else if(m_min==m_max) {
                html = "(请选择" + m_min + "个选项)";
            } else {
                html = "(请选择" + m_min + "到" + m_max + "个选项)";
            }
            m_secret.setNote(html);
        })();
        
        return that;
    };
})();

/**
 * Matrix. How to use ?
 *  var ropthtmls = ["a", "b", "c", "d", "e"],
 *      copthtmls = ["1", "2", "3", "4"];
 *  var node = NUI.Widget.Input.Matrix(ropthtmls, copthtmls, function(vIndexs, vROV, vCOV) {
 *      alert(vIndexs + vROV + vCOV)}, {rmin:1, rmax: 3, rhasOther : true, cmin:1, cmax: 2, chasOther : false});
 *  node.appendTo("options");
 */
NUI.Widget.Input.Matrix = (function() {
    var g_dom = NUI.Util.DomService,
        g_incrChar = NUI.Util.StringService.increaseChar,
        g_sb = NUI.Util.StringService.StringBuilder,
        g_ht = NUI.Util.DataStructure.HashTable,
        g_optType = {
            row : "row",
            col : "col"
        };
    
    /**
     * @class NUI.Widget.Input.Matrix 
     * @param vRoptHtmls {string}. The html of row options.
     * @param vCoptHtmls {string}. The html of col options.
     * @param vFunc(vOptIndexes, vRotherValue, vCotherValue) {function}. The onclick event handler. 
     *  vOptIndexes is two-dimension array. 
     *  ATTENTION : If vFunc is null. The matrix does not check the answer automatically
     * @param vAttributes {object}.
     *      vAttributes = {
     *          id : {string},
     *          rmin : {int},
     *          rmax : {int},
     *          cmin : {int},
     *          cmax : {int},
     *          rhasOther : {boolean},
     *          chasOther : {boolean},
     *          initIndexes : {array},
     *          initRowOtherValue : {string},
     *          initColOtherValue : {string}
     *      }
     */
    return function(vRoptHtmls, vCoptHtmls, vFunc, vAttributes) {
        var m_optHtmls = {
                row : NUI.Util.ObjectService.clone(vRoptHtmls),
                col : NUI.Util.ObjectService.clone(vCoptHtmls)
            },
            m_min = {
                row : 1,
                col : 1
            },
            m_max = {
                row : 1,
                col : 1
            },
            m_other = {
                row : ((vAttributes && vAttributes.rhasOther) ? true : false),
                col : ((vAttributes && vAttributes.chasOther) ? true : false)
            },
            m_resultIndexes = (function() {
                var retval = [],
                    rowCount = m_optHtmls.row.length + (m_other.row ? 1 : 0),
                    colCount = m_optHtmls.col.length + (m_other.col ? 1 : 0);
                for(var r=0; r<rowCount; r++) {
                    retval[r] = [];
                    for(var c=0; c<colCount; c++) {
                        retval[r][c] = 0;
                    }
                }
                return retval;
            })(),
            m_resultOtherValue = {
                row : "其他(请填写)",
                col : "其他(请填写)"
            }, 
            m_func = vFunc ? vFunc : function() {},
            m_secret = {};
        if(vAttributes) {
            if(vAttributes.id != null) { m_secret.id = vAttributes.id; }
            if(vAttributes.rmin >= 0) { m_min[g_optType.row] = vAttributes.rmin; }
            if(vAttributes.rmax >= 0) { m_max[g_optType.row] = vAttributes.rmax; }
            if(vAttributes.cmin >= 0) { m_min[g_optType.col] = vAttributes.cmin; }
            if(vAttributes.cmax >= 0) {m_max[g_optType.col] = vAttributes.cmax; }
//            if(vAttributes.rhasOther) { m_other[g_optType.row] = true; }
//            if(vAttributes.chasOther) { m_other[g_optType.col] = true; }
            if(vAttributes.initIndexes != null) {
                var rowCount = m_resultIndexes.length;
                if(rowCount > 0) {
                    var colCount = m_resultIndexes[0].length;
                    for(var r=0; r<rowCount; r++) {
                        if(vAttributes.initIndexes[r]==null) {
                            continue;
                        }
                        for(var c=0; c<colCount; c++) {
                            if(vAttributes.initIndexes[r][c] != null)
                                m_resultIndexes[r][c] = vAttributes.initIndexes[r][c];
                        }
                    }
                }
            }
            if(vAttributes.initRowOtherValue != null) { m_resultOtherValue.row = vAttributes.initRowOtherValue; }
            if(vAttributes.initColOtherValue != null) { m_resultOtherValue.col = vAttributes.initColOtherValue; }
        }
        var that = NUI.Widget.Input.Base(m_secret),
            m_id = m_secret.id;
        
        NUI.Util.ObjectService.walkObject(g_optType, function(vName) {
            var name = g_optType[vName];
            if(m_other[name]) {
                var htmls = m_optHtmls[name];
                htmls[htmls.length] = "<input id=\"" + m_id + "_" + name + 
                    "_other\" value=\"" + m_resultOtherValue[name] + "\" type=\"text\" class=\"enabled\" />";
            }
        });
        var m_optTmplt = "<div><input type=\"checkbox\" id=\"{OPT_ID}\" style=\"cursor:pointer;\" " + 
            "title=\"{TOOL_TIP}\" {OPT_ADDITIONAL} /></div>";
        
        /**
         * Get a option's id;
         */
        function _getOptId(vRindex, vCindex) {
            return m_id + "_opt_" + vRindex + "_" + vCindex;
        }
        function _getLabelId(vType, vIndex) {
            return m_id + "_" + vType + "_" + vIndex;
        }
        
        /**
         * Get the user's input for the "other option"
         */
        function __getOtherValue(vType) {
            if(!m_other[vType]) {
                return null;
            }
            var ipt = m_secret.getDom(m_id + "_" + vType + "_other");
            if(ipt) {
                return ipt.value;
            }
            return null;
        }
        /**
         * Get the selected value
         */
        function _setupResult(vCheckBox) {
            if(!vCheckBox) {
                return;
            }
            
            var c = vCheckBox.id.controlId(),
                r = vCheckBox.id.controlName().controlId();
            m_resultIndexes[r][c] = vCheckBox.checked ? 1 : 0;
        
            m_resultOtherValue.row = __getOtherValue(g_optType.row);
            m_resultOtherValue.col = __getOtherValue(g_optType.col);
        }
        
        /**
         * The click event
         */
        function _clickEvent() {
            var src = event.srcElement;
            if(src) {
                if(g_dom.isCheckBox(src)) {
                    _setupResult(src);
                    var msg = "";
                    if(src.checked) {
                        msg = _checkMax(m_resultIndexes);
                        if(msg != "") {
                            m_secret.showMsg(msg);
                            src.checked = false;
                            var c = src.id.controlId(),
                                r = src.id.controlName().controlId();
                            m_resultIndexes[r][c] = 0;
                            return;
                        }
                    }
                    var td = src.parentNode.parentNode;
                    if(td) {
                        if(src.checked) {
                            g_dom.addCssClass(td, "selected");
                        } else {
                            g_dom.removeCssClass(td, "selected");
                        }
                    }
                    m_secret.showMsg(msg);
                    if(m_func != null) {
                        m_func(m_resultIndexes, m_resultOtherValue.row, m_resultOtherValue.col);
                    }
                }
            }
        }
        var m_time_counter = 0;     // Time span counter
        function _checkMax(vOptIndexes) {
            var tc = m_time_counter;
            m_time_counter++;
            setTimeout(function() {
                m_time_counter--;
            }, 1000);
            if(tc > 0) {
                return "您回答的速度太快了，请看清题目，确保回答正确。";
            }
            if(vOptIndexes == null || vOptIndexes.length == 0) {
                return "选项值有误";
            }
            var rlen = vOptIndexes.length,  
                clen = vOptIndexes[0].length,
                msg = new g_sb("");
            for(var r1=0; r1<rlen; r1++) {
                var rcount = 0;
                for(var c1=0; c1<clen; c1++) {
                    if(vOptIndexes[r1][c1] == 1) {
                        rcount ++;
                    }
                }
                var max1 = m_max[g_optType.row];
                if(rcount > max1) {
                    msg.append("第", r1+1, "行最多选", max1, "个选项\r\n");
                }
            }
            for(var c2=0; c2<clen; c2++) {
                var ccount = 0;
                for(var r2=0; r2<rlen; r2++) {
                    if(vOptIndexes[r2][c2] == 1) {
                        ccount ++;
                    }
                }
                var max2 = m_max[g_optType.col];
                if(ccount > max2) {
                    msg.append("第", c2+1, "列最多选", max2, "个选项\r\n");
                }
            }
            return msg.toString().trim();
        }
        function _checkMin(vOptIndexes) {
            if(vOptIndexes == null || vOptIndexes.length == 0) {
                return "选项值有误";
            }
            var rlen = vOptIndexes.length,  
                clen = vOptIndexes[0].length,
                msg = new g_sb("");
            for(var r1=0; r1<rlen; r1++) {
                var rcount = 0;
                for(var c1=0; c1<clen; c1++) {
                    if(vOptIndexes[r1][c1] == 1) {
                        rcount ++;
                    }
                }
                var min1 = m_min[g_optType.row];
                if(rcount < min1) {
                    msg.append("第", r1+1, "行至少选", min1, "个选项\r\n");
                }
            }
            for(var c2=0; c2<clen; c2++) {
                var ccount = 0;
                for(var r2=0; r2<rlen; r2++) {
                    if(vOptIndexes[r2][c2] == 1) {
                        ccount ++;
                    }
                }
                var min2 = m_min[g_optType.col];
                if(ccount < min2) {
                    msg.append("第", c2+1, "列至少选", min2, "个选项\r\n");
                }
            }
            return msg.toString().trim();
        }
        
        var m_node = (function() {
            var retval = m_secret.node,
                opts = g_dom.createNode("div", {
                    id : m_id,
                    className : "matrix",
                    onclick : _clickEvent
                });
            
            var sb = new g_sb(),
                rhtmls = m_optHtmls[g_optType.row],
                chtmls = m_optHtmls[g_optType.col],
                rlen = rhtmls.length,
                clen = chtmls.length;
            sb.append("<div>");
            sb.append("<table cellpadding=\"0\" cellspacing=\"0\"><tr class=\"A\"><td>&nbsp;</td>");
            for(var c0=0; c0<clen; c0++) {
                sb.append(
                    "<td><span class=\"optTag\">", 
                    g_incrChar("A", c0) , 
                    ".</span>", 
                    "<div id=\"", _getLabelId(g_optType.col, c0), "\" style=\"display:inline\">", 
                    chtmls[c0], 
                    "</div></td>"
                );
            }
            sb.append("</tr>");
            var alter = false;
            for(var r=0; r<rlen; r++) {
                var className = alter ? "A" : "B";
                alter = !alter;
                sb.append(
                    "<tr class=\"",
                    className,
                    "\"><td><span class=\"optTag\">", 
                    (r+1) , 
                    ".</span>", 
                    "<div id=\"", _getLabelId(g_optType.row, r), "\" style=\"display:inline\">", 
                    rhtmls[r], 
                    "</div></td>"
                );//alert(m_resultIndexes.length + " " + r);
                for(var c=0; c<clen; c++) {
                    var ischecked = (m_resultIndexes[r][c] > 0);
                    sb.append(
                        "<td class=\"normal ",
                        ischecked ? "selected" : "",
                        "\" onmouseover=\"NUI.Util.DomService.replaceCssClass(this, 'normal', 'hover');\" ",
                        "onmouseout=\"NUI.Util.DomService.replaceCssClass(this, 'hover', 'normal');\" >", 
                        m_optTmplt.supplant({
                            OPT_ID : _getOptId(r, c),
                            TOOL_TIP : g_incrChar("A", c) + (r+1),
                            OPT_ADDITIONAL : ischecked ? "checked=\"true\"" : ""
                        }), 
                        "</td>"
                    );
                }
                sb.append("</tr>");
            }
            sb.append("</table></div>");
            
            g_dom.setInnerHTML(opts, sb.toString());
            g_dom.appendNode(retval, opts);
            return retval;
        })();
        
        NUI.Util.ObjectService.annex(that, { 
            nodeEntity : m_node,
            
            /** 
             * Reset the onclick event
             */
            resetEvent : function(vFunc) {
                m_func = vFunc;
            },
            
            /**
             * Get the div container of the input ref of an option
             * @param vIndex {int} The row index
             */
            getRoptDivDom : function(vIndex) {
                var id = _getLabelId(g_optType.row, vIndex);
                return m_secret.getDom(id);
            },
            /**
             * Get the div container of the input ref of an option
             * @param vIndex {int} The row index
             */
            getCoptDivDom : function(vIndex) {
                var id = _getLabelId(g_optType.col, vIndex);
                return m_secret.getDom(id);
            }
        });
        
        //SET the event handler of other-input
        NUI.Util.ObjectService.walkObject(g_optType, function(vName) {
            var name = g_optType[vName];
            if(m_other[name]) {
                NUI.Util.EventService.attachEventHandler(m_secret.getDom(m_id + "_" + name + "_other"), "onblur", function() {
                    m_resultOtherValue.row = __getOtherValue(g_optType.row);
                    m_resultOtherValue.col = __getOtherValue(g_optType.col);
                    if(m_func != null) {
                        m_func(m_resultIndexes, m_resultOtherValue.row, m_resultOtherValue.col);
                    }
                });
            }
        });
        
        
        /**
         * Set note
         */
        (function() {
            var html = "(",
                rmin = m_min.row,
                rmax = m_max.row,
                cmin = m_min.col,
                cmax = m_max.col;
            if(rmin==rmax) {
                html += "每行可选" + rmin + "个选项&nbsp;";
            } else {
                html += "每行可选" + rmin + "到" + rmax + "个选项&nbsp;";
            }
            if(cmin==cmax) {
                html += "每列可选" + cmin + "个选项)";
            } else {
                html += "每列可选" + cmin + "到" + cmax + "个选项)";
            }
            m_secret.setNote(html);
        })();
        
        return that;
    };
})();


/**
 * MatrixInput. How to use ?
 *  var ropthtmls = ["a", "b", "c", "d", "e"],
 *      copthtmls = ["1", "2", "3", "4"];
 *  var node = NUI.Widget.Input.MatrixInput(ropthtmls, copthtmls, function(vOptValues, vROV, vCOV) {
 *      alert(vOptValues + vROV + vCOV)}, {rmin:1, rmax: 3, rhasOther : true, chasOther : false});
 *  node.appendTo("options");
 */
NUI.Widget.Input.MatrixInput = (function() {
    var g_dom = NUI.Util.DomService,
        g_incrChar = NUI.Util.StringService.increaseChar,
        g_sb = NUI.Util.StringService.StringBuilder,
        g_ht = NUI.Util.DataStructure.HashTable,
        g_optType = {
            row : "row",
            col : "col"
        };
    
    /**
     * @class NUI.Widget.Input.MatrixInput 
     * @param vRoptHtmls {string}. The html of row options.
     * @param vCoptHtmls {string}. The html of col options.
     * @param vFunc(vOptValues, vRotherValue, vCotherValue) {function}. The onclick event handler. 
     *  vOptValues is two-dimension array. 
     *  ATTENTION : If vFunc is null. The matrix does not check the answer automatically
     * @param vAttributes {object}.
     *      vAttributes = {
     *          id : {string},
     *          rhasOther : {boolean},
     *          chasOther : {boolean},
     *          initValues : {array},
     *          initRowOtherValue : {string},
     *          initColOtherValue : {string}
     *      }
     */
    return function(vRoptHtmls, vCoptHtmls, vFunc, vAttributes) {
        var m_optHtmls = {
                row : NUI.Util.ObjectService.clone(vRoptHtmls),
                col : NUI.Util.ObjectService.clone(vCoptHtmls)
            },
            m_other = {
                row : ((vAttributes && vAttributes.rhasOther) ? true : false),
                col : ((vAttributes && vAttributes.chasOther) ? true : false)
            },
            m_resultValues = (function() {
                var retval = [],
                    rowCount = m_optHtmls.row.length + (m_other.row ? 1 : 0),
                    colCount = m_optHtmls.col.length + (m_other.col ? 1 : 0);
                for(var r=0; r<rowCount; r++) {
                    retval[r] = [];
                    for(var c=0; c<colCount; c++) {
                        retval[r][c] = "";
                    }
                }
                return retval;
            })(),
            m_resultOtherValue = {
                row : "其他(请填写)",
                col : "其他(请填写)"
            }, 
            m_func = vFunc ? vFunc : function() {},
            m_secret = {};
        if(vAttributes) {
            if(vAttributes.id != null) { m_secret.id = vAttributes.id; }
            if(vAttributes.initValues != null) {
                var rowCount = m_resultValues.length;
                if(rowCount > 0) {
                    var colCount = m_resultValues[0].length;
                    for(var r=0; r<rowCount; r++) {
                        if(vAttributes.initValues[r]==null) {
                            continue;
                        }
                        for(var c=0; c<colCount; c++) {
                            if(vAttributes.initValues[r][c] != null)
                                m_resultValues[r][c] = vAttributes.initValues[r][c];
                        }
                    }
                }
            }
            if(vAttributes.initRowOtherValue != null) { m_resultOtherValue.row = vAttributes.initRowOtherValue; }
            if(vAttributes.initColOtherValue != null) { m_resultOtherValue.col = vAttributes.initColOtherValue; }
        }
        var that = NUI.Widget.Input.Base(m_secret),
            m_id = m_secret.id;
        
        NUI.Util.ObjectService.walkObject(g_optType, function(vName) {
            var name = g_optType[vName];
            if(m_other[name]) {
                var htmls = m_optHtmls[name];
                htmls[htmls.length] = "<input id=\"" + m_id + "_" + name + 
                    "_other\" value=\"" + m_resultOtherValue[name] + "\" type=\"text\" class=\"enabled\" />";
            }
        });
        var m_optTmplt = "<div><input type=\"text\" id=\"{OPT_ID}\" style=\"color:#B88906\" value=\"{OPT_VALUE}\" " + 
            "title=\"{TOOL_TIP}\" /></div>";
        
        /**
         * Get a option's id;
         */
        function _getOptId(vRindex, vCindex) {
            return m_id + "_opt_" + vRindex + "_" + vCindex;
        }
        function _getLabelId(vType, vIndex) {
            return m_id + "_" + vType + "_" + vIndex;
        }
        
        /**
         * Get the user's input for the "other option"
         */
        function __getOtherValue(vType) {
            if(!m_other[vType]) {
                return null;
            }
            var ipt = m_secret.getDom(m_id + "_" + vType + "_other");
            if(ipt) {
                return ipt.value;
            }
            return null;
        }
        /**
         * Get the selected value
         */
        function _setupResult(vInputBox) {
            if(!vInputBox) {
                return;
            }
            
            var c = vInputBox.id.controlId(),
                r = vInputBox.id.controlName().controlId();
            m_resultValues[r][c] = vInputBox.value;
        
            m_resultOtherValue.row = __getOtherValue(g_optType.row);
            m_resultOtherValue.col = __getOtherValue(g_optType.col);
        }
        
        /**
         * The blur event
         */
//        function _blurEvent() {
//            var src = event.srcElement;
//            if(src) {
//                if(g_dom.isTextInput(src) && src.id.controlName().controlName == (m_id + "_opt")) {
//                    _setupResult(src);
//                    if(m_func != null) {
//                        m_func(m_resultValues, m_resultOtherValue.row, m_resultOtherValue.col);
//                    }
//                }
//            }
//        }
        
        var m_node = (function() {
            var retval = m_secret.node,
                opts = g_dom.createNode("div", {
                    id : m_id,
                    className : "matrix"
                });
            
            var sb = new g_sb(),
                rhtmls = m_optHtmls[g_optType.row],
                chtmls = m_optHtmls[g_optType.col],
                rlen = rhtmls.length,
                clen = chtmls.length;
            sb.append("<div>");
            sb.append("<table cellpadding=\"0\" cellspacing=\"0\"><tr class=\"A\"><td>&nbsp;</td>");
            for(var c0=0; c0<clen; c0++) {
                sb.append(
                    "<td><span class=\"optTag\">", 
                    g_incrChar("A", c0) , 
                    ".</span>", 
                    "<div id=\"", _getLabelId(g_optType.col, c0), "\" style=\"display:inline\">", 
                    chtmls[c0], 
                    "</div></td>"
                );
            }
            sb.append("</tr>");
            var alter = false;
            for(var r=0; r<rlen; r++) {
                var className = alter ? "A" : "B";
                alter = !alter;
                sb.append(
                    "<tr class=\"",
                    className,
                    "\"><td><span class=\"optTag\">", 
                    (r+1) , 
                    ".</span>", 
                    "<div id=\"", _getLabelId(g_optType.row, r), "\" style=\"display:inline\">", 
                    rhtmls[r], 
                    "</div></td>"
                );
                for(var c=0; c<clen; c++) {
                    sb.append(
                        "<td class=\"normal ",
                        "\" onmouseover=\"NUI.Util.DomService.replaceCssClass(this, 'normal', 'hover');\" ",
                        "onmouseout=\"NUI.Util.DomService.replaceCssClass(this, 'hover', 'normal');\" >", 
                        m_optTmplt.supplant({
                            OPT_ID : _getOptId(r, c),
                            TOOL_TIP : g_incrChar("A", c) + (r+1),
                            OPT_VALUE : m_resultValues[r][c]
                        }), 
                        "</td>"
                    );
                }
                sb.append("</tr>");
            }
            sb.append("</table></div>");
            
            g_dom.setInnerHTML(opts, sb.toString());
            g_dom.appendNode(retval, opts);
            return retval;
        })();
        
        NUI.Util.ObjectService.annex(that, { 
            nodeEntity : m_node,
            
            /** 
             * Reset the onclick event
             */
            resetEvent : function(vFunc) {
                m_func = vFunc;
            },
            
            /**
             * Get the div container of the input ref of an option
             * @param vIndex {int} The row index
             */
            getRoptDivDom : function(vIndex) {
                var id = _getLabelId(g_optType.row, vIndex);
                return m_secret.getDom(id);
            },
            /**
             * Get the div container of the input ref of an option
             * @param vIndex {int} The row index
             */
            getCoptDivDom : function(vIndex) {
                var id = _getLabelId(g_optType.col, vIndex);
                return m_secret.getDom(id);
            }
        });
        
        //SET the event handler of opt-input
        var rlen = m_optHtmls[g_optType.row].length,
            clen = m_optHtmls[g_optType.col].length;
        for(var r=0; r<rlen; r++) {
            for(var c=0; c<clen; c++) {
                NUI.Util.EventService.attachEventHandler(m_secret.getDom(_getOptId(r, c)), "onblur", function() {
                    _setupResult(this);
                    if(m_func != null) {
                        m_func(m_resultValues, m_resultOtherValue.row, m_resultOtherValue.col);
                    }
                });
            }
        }
            
        //SET the event handler of other-input
        NUI.Util.ObjectService.walkObject(g_optType, function(vName) {
            var name = g_optType[vName];
            if(m_other[name]) {
                NUI.Util.EventService.attachEventHandler(m_secret.getDom(m_id + "_" + name + "_other"), "onblur", function() {
                    m_resultOtherValue.row = __getOtherValue(g_optType.row);
                    m_resultOtherValue.col = __getOtherValue(g_optType.col);
                    if(m_func != null) {
                        m_func(m_resultValues, m_resultOtherValue.row, m_resultOtherValue.col);
                    }
                });
            }
        });
        
        
        /**
         * Set note
         */
        (function() {
            var html = "";
            m_secret.setNote(html);
        })();
        
        return that;
    };
})();

/**
 * Options. How to use ?
 */
NUI.Widget.Input.TextInput = (function() {
    var g_dom = NUI.Util.DomService,
        g_evt = NUI.Util.EventService,
        g_sb = NUI.Util.StringService.StringBuilder,
        g_ht = NUI.Util.DataStructure.HashTable,
        g_math = NUI.Util.MathService,
        g_type = NUI.Widget.Input.TextInputType;
        
    function _isTypeLegal(vType) {
        var isLegal = false;
        NUI.Util.ObjectService.searchObject(g_type, function(vName) {
            isLegal = (NUI.Util.ObjectService.sameAs(g_type[vName], vType));
            return isLegal;
        });
        return isLegal;
    }
    
    var g_checker = {};
    g_checker[g_type.STRING.value] = function(vValue, vMin, vMax) { //vValue is string
        var _msg = "";
        if(vValue == null) {
            _msg = "输入值不能为空";
        } else if(vValue.length < vMin) {
            _msg = "输入文字长度必须大于" + vMin;
        } else if(vValue.length > vMax) {
            _msg = "输入文字长度必须小于" + vMax;
        }
        return {
            value : vValue,
            msg : _msg
        };
    };
    g_checker[g_type.INT.value] = function(vValue, vMin, vMax) {
        var intvalue = g_math.toInt(vValue),
            _msg = "";
        if(isNaN(intvalue)) {
            _msg = "输入必须为整数"; 
        } else if(intvalue < vMin) {
            _msg = "输入整数必须大于" + vMin;
        } else if(intvalue > vMax) {
            _msg = "输入整数必须小于" + vMax;
        }
        return {
            value : intvalue,
            msg : _msg
        };
    };
    g_checker[g_type.FLOAT.value] = function(vValue, vMin, vMax) {
        var fltvalue = g_math.toFloat(vValue),
            _msg = "";
        if(isNaN(fltvalue)) {
            _msg = "输入必须为浮点数"; 
        } else if(fltvalue < vMin) {
            _msg = "输入浮点数必须大于" + vMin;
        } else if(fltvalue > vMax) {
            _msg = "输入浮点数必须小于" + vMax;
        }
        return {
            value : fltvalue,
            msg : _msg
        };
    };
    g_checker[g_type.EMAIL.value] = function(vValue, vMin, vMax) {
        var _msg = "";
        if(vValue == null) {
            _msg = "输入值不能为空";
        } else {
            var checkMail = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
            if(!checkMail.test(vValue)) {
                _msg = "邮箱地址不合法";
            }
        }
        return {
            value : vValue,
            msg : _msg
        };
    };
    
    /**
     * @class NUI.Widget.Input.TextInput
     * @param vType {NUI.Widget.Input.TextInputType}
     * @param vMin {int} The min value/length
     * @param vMax {int} Tha max value/length
     * @param vFunc(vValue) {function{string|int|float}}
     * @param vAttributes {object}.
     *      vAttributes = {
     *          id : {string},
     *          initValue : {string | number}
     *      }
     */
    return function(vType, vMin, vMax, vFunc, vAttributes) {
        if(!_isTypeLegal(vType)) {
            return null;
        }
        var m_type = vType,
            m_min = vMin,
            m_max = vMax,
            m_func = vFunc ? vFunc : function() {},
            m_resultValue = "",
            m_secret = {},
            that = NUI.Widget.Input.Base(m_secret),
            m_id = m_secret.id;
            
        if(vAttributes != null) {
            if(vAttributes.initValue != null) { m_resultValue = vAttributes.initValue; }
        }

        var m_inputId = m_id + "_input",
            m_inputTmplt = (function(){
                if(m_type.id == g_type.STRING.id && m_max >= 500) {
                    return "<div style=\"text-align:center;\"><textarea id=\"{INPUT_ID}\" " + 
                        "style=\"width:80%; height:100px;\">" + m_resultValue + "</textarea></div>";
                } else {
                    return "<input type=\"text\" id=\"{INPUT_ID}\" value=\"" + m_resultValue + "\" />";
                }
            })(),
            m_innerHTML = (function() {
                var sb = new g_sb();
                sb.append(
                    m_inputTmplt.supplant({
                        INPUT_ID : m_inputId
                    }),
                    "<span id=\"" + m_id + "_msg\" style=\"background:#FAD163;\"></span>"
                );
                sb.append("<span class=\"note\">");
                if(m_type.id == g_type.EMAIL.id) {
                    sb.append("(邮箱地址必须合法)");
                } else {
                    sb.append("(输入" + m_type.text + "在" + m_min + "到" + m_max + "之间)");
                }
                sb.append("</span>");
                return sb.toString();
            })();
            
        /**
         * The onblur event
         */
        var _onblurEvent = function() {
            var ck = g_checker[m_type.value](this.value.trim(), m_min, m_max);
            m_secret.getDom(m_id + "_msg").innerHTML = ck.msg;
            this.value = ck.value;
            if(ck.msg == "") {
                if(m_func == null) {
                    return;
                }
                m_func(ck.value);
            }
        };
        
        var m_node = (function() {
            var retval = g_dom.createNode("div", {
                    id : m_id,
                    style : {
                        display : "inline"
                    }
                }),
                innerHTML = m_innerHTML;
            g_dom.setInnerHTML(retval, innerHTML);
            var ipt = g_dom.getNode(m_inputId, {root : retval});
            if(ipt != null) {
                g_evt.attachEventHandler(ipt, "onblur", _onblurEvent);
            }
            return retval;
        })();
        
        NUI.Util.ObjectService.annex(that, { 
            nodeEntity : m_node,
            
            /** 
             * Reset the onclick event
             */
            resetEvent : function(vFunc) {
                m_func = vFunc;
            }
        });
        
        return that;
    };
})();

/**
 * RankBar. How to use ?
 *  var node = NUI.Widget.Input.RankBar("test", function() {}, {});
 *  node.appendTo("conId");
 */
NUI.Widget.Input.RankBar = (function() {
    var g_type = NUI.Widget.Input.RankBarType,
        g_dom = NUI.Util.DomService,
        g_btn = NUI.Widget.Button.SpanButton,
        g_btnStatus = NUI.Widget.Button.ButtonStatus,
        g_imgInfo = {
            index : 0,
            width : 24,
            height : 24,
            xCount : 3,
            yCount : 15,
            image : "nui/input/rankbar.gif"
        };
    
    /**
     * @class NUI.Widget.Input.Options 
     * @param vContent {string}. The html content.
     * @param vFunc(vCount) {function}. The function to execute after clicking on the bar
     * @param vAttributes {object}.
     *      vAttributes = {
     *          id : {string},
     *          type : {NUI.Widget.Input.RankBarType.*},
     *          count : {int},
     *          initValue : {int}
     *      }
     */
    return function(vContent, vFunc, vAttributes) {
        var m_html = vContent,
            m_type = g_type.star0,
            m_count = 10,
            m_func = vFunc ? vFunc : function() {},
            m_resultValue = 0,
            m_secret = {};
        if(vAttributes) {
            if(vAttributes.id != null) { m_secret.id = vAttributes.id; }
            if(vAttributes.type != null && NUI.Util.ObjectService.hasValue(g_type, vAttributes.type)) { m_type = vAttributes.type;}
            if(vAttributes.count > 0) {m_count = vAttributes.count;}
            if(vAttributes.initValue > 0) {m_resultValue = vAttributes.initValue;}
        }
        var that = NUI.Widget.Input.Base(m_secret),
            m_id = m_secret.id,
            m_contentDom = (function() {
                var retval = g_dom.createNode("div", {
                    className : "content"
                });
                g_dom.setInnerHTML(retval, m_html);
                return retval;
            })(),
            m_iconDom = g_dom.createNode("div", {
                id : m_id + "_icons",
                className : "icons"
            }),
            m_icons = (function() {
                var retval = [];
                for(var i=0; i<m_count; i++) {
                    g_imgInfo.index = m_type;
                    retval[i] = new g_btn(g_imgInfo, {
                        title : i+1,
                        onclick : (function(vIndex) {
                            return function() {
                                _onclick(vIndex);
                            };
                        })(i),
                        onmouseover : (function(vIndex) {
                            return function() {
                                _onmouseover(vIndex);
                            };
                        })(i),
                        onmouseout : _onmouseout
                    });
                    if(i < m_resultValue) {
                        retval[i].lockStatus(g_btnStatus.mousedown);
                    }
                    retval[i].appendTo(m_iconDom);
                }
                return retval;
            })(),
            m_tipDom = (function() {
                var retval = g_dom.createNode("span", {
                    id : m_id + "_tip",
                    className : "tip"
                });
                g_dom.setInnerHTML(retval, m_resultValue + "/" + m_count);
                return retval;
            })(),
            m_nodeDom = (function() {
                var retval = m_secret.node,
                    body = g_dom.createNode("div", {
                        className : "rankbar"
                    }),
                    iconCon = g_dom.createNode("div", {
                        className : "iconCon"
                    });
                g_dom.appendNode(body, m_contentDom);
                g_dom.appendNode(iconCon, m_iconDom);
                g_dom.appendNode(iconCon, m_tipDom);
                g_dom.appendNode(body, iconCon);
                g_dom.appendNode(retval, body);
                return retval;
            })();
            
        /**
         * The event handler of the icon
         */
        function _onclick(vIndex) {
            m_resultValue = vIndex + 1;
            __setIcon(vIndex);
            __setTip(m_resultValue);
            if(!m_func) {
                return;
            }
            m_func(m_resultValue);
        }
        function _onmouseover(vIndex) {
            __setIcon(vIndex);
            __setTip(vIndex + 1);
        }
        function _onmouseout() {
            __setIcon(m_resultValue -1);
            __setTip(m_resultValue);
        }
        function __setIcon(vIndex) {
            var bound1 = m_resultValue,
                bound2 = vIndex + 1;
            if(bound1 > bound2) {
                var tmp = bound1;
                bound1 = bound2;
                bound2 = tmp;
            }
            for(var i1=0; i1<bound1; i1++) {
                m_icons[i1].lockStatus(g_btnStatus.mousedown);
            }
            for(var i2=bound1; i2<bound2; i2++) {
                m_icons[i2].lockStatus(g_btnStatus.mouseover);
            }
            for(var i3=bound2; i3<m_count; i3++) {
                m_icons[i3].lockStatus(g_btnStatus.mouseout);
            }
        }
        function __setTip(vValue) {
            g_dom.setInnerHTML(m_tipDom, vValue + "/" + m_count);
        }
        
        NUI.Util.ObjectService.annex(that, { 
            nodeEntity : m_nodeDom,
            
            /**
             * Get the label dom
             */
            getLabelDom : function() {
                return m_contentDom;
            },
            
            /** 
             * Reset the onclick event
             */
            resetEvent : function(vFunc) {
                m_func = vFunc;
            }
        });
        
        return that;
    };
})();

/**
 * SortPanel. How to use ?
 *  var node = NUI.Widget.Input.SortPanel(["aaa", "bb<br />b", "ccc", "ddd", "ee"], 
 *      function(v){document.getElementById("abc").innerHTML = (v)}, {column:2});
 *  node.appendTo(conId);
 */
NUI.Widget.Input.SortPanel = (function() {
    var g_dom = NUI.Util.DomService,
        g_sb = NUI.Util.StringService.StringBuilder;
    
    /**
     * @class NUI.Widget.Input.Options 
     * @param vOptHtmls {string}. The html of options.
     * @param vFunc(vRankedValue) {function}. The onclick event handler
     * @param vAttributes {object}.
     *      vAttributes = {
     *          id : {string},
     *          column : {int},
     *          initValue : {array}
     *      }
     */
    return function(vOptHtmls, vFunc, vAttributes) {
        var m_optHtmls = NUI.Util.ObjectService.clone(vOptHtmls),
            m_len = m_optHtmls.length,
            m_column = 3,
            m_func = vFunc ? vFunc : function() {},
            m_resultValue = (function() {
                var retval = [];
                for(var i=0; i<m_len; i++) {
                    retval[i] = -1;
                }
                return retval;
            })(),
            m_secret = {};
        if(vAttributes) {
            if(vAttributes.id != null) { m_secret.id = vAttributes.id; }
            if(vAttributes.column > 0) { m_column = vAttributes.column; }
            if(vAttributes.initValue != null) { m_resultValue = vAttributes.initValue; }
        }
        
        var that = NUI.Widget.Input.Base(m_secret),
            m_id = m_secret.id;
        
        function _getMenuId(vIndex) {
            return m_id + "_menu_" + vIndex;
        }
        function _getCbxId(vIndex) {
            return m_id + "_cbx_" + vIndex;
        }
        function _getOptId(vIndex) {
            return m_id + "_opt_" + vIndex;
        }
        function _getTipId(vIndex) {
            return m_id + "_tip_" + vIndex;
        }
                  
        var m_currentRank = 0,
            m_menus = (function() {
                var retval = g_dom.createNode("div", {
                    id : m_id + "_menus",
                    className : "menus",
                    onclick : function() {
                        var src = event.srcElement;
                        if(g_dom.isButton(src)) {
                            var preNode = m_secret.getDom(_getMenuId(m_currentRank));
                            if(preNode) {
                                g_dom.removeCssClass(preNode.parentNode, "selected");
                                preNode.disabled = false;
                            }
                            m_currentRank = src.id.controlId();
                            src.disabled = true;
                            g_dom.addCssClass(src.parentNode, "selected");
                            for(var i=0; i<m_len; i++) {
                                var cbx = m_secret.getDom(_getCbxId(i));
                                if(!cbx) {
                                    continue;
                                }
                                cbx.disabled = (m_resultValue[i] >= 0 && m_resultValue[i] != m_currentRank);
                            }
                        }
                    }
                });
                var sb = new g_sb();
                for(var i=0; i<m_len; i++) {
                    sb.append("<div class=\"item\"><input type=\"button\" id=\"",
                        _getMenuId(i), "\" value=\"第", (i+1), 
                        "名\" /></div>"
                    );
                }
                sb.append("<div class=\"clearup\"></div>");
                g_dom.setInnerHTML(retval, sb.toString());
                return retval;
            })(),
            m_options = (function() {
                var retval = g_dom.createNode("div", {
                        id : m_id + "_content",
                        className : "content",
                        onclick : function() {
                            var src = event.srcElement;
                            if(g_dom.isCheckBox(src)) {
                                var checked = src.checked;
                                for(var i=0; i<m_len; i++) {
                                    if(m_resultValue[i] == m_currentRank) {
                                        m_resultValue[i] = -1;
                                        g_dom.setInnerHTML(m_secret.getDom(_getTipId(i)), "");
                                        m_secret.getDom(_getCbxId(i)).checked = false;
                                    }
                                }
                                src.checked = checked;
                                if(checked) {
                                    var index = src.id.controlId();
                                    g_dom.setInnerHTML(m_secret.getDom(_getTipId(index)), "("+(m_currentRank+1)+")");
                                    m_resultValue[index] = m_currentRank;
                                    var next = m_currentRank+1;
                                    if(next >= m_len){
                                        next = 0;
                                    }
                                    m_secret.getDom(_getMenuId(next)).click();
                                }
                            }
                            if(m_func) {
                                m_func(m_resultValue);
                            }
                        }
                    }),
                    body = NUI.Widget.Panel.RoundConner({border : "#7089C1", background : "#BFCAE6"});
                var sb = new g_sb(),
                    incrChar = NUI.Util.StringService.increaseChar;
                var rCount = Math.ceil(m_optHtmls.length/m_column);
                sb.append("<table cellpadding=\"0\" cellspacing=\"0\" width=\"100%\" valign=\"middle\">");
                for(var r=0; r<rCount; r++) {
                    sb.append("<tr>");
                    for(var c=0; c<m_column; c++) {
                        var idx = r*m_column + c;
                            html = m_optHtmls[idx];
                        sb.append("<td class=\"cb\">");
                        if(html!=null) {
                            sb.append(
                                "<input type=\"checkbox\" id=\"" + _getCbxId(idx) + "\" ",
                                (m_resultValue[idx] >= 0) ? "checked=\"true\" disabled=\"true\"" : "",
                                " /></td><td><span class=\"optTag\">",
                                incrChar("A", idx),
                                ".&nbsp;</span><div style=\"display:inline;\" id=\"" + _getOptId(idx) + "\" >",
                                html, 
                                "</div><span id=\"" + _getTipId(idx) + "\" class=\"tip\">",
                                (m_resultValue[idx] >= 0) ? "(" + (m_resultValue[idx]+1) + ")" : "",
                                "</span>"
                            );
                        } else {
                            sb.append("</td><td>");
                        }
                        sb.append("</td>");
                    }
                    sb.append("</tr>");
                }
                sb.append("</table>");
                body.setInnerNode(sb.toString());
                body.appendTo(retval);
                return retval;
            })(),
            m_node = (function() {
                var retval = m_secret.node,
                    body = g_dom.createNode("div", {
                    id : m_id,
                    className : "sortPanel"
                });
                g_dom.appendNode(retval, body);
                g_dom.appendNode(body, m_menus);
                g_dom.appendNode(body, m_options);
                g_dom.appendNode(body, g_dom.createNode("div", {className:"clearup"}));
                return retval;
            })();
            
        NUI.Util.ObjectService.annex(that, { 
            nodeEntity : m_node,
            
            /** 
             * Reset the onclick event
             */
            resetEvent : function(vFunc) {
                m_func = vFunc;
            },
            
            /**
             * Get the div container of the input ref of an option
             * @param vIndex {int} The index of the option
             */
            getOptDivDom : function(vIndex) {
                return m_secret.getDom(_getOptId(vIndex));
            }
        });
        
        /**
         * Click the firt menu
         */
        var menu1 = m_secret.getChild(_getMenuId(0));
        if(menu1!=null) {
            menu1.click();
        }
        
        return that;
    };
})();

/**
 * ConstBar. How to use ?
 *  var node = NUI.Widget.Input.ConstBar(["aaa", "bb<br />b", "ccc", "ddd", "ee"], function(vResult){
 *      alert(vResult);
 *  }, {
 *      type:NUI.Widget.Input.ConstBarType.blue, 
 *      arrange:NUI.Widget.Input.ArrangeType.horizontal
 *  });
 *  node.appendTo(conId);
 */
NUI.Widget.Input.ConstBar = (function() {
    var g_dom = NUI.Util.DomService,
        g_sb = NUI.Util.StringService.StringBuilder,
        g_incrChar = NUI.Util.StringService.increaseChar,
        g_gmt = NUI.Util.WindowService.Geometry,
        g_cbType = NUI.Widget.Input.ConstBarType,
        g_argType = NUI.Widget.Input.ArrangeType,
        g_optTmplt = "<div class=\"item\" style=\"{STYLE}\"><div class=\"tag\">{OPT_TAG}</div>" + 
            "<div class=\"content\" id=\"{OPT_ID}\">{OPT_HTML}</div></div>",
        g_tagTmplt = "<div id=\"{TAG_ID}\" class=\"tag\" style=\"left:{LEFT}%\">{TAG}<span id=\"{TAG_ID}_inner\">{VALUE}%</span></div>",
        g_borderTmplt = "<div class=\"border\" style=\"background-position:-3px {BG_POSITION}px;\"></div>",
        g_staffTmplt = "<div id=\"{STAFF_ID}\" class=\"staff\" style=\"background-position:0 {BG_POSITION}px;width:{WIDTH}px;\"></div>",
        g_ballTmplt = "<div id=\"{BALL_ID}\" class=\"ball\" style=\"background-position:0 {BG_POSITION_01}px;\" " + 
            "onmouseover=\"this.style.backgroundPosition='0 {BG_POSITION_02}px';\" " + 
            "onmousedown=\"this.style.backgroundPosition='0 {BG_POSITION_03}px';\" " + 
            "onmouseup=\"this.style.backgroundPosition='0 {BG_POSITION_02}px';\" " + 
            "onmouseout=\"this.style.backgroundPosition='0 {BG_POSITION_01}px';\" " + 
            "></div>";
    
    /**
     * @class NUI.Widget.Input.Options 
     * @param vOptHtmls {string}. The html of options.
     * @param vFunc(vResult) {function}. The drag event handler
     * @param vAttributes {object}.
     *      vAttributes = {
     *          id : {string},
     *          type : {NUI.Widget.Input.ConstBarType.*},
     *          arrange : {NUI.Widget.Input.ArrangeType.*},
     *          initValue : {array of float}
     *      }
     */
    return function(vOptHtmls, vFunc, vAttributes) {
        var m_optHtmls = NUI.Util.ObjectService.clone(vOptHtmls),
            m_len = m_optHtmls.length,
            m_type = 0,
            m_arrange = NUI.Widget.Input.ArrangeType.horizontal,
            m_func = vFunc ? vFunc : function() {},
            m_resultValue = (function() {
                if(m_len <= 0) {
                    return [];
                }
                var retval = [],
                    value = 1 / m_len;
                for(var i=0; i < m_len-1; i++) {
                    retval[i] = value;
                }
                retval[retval.length] = 1 - value*(m_len - 1);
                return retval;
            })(),
            m_secret = {};
        if(vAttributes) {
            if(vAttributes.id != null) { m_secret.id = vAttributes.id; }
            if(NUI.Util.ObjectService.hasValue(g_cbType, vAttributes.type)) { m_type = vAttributes.type; }
            if(NUI.Util.ObjectService.hasValue(g_argType, vAttributes.arrange)) { m_arrange = vAttributes.arrange; }
            if(vAttributes.initValue != null && vAttributes.initValue.length == m_len) {
                m_resultValue = vAttributes.initValue;
            }
        }
        var that = NUI.Widget.Input.Base(m_secret),
            m_id = m_secret.id,
            m_style = (m_arrange==g_argType.vertical) ? "clear:both" : "display:inline";
        
        /**
         * Get a option's id;
         */
        function _getOptId(vIndex) {
            return m_id + "_opt_" + vIndex;
        }
        /**
         * Get a option's tag;
         */
        function _getOptTag(vIndex) {
            return g_incrChar("A", vIndex);
        }
        /**
         * Get a bar tag's id
         */
        function _getTagId(vIndex) {
            return m_id + "_tag_" + vIndex;
        }
        /**
         * Get a ball's id
         */
        function _getBallId(vIndex) {
            return m_id + "_ball_" + vIndex;
        }
        /**
         * Get a staff's id
         */
        function _getStaffId(vIndex) {
            return m_id + "_staff_" + vIndex;
        }
        
        /**
         * Get the background image position of the bar
         */
        function _getBgPosition(vIndex) {
            var alt = vIndex - Math.floor(vIndex / 2)*2;
            var base = (m_type + alt) * 48;
            return {
                staff : - (base),
                ball_01 : - (base + 6),
                ball_02 : - (base + 16),
                ball_03 : - (base + 26),
                border :  - (base + 36)
            };
        }
        
        /**
         * Get the left position percent
         */
        function _getTagLeft(vIndex) {
            var adjust = 10 / m_totalWidth,
                left = 0;
            for(var i=0; i<vIndex; i++) {
                left += m_resultValue[i] + adjust;
            }
            left += m_resultValue[vIndex] / 2;
            return left * 100;
        }
        
        var m_totalWidth = 500,
            m_widths = (function() {
                m_resultValue
                var retval = [],
                    len = m_len-1,
                    sum = 0;
                for(var i=0; i<len; i++) {
                    retval[i] = m_totalWidth * m_resultValue[i];
                    sum += retval[i];
                }
                retval[len] = m_totalWidth - sum;
                return retval;
            })(),
            m_options = (function() {
                var retval = g_dom.createNode("div", {
                    id : m_id + "_optcon",
                    className : "options"
                });
                var sb = new g_sb();
                for(var i=0; i<m_len; i++) {
                    sb.append(g_optTmplt.supplant({
                        OPT_ID : _getOptId(i),
                        OPT_TAG : _getOptTag(i),
                        OPT_HTML : m_optHtmls[i],
                        STYLE : m_style
                    }));
                }
                g_dom.setInnerHTML(retval, sb.toString());
                return retval;
            })(),
            m_docEvent = null,
            m_docReset = true,
            m_bar = (function() {
                var retval = g_dom.createNode("div", {
                    id : m_id + "_bar",
                    className : "bar",
                    onmousedown : function() {
                        var src = event.srcElement,
                            x0 = event.clientX;
                        if(src && g_dom.isDiv(src) && g_dom.hasCssClass(src, "ball")) {
                            var idx = src.id.controlId(),
                                leftStaff = m_secret.getDom(_getStaffId(idx)),
                                rightStaff = m_secret.getDom(_getStaffId(idx + 1)),
                                leftTag = m_secret.getDom(_getTagId(idx)),
                                rightTag = m_secret.getDom(_getTagId(idx + 1)),
                                leftTagValue = m_secret.getDom(_getTagId(idx)+"_inner"),
                                rightTagValue = m_secret.getDom(_getTagId(idx + 1)+"_inner");
                            if(leftStaff && rightStaff) {
                                if(m_docReset) {
                                    m_docEvent = document.onmousemove;
                                    m_docReset = false;
                                }
                                document.onmousemove = function() {
                                    var x1 = event.clientX;
                                    var detaX = x1 - x0;
                                    var w1 = m_widths[idx] + detaX,
                                        w2 = m_widths[idx+1] - detaX;
                                    if(w1<0 || w2<0) {
                                        return;
                                    }
                                    x0 = x1;
                                    m_widths[idx] = w1;
                                    m_widths[idx+1] = w2;
                                    m_resultValue[idx] = w1 / m_totalWidth;
                                    m_resultValue[idx+1] = w2 / m_totalWidth;
                                    leftStaff.style.width = w1 + "px";
                                    rightStaff.style.width = w2 + "px";
                                    var left = 0;
                                    for(var i=0; i<idx; i++) {
                                        left += m_resultValue[i];
                                    }
                                    leftTag.style.left = _getTagLeft(idx) + "%";
                                    rightTag.style.left = _getTagLeft(idx + 1) + "%";
                                    g_dom.setInnerHTML(leftTagValue, Math.round(10000*m_resultValue[idx])/100 + "%");
                                    g_dom.setInnerHTML(rightTagValue, Math.round(10000*m_resultValue[idx+1])/100 + "%");
                                };
                                document.onmouseup = function() {
                                    if(m_func) {
                                        m_func(m_resultValue);
                                    }
                                    if(!m_docReset) {
                                        document.onmousemove = m_docEvent;
                                        m_docReset = true;
                                    }
                                };
                            }
                        }
                    }
                });
                var sb = new g_sb();
                var pos = _getBgPosition(0);
                sb.append("<div class=\"tags\" style=\"width:" + m_totalWidth + "px;\">");
                for(var i=0; i<m_len; i++) {
                    sb.append(g_tagTmplt.supplant({
                        TAG_ID : _getTagId(i),
                        TAG : _getOptTag(i),
                        LEFT : _getTagLeft(i),
                        VALUE : Math.round(10000*m_resultValue[i])/100
                    }));
                }
                sb.append("</div>");
                sb.append(g_borderTmplt.supplant({
                    BG_POSITION : pos.border
                }));
                var len = m_len-1;
                for(var i=0; i<len; i++) {
                    var pos = _getBgPosition(i);
                    sb.append(g_staffTmplt.supplant({
                        STAFF_ID : _getStaffId(i),
                        BG_POSITION : pos.staff,
                        WIDTH : m_widths[i]
                    }), g_ballTmplt.supplant({
                        BALL_ID : _getBallId(i),
                        BG_POSITION_01 : pos.ball_01,
                        BG_POSITION_02 : pos.ball_02,
                        BG_POSITION_03 : pos.ball_03
                    }));
                }
                var pos = _getBgPosition(len);
                sb.append(g_staffTmplt.supplant({
                    STAFF_ID : _getStaffId(len),
                    BG_POSITION : pos.staff,
                    WIDTH : m_widths[len]
                }), g_borderTmplt.supplant({
                    BG_POSITION : pos.border
                }));
                g_dom.setInnerHTML(retval, sb.toString());
                return retval;
            })(),
            m_node = (function() {
                var retval = m_secret.node,
                    body = g_dom.createNode("div", {className : "constBar"});
                g_dom.appendNode(body, m_options);
                g_dom.appendNode(body, m_bar);
                g_dom.appendNode(retval, body);
                return retval;
            })();
            
        NUI.Util.ObjectService.annex(that, { 
            nodeEntity : m_node,
            
            /** 
             * Reset the onclick event
             */
            resetEvent : function(vFunc) {
                m_func = vFunc;
            },
            
            /**
             * Get the div container of the input ref of an option
             * @param vIndex {int} The index of the option
             */
            getOptDivDom : function(vIndex) {
                return m_secret.getDom(_getOptId(vIndex));
            }
        });
        
        /**
         * Set note
         */
        (function() {
            m_secret.setNote("(拖动圆点改变各个选项所占权重)");
        })();
        
        return that;
    };
})();
