﻿//<using>
//  nui/nui.js
//  nui/prototype.js
//  nui/util.js
//  nui/widget.js
//  nui/widget/input.js
//  nui/quill/entity/*
//  nui/quill/render/render.js
//</using>

/**
 * The namespace of the question renders
 * @namespace NUI.Quill.Render.Question
 */
NUI.Quill.Render.Question = {
    getQuestionRender : function(vQuestion, vAnswer, vAttribute) {},
    Base : function(vSecret) {},
    Choice : function(vQuestion, vAnswer, vAttribute) {},
    Matrix : function(vQuestion, vAnswer) {},
    Input : function(vQuestion, vAnswer) {},
    Rank : function(vQuestion, vAnswer) {},
    Sort : function(vQuestion, vAnswer) {},
    ConstSum : function(vQuestion, vAnswer) {},
    Location : function(vQuestion, vAnswer) {},
    MatrixInput : function(vQuestion, vAnswer) {}
};

/**
 * Get a question's render
 * @param vQuestion {object}. The entity of the question
 * @param vAnswer {object}. The answer of the question
 */
NUI.Quill.Render.Question.getQuestionRender = function(vQuestion, vAnswer, vAttribute) {
    if(vQuestion == null) {
        return null;
    }
    var type = vQuestion.type,
        typeValue = null,
        qType = NUI.Quill.Enum.QuestionType;
    NUI.Util.ObjectService.searchObject(qType, function(vName) {
        if(qType[vName].id == type) {
            typeValue = qType[vName].value;
            return true;
        }
        return false;
    });
    if(typeValue == null) {
        return null;
    }
    return NUI.Quill.Render.Question[typeValue](vQuestion, vAnswer, vAttribute);
};

/**
 * The base class of all kinds of question Render.
 * @class NUI.Quill.Render.Question.Base
 * @param vSecret {object}
 *      vSecret = {
 *          question : {object},  // NUI.Quill.Entity.*
 *      }
 */
NUI.Quill.Render.Question.Base = (function() {
    var g_dom = NUI.Util.DomService,
        g_entity = NUI.Quill.Entity.Question,
        g_widget = NUI.Widget;
    
    return function(vSecret) {
        var secret = vSecret || {};
        if(!secret.question) {
            secret.question = g_entity["Base"]();
        }
        var that = g_widget.Base(secret),
            m_question = secret.question,
            m_frame = (function() {
                var frame = g_dom.createNode("div", {
                    className : "question"
                });
                return frame;
            })(),
            m_caption = (function() {
                var cap = g_dom.createNode("div", {
                    className : "cap"
                });
                g_dom.setInnerHTML(cap, m_question.caption);
                return cap;
            })(),
            m_optCon = (function() {
                var opt = g_dom.createNode("div", {
                    className : "opt"
                });
                return opt;
            })();
        
        g_dom.appendNode(m_frame, m_caption);       // append the caption to frame
        g_dom.appendNode(m_frame, m_optCon);        // append the opt to frame
        
        NUI.Util.ObjectService.annex(secret, {});
        
        NUI.Util.ObjectService.annex(that, {
            nodeEntity : m_frame,
            
            /**
             * Get the frame dom object
             */
            getFrameDom : function() {
                return m_frame;
            },
            
            /**
             * Get the caption dom object
             */
            getCaptionDom : function() {
                return m_caption;
            },
            
            /**
             * Get the caption dom object
             */
            getOptConDom : function() {
                return m_optCon;
            }
        });
        return that;
    };
})();

/**
 * Choice question
 * @class NUI.Quill.Render.Question.Choice
 * @param vQuestion {object}. NUI.Quill.Entity.Question.*
 * @param vAnswer {object}. NUI.Quill.Entity.Answer.*
 * @param vAttribute {object} random or not
 *      vAttribute = {
 *          openRandom : {boolean}
 *      }
 */
NUI.Quill.Render.Question.Choice = (function() {
    var g_dom = NUI.Util.DomService,
        g_ns = NUI.Quill.Render.Question,
        g_type = NUI.Quill.Enum.QuestionType,
        g_input = NUI.Widget.Input;
    
    return function(vQuestion, vAnswer, vAttribute) {
        if(vQuestion == null || vQuestion.type != g_type.CHOICE.id) {
            return null;
        }
        var secret = {
            question : vQuestion
        };
        var that = new g_ns.Base(secret),
            m_question = secret.question,
            m_options = (function(){
                var attrs = {
                    hasOther : m_question.optSet.hasOtherOption
                };
                NUI.Util.ObjectService.annex(attrs, m_question.optSet.constrain);
                NUI.Util.ObjectService.annex(attrs, m_question.style);
                if(vAnswer && vAnswer.type == g_type.CHOICE.id) {
                    attrs.initIndexes = vAnswer.answers;
                    attrs.initOtherValue = vAnswer.other;
                }
                if(vAttribute && vAttribute.openRandom) {
                    attrs.random = m_question.style.isRandom;
                }
                return g_input.Options(m_question.optSet.options, null, attrs);
            })();
            
        m_options.appendTo(that.getOptConDom());
        
        NUI.Util.ObjectService.annex(that, {
            /**
             * Get the option dom object
             */
            getOptionDom : function(vIndex) {
                return m_options.getOptDivDom(vIndex);
            },
            
            /**
             * Set the function to execute when click on the checkbox
             * @param vFunc(vOptIndexes, vOtherValue) {function}
             */
            setOptEventHandler : function(vFunc) {
                m_options.resetEvent(vFunc);
            }
        });
        return that;
    };
})();

/**
 * Matrix choice question
 * @class NUI.Quill.Render.Question.Matrix
 * @param vQuestion {object}. NUI.Quill.Entity.Question.*
 * @param vAnswer {object}. NUI.Quill.Entity.Answer.*
 */
NUI.Quill.Render.Question.Matrix = (function() {
    var g_dom = NUI.Util.DomService,
        g_ns = NUI.Quill.Render.Question,
        g_type = NUI.Quill.Enum.QuestionType,
        g_input = NUI.Widget.Input;
    
    return function(vQuestion, vAnswer) {
        if(vQuestion == null || vQuestion.type != g_type.MATRIX.id) {
            return null;
        }
        var secret = {
            question : vQuestion
        };
        var that = new g_ns.Base(secret),
            m_question = secret.question,
            m_options = (function(){
                var rs = m_question.rows,
                    cs = m_question.cols,
                    attrs = {
                        rmin : cs.constrain.min,
                        rmax : cs.constrain.max,
                        cmin : rs.constrain.min,
                        cmax : rs.constrain.max,
                        rhasOther : rs.hasOtherOption,
                        chasOther : cs.hasOtherOption
                    };
                if(vAnswer && vAnswer.type == g_type.MATRIX.id) {
                    attrs.initIndexes = vAnswer.answers;
                    attrs.initRowOtherValue = vAnswer.rowOther;
                    attrs.initColOtherValue = vAnswer.colOther;
                }
                return g_input.Matrix(rs.options, cs.options, null, attrs);
            })();
            
        m_options.appendTo(that.getOptConDom());
        
        NUI.Util.ObjectService.annex(that, {
            /**
             * Get the option dom object
             */
            getRowOptionDom : function(vIndex) {
                return m_options.getRoptDivDom(vIndex);
            },
            getColOptionDom : function(vIndex) {
                return m_options.getCoptDivDom(vIndex);
            },
            
            /**
             * Set the function to execute when click on the checkbox
             * @param vFunc(vOptIndexes, vRotherValue, vCotherValue) {function}
             */
            setOptEventHandler : function(vFunc) {
                m_options.resetEvent(vFunc);
            }
        });
        return that;
    };
})();

/**
 * Text input question
 * @class NUI.Quill.Render.Question.Input
 * @param vQuestion {object}. NUI.Quill.Entity.Question.*
 * @param vAnswer {object}. NUI.Quill.Entity.Answer.*
 */
NUI.Quill.Render.Question.Input = (function() {
    var g_dom = NUI.Util.DomService,
        g_ns = NUI.Quill.Render.Question,
        g_type = NUI.Quill.Enum.QuestionType,
        g_input = NUI.Widget.Input,
        g_inputType = NUI.Widget.Input.TextInputType,
        g_optType = NUI.Quill.Enum.InputOptionType;
    
    return function(vQuestion, vAnswer) {
        if(vQuestion == null || vQuestion.type != g_type.INPUT.id) {
            return null;
        }
            
        var secret = {
            question : vQuestion
        };
        var that = new g_ns.Base(secret),
            m_question = secret.question,
            m_inputs = [],
            m_texts = [];
        (function() {
            var frame = that.getFrameDom(),
                retval = [],
                mask = m_question.optTypeMask,
                len = mask.length,
                texts = m_question.texts,
                tIdx = 0,
                inputs = m_question.inputs,
                iIdx = 0;
            for(var i=0; i<len; i++) {
                var optDom = null;
                if(mask[i] == g_optType.TEXT) {
                    optDom = g_dom.createNode("div", {
                        style : {
                            display : "inline"
                        }
                    });
                    g_dom.setInnerHTML(optDom, texts[tIdx]);
                    g_dom.appendNode(frame, optDom);
                    m_texts[tIdx] = optDom;
                    tIdx ++;
                } else if(mask[i] == g_optType.INPUT) {
                    var type = null,
                        typeId = inputs[iIdx].type;
                    NUI.Util.ObjectService.searchObject(g_inputType, function(vName) {
                        if(g_inputType[vName].id == typeId) {
                            type = g_inputType[vName];
                            return true;
                        }
                        return false;
                    });
                    if(type == null) {
                        return;
                    }
                    var value = (function() {
                        var retval = "";
                        if(vAnswer && vAnswer.type == g_type.INPUT.id && vAnswer.answers[iIdx] != null) {
                            retval = vAnswer.answers[iIdx];
                        }
                        return retval;
                    })();
                    optDom = g_input.TextInput(type, inputs[iIdx].min, inputs[iIdx].max, null, {
                        initValue : value
                    });
                    optDom.appendTo(frame);
                    m_inputs[iIdx] = optDom;
                    iIdx ++;
                }
            }
        })();
        
        // hide the caption dom
        g_dom.hide(that.getCaptionDom());
        
        NUI.Util.ObjectService.annex(that, {
            /**
             * Get the text dom object
             */
            getOptionDom : function(vType, vIndex) {
                var mask = m_question.optTypeMask,
                    retval = null;
                if(vType == g_optType.TEXT) {
                    retval = m_texts[vIndex];
                } else if(vType == g_optType.INPUT) {
                    retval = m_inputs[vIndex];
                }
                return retval;
            },
            
            /**
             * Set the function to execute when the input blur
             * @param vIndex {int} The index of the input
             * @param vFunc(vValue) {function{string|int|float}}
             */
            setInputBlurEventHandler : function(vIndex, vFunc) {
                if(!m_inputs.isIndexLegal(vIndex)) {
                    return;
                }
                m_inputs[vIndex].resetEvent(vFunc);
            }
        });
        return that;
    };
})();

/**
 * Rank question
 * @class NUI.Quill.Render.Question.Rank
 * @param vQuestion {object}. NUI.Quill.Entity.Question.*
 * @param vAnswer {object}. NUI.Quill.Entity.Answer.*
 */
NUI.Quill.Render.Question.Rank = (function() {
    var g_dom = NUI.Util.DomService,
        g_ns = NUI.Quill.Render.Question,
        g_type = NUI.Quill.Enum.QuestionType,
        g_input = NUI.Widget.Input,
        g_incrChar = NUI.Util.StringService.increaseChar,
        g_sb = NUI.Util.StringService.StringBuilder;
        
    return function(vQuestion, vAnswer) {
        if(vQuestion == null || vQuestion.type != g_type.RANK.id) {
            return null;
        }
        var secret = {
            question : vQuestion
        };
        var that = new g_ns.Base(secret),
            m_question = secret.question,
            m_options = (function() {
                var optCon = that.getOptConDom(),
                    retval = [],
                    opts = m_question.options,
                    len = opts.length,
                    tagTmplt = (function() {
                        var sb = new g_sb();
                        sb.append(
                            "<span style=\"position:absolute; top:0px; left:-5px; text-align:center;",
                            "width:16px; height:16px; background:#ccc; color:#fff;\">{TEXT}</span>"
                        );
                        return sb.toString();
                    })();
                for(var i=0; i<len; i++) {
                    var opt = opts[i],
                        optDom = null;
                    var itemDom = g_dom.createNode("div", {
                        style : {
                            position : "relative",
                            padding : "0 0 0 11px",
                            margin : "5px"
                        }
                    });
                    g_dom.appendNode(optCon, itemDom);
                    g_dom.setInnerHTML(itemDom, tagTmplt.supplant({
                        TEXT : g_incrChar("A", i)
                    }));
                    var value = (function() {
                        var retval = 0;
                        if(vAnswer && vAnswer.type == g_type.RANK.id && vAnswer.answers[i] != null) {
                            retval = vAnswer.answers[i];
                        }
                        return retval;
                    })();
                    optDom = g_input.RankBar(opt.value, null, {
                        type : opt.type,
                        count : opt.count,
                        initValue : value
                    });
                    optDom.appendTo(itemDom);
                    retval[retval.length] = optDom;
                }
                return retval;
            })();

        NUI.Util.ObjectService.annex(that, {
            /**
             * Get the option dom object
             */
            getOptionDom : function(vIndex) {
                if(!m_options.isIndexLegal(vIndex)) {
                    return null;
                }
                return m_options[vIndex].getLabelDom();
            },
            
            /**
             * Set the function to execute when click on the rank icon
             * @param vIndex {int} The index of the options
             * @param vFunc(vValue) {function{int}}
             */
            setOptEventHandler : function(vIndex, vFunc) {
                if(!m_options.isIndexLegal(vIndex)) {
                    return;
                }
                m_options[vIndex].resetEvent(vFunc);
            }
        });
        return that;
    };
})();

/**
 * Sort question
 * @class NUI.Quill.Render.Question.Sort
 * @param vQuestion {object}. NUI.Quill.Entity.Question.*
 * @param vAnswer {object}. NUI.Quill.Entity.Answer.*
 */
NUI.Quill.Render.Question.Sort = (function() {
    var g_dom = NUI.Util.DomService,
        g_ns = NUI.Quill.Render.Question,
        g_type = NUI.Quill.Enum.QuestionType,
        g_input = NUI.Widget.Input;
        
    return function(vQuestion, vAnswer) {
        if(vQuestion == null || vQuestion.type != g_type.SORT.id) {
            return null;
        }
        var secret = {
            question : vQuestion
        };
        var that = new g_ns.Base(secret),
            m_question = secret.question,
            m_options = (function(){
                var value = null;
                if(vAnswer && vAnswer.type == g_type.SORT.id) {
                    value = vAnswer.answers;
                }
                return g_input.SortPanel(m_question.options, null, {
                    column : m_question.style.column,
                    initValue : value
                });
            })();
            
        m_options.appendTo(that.getOptConDom());
        
        NUI.Util.ObjectService.annex(that, {
            /**
             * Get the option dom object
             */
            getOptionDom : function(vIndex) {
                return m_options.getOptDivDom(vIndex);
            },
            
            /**
             * Set the function to execute when click on the checkbox
             * @param vFunc(vOptIndexes) {function}
             */
            setOptEventHandler : function(vFunc) {
                m_options.resetEvent(vFunc);
            }
        });
        return that;
    };
})();

/**
 * Const sum question
 * @class NUI.Quill.Render.Question.ConstSum
 * @param vQuestion {object}. NUI.Quill.Entity.Question.*
 * @param vAnswer {object}. NUI.Quill.Entity.Answer.*
 */
NUI.Quill.Render.Question.ConstSum = (function() {
    var g_dom = NUI.Util.DomService,
        g_ns = NUI.Quill.Render.Question,
        g_type = NUI.Quill.Enum.QuestionType,
        g_input = NUI.Widget.Input;
    
    return function(vQuestion, vAnswer) {
        if(vQuestion == null || vQuestion.type != g_type.CONSTSUM.id) {
            return null;
        }
        var secret = {
            question : vQuestion
        };
        var that = new g_ns.Base(secret),
            m_question = secret.question,
            m_options = (function(){
                var value = null;
                if(vAnswer && vAnswer.type == g_type.CONSTSUM.id) {
                    value = vAnswer.answers;
                }
                return g_input.ConstBar(m_question.options, null, {
                    type : m_question.color, 
                    arrange : m_question.arrange,
                    initValue : value
                });
            })();
            
        m_options.appendTo(that.getOptConDom());
        
        NUI.Util.ObjectService.annex(that, {
            /**
             * Get the option dom object
             */
            getOptionDom : function(vIndex) {
                return m_options.getOptDivDom(vIndex);
            },
            
            /**
             * Set the function to execute when slide the const bar
             * @param vFunc(vResult) {function}
             */
            setOptEventHandler : function(vFunc) {
                m_options.resetEvent(vFunc);
            }
        });
        return that;
    };
})();

/**
 * Location question
 * @class NUI.Quill.Render.Question.Location
 * @param vQuestion {object}. NUI.Quill.Entity.Question.*
 * @param vAnswer {object}. NUI.Quill.Entity.Answer.*
 */
NUI.Quill.Render.Question.Location = (function() {
    var g_dom = NUI.Util.DomService,
        g_ns = NUI.Quill.Render.Question,
        g_type = NUI.Quill.Enum.QuestionType,
        g_input = NUI.Widget.Input;
    
    return function(vQuestion, vAnswer) {
        if(vQuestion == null || vQuestion.type != g_type.LOCATION.id) {
            return null;
        }
        var secret = {
            question : vQuestion
        };
        var that = new g_ns.Base(secret),
            m_question = secret.question,
            m_options = (function(){
                var v = null;
                if(vAnswer && vAnswer.answers && vAnswer.answers.length > 0) {
                    v = vAnswer.answers[0];
                }
                var locationInput = new g_input.Location(function() {}, {
                    initValue : v,
                    isMultipleCity : (m_question.constrain.min!=1 || m_question.constrain.max!=1)
                });
                return locationInput;
            })();
            
        m_options.appendTo(that.getOptConDom());
        
        NUI.Util.ObjectService.annex(that, {
            /**
             * Set the function to execute when click on the checkbox
             * @param vFunc(vOptIndexes, vOtherValue) {function}
             */
            setOptEventHandler : function(vFunc) {
                m_options.resetEvent(vFunc);
            }
        });
        return that;
    };
})();

/**
 * MatrixInput choice question
 * @class NUI.Quill.Render.Question.MatrixInput
 * @param vQuestion {object}. NUI.Quill.Entity.Question.*
 * @param vAnswer {object}. NUI.Quill.Entity.Answer.*
 */
NUI.Quill.Render.Question.MatrixInput = (function() {
    var g_dom = NUI.Util.DomService,
        g_ns = NUI.Quill.Render.Question,
        g_type = NUI.Quill.Enum.QuestionType,
        g_input = NUI.Widget.Input;
    
    return function(vQuestion, vAnswer) {
        if(vQuestion == null || vQuestion.type != g_type.MATRIXINPUT.id) {
            return null;
        }
        var secret = {
            question : vQuestion
        };
        var that = new g_ns.Base(secret),
            m_question = secret.question,
            m_options = (function(){
                var rs = m_question.rows,
                    cs = m_question.cols,
                    attrs = {
                        rhasOther : rs.hasOtherOption,
                        chasOther : cs.hasOtherOption
                    };
                if(vAnswer && vAnswer.type == g_type.MATRIXINPUT.id) {
                    attrs.initValues = vAnswer.answers;
                    attrs.initRowOtherValue = vAnswer.rowOther;
                    attrs.initColOtherValue = vAnswer.colOther;
                }
                return g_input.MatrixInput(rs.options, cs.options, null, attrs);
            })();
            
        m_options.appendTo(that.getOptConDom());
        
        NUI.Util.ObjectService.annex(that, {
            /**
             * Get the option dom object
             */
            getRowOptionDom : function(vIndex) {
                return m_options.getRoptDivDom(vIndex);
            },
            getColOptionDom : function(vIndex) {
                return m_options.getCoptDivDom(vIndex);
            },
            
            /**
             * Set the function to execute when click on the checkbox
             * @param vFunc(vOptIndexes, vRotherValue, vCotherValue) {function}
             */
            setOptEventHandler : function(vFunc) {
                m_options.resetEvent(vFunc);
            }
        });
        return that;
    };
})();

