﻿//<using>
//  nui/nui.js
//  nui/prototype.js
//  nui/lang.js
//  nui/quill/processor/processor.js
//  nui/quill/entity/*
//  nui/quill/proxy.js
//</using>

/**
 * The namespace of answer processor used in netranking.cn 
 * @namespace NUI.Quill.Processor.Answer
 */
NUI.Quill.Processor.Answer = {
    getAnswerPrcs : function(vQuestion, vAnswer) {},
    Base : function(vSecret) {},
    Choice : function(vQuestion, vAnswer) {},
    Matrix : function(vQuestion, vAnswer) {},
    Input : function(vQuestion, vAnswer) {},
    Rank : function(vQuestion, vAnswer) {},
    Sort : function(vQuestion, vAnswer) {},
    ConstSum : function(vQuestion, vAnswer) {},
    MatrixInput : function(vQuestion, vAnswer) {}
};

/**
 * Get a question's Answer
 * @param vQuestion {object}. The entity of the question
 */
NUI.Quill.Processor.Answer.getAnswerPrcs = function(vQuestion, vAnswer) {
    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.Processor.Answer[typeValue](vQuestion, vAnswer);
};

/**
 * The base class of all kinds of answer Processors.
 * @class NUI.Quill.Processor.Answer.Base
 * @param vSecret {object} 
 *      vSecret = {
 *          entity : {object},  // NUI.Quill.Entity.*
 *      }
 */
NUI.Quill.Processor.Answer.Base = (function() {
    var g_answer = NUI.Quill.Entity.Answer,
        g_question = NUI.Quill.Entity.Question,
        g_ns = NUI.Quill.Processor.Answer,
        g_lang = NUI.Lang,
        g_enum = NUI.Quill.Enum;
    
    return function(vSecret) {
        var m_secret = vSecret || {};
        var m_question = m_secret.question || g_question["Base"](),
            m_answer = (function() {
                if(m_secret.answer && m_secret.answer.type == m_secret.question.type) {// todo : check more
                    return m_secret.answer;
                }
                var type = m_secret.question.type,
                    typeValue = null,
                    qType = g_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 g_answer[typeValue](m_secret.question);
            })();
            
        NUI.Util.ObjectService.annex(m_secret, {
            question : m_question,
            answer : m_answer
        });
        
        var that = {
            /**
             * Set the answer's value
             * @param vAnswers {array}.
             */
            setAnswer : function(vAnswers) {
                if(g_lang.isArray(vAnswers)) {
                    m_secret.answer.answers = NUI.Util.ObjectService.clone(vAnswers);
                    return true;
                }
                return false;
            },
            
            /**
             * update the answer of an input
             * @param vAnswerIndex {int}. The index of the answer item
             * @param vAnswer {string | number}. The value of the answer item
             */
            updateAnswer : function(vAnswerIndex, vAnswer) {
                if(!m_secret.answer.answers.isIndexLegal(vAnswerIndex) || vAnswer == null) {
                    return false;
                }
                m_secret.answer.answers[vAnswerIndex] = vAnswer;
                return true;
            },
            
            /**
             * Check whether the answer is legal or not
             * IMPORTANT : This method should be overrided by the inherit classes
             */
            check : function() {
                return "";
            },
            
            /**
             * Save the answer
             * @param vFunc(vIsSuccess) {function}. The function to execute after saving
             */
            save : function(vSurveyId, vFunc) {
                NUI.Quill.Proxy.Answer.saveAnswer(vSurveyId, m_question.id, m_answer, function(vIsSuccess) {
                    vFunc(vIsSuccess);
                });
            },
            
            getAnswer : function() {
                if(m_answer == null) {
                    return null;
                }
                return NUI.Util.ObjectService.clone(m_answer);
            }
        };
        
        return that;
    };
})();

/**
 * The class of choice question's answer processor.
 * @class NUI.Quill.Processor.Answer.Choice
 * @param vQuestion {object}. The entity of the choice question
 * @param vAnswer {object}. The init answer of the question
 */
NUI.Quill.Processor.Answer.Choice = (function() {
    var g_lang = NUI.Lang,
        g_ns = NUI.Quill.Processor.Answer,
        g_type = NUI.Quill.Enum.QuestionType;
    
    return function(vQuestion, vAnswer) {
        if(vQuestion == null || !(g_type.CHOICE.id == vQuestion.type)) {
            return null;
        }
            
        var m_secret = {
            question : vQuestion,
            answer : vAnswer
        };
        var that = new g_ns.Base(m_secret),
            m_question = m_secret.question,
            m_answer = m_secret.answer;
            
        NUI.Util.ObjectService.annex(that, {
            /**
             * Set the other value of the answer
             * @param vOtherValue {string}. The "other option"'s value
             */
            setOther : function(vOtherValue) {
                if(vOtherValue != null && g_lang.isString(vOtherValue)) {
                    m_answer.other = vOtherValue;
                    return true;
                }
                return false;
            },
            
            /**
             * Check if the answer is legal or not
             * @return {string}. The error message
             */
            check : function() {
                if(m_answer.answers == null) {
                    return "答案不能为空";
                }
                var ans = m_answer.answers,
                    optLen = m_question.optSet.options.length,
                    ansLen = m_question.optSet.hasOtherOption ? (optLen + 1) : optLen;
                if(ans.length != ansLen){
                    return "答案与选项无法对应";
                }
                var count = 0;
                for(var i=0; i<ansLen; i++) {
                    if(ans[i] > 0) {
                        count ++;
                    }
                }
                if(count < m_question.optSet.constrain.min){
                    return "请至少选择" + m_question.optSet.constrain.min + "个选项";
                }
                if(count > m_question.optSet.constrain.max){
                    return "请最多选择" + m_question.optSet.constrain.max + "个选项";
                }
                return "";
            }
        });
        return that;
    };
})();

/**
 * The class of Matrix question's answer processor.
 * @class NUI.Quill.Processor.Answer.Matrix
 * @param vQuestion {object}. The entity of the Matrix question
 * @param vAnswer {object}. The init answer of the question
 */
NUI.Quill.Processor.Answer.Matrix = (function() {
    var g_lang = NUI.Lang,
        g_ns = NUI.Quill.Processor.Answer,
        g_type = NUI.Quill.Enum.QuestionType;
    
    return function(vQuestion, vAnswer) {
        if(vQuestion == null || !(g_type.MATRIX.id == vQuestion.type)) {
            return null;
        }
            
        var m_secret = {
            question : vQuestion,
            answer : vAnswer
        };
        var that = new g_ns.Base(m_secret),
            m_question = m_secret.question,
            m_answer = m_secret.answer;
            
        NUI.Util.ObjectService.annex(that, {
            /**
             * Set the other value of the row
             * @param vOtherValue {string}. The "other option"'s value
             */
            setRowOther : function(vOtherValue) {
                if(vOtherValue != null && g_lang.isString(vOtherValue)) {
                    m_answer.rowOther = vOtherValue;
                    return true;
                }
                return false;
            },
            
            /**
             * Set the other value of the row
             * @param vOtherValue {string}. The "other option"'s value
             */
            setColOther : function(vOtherValue) {
                if(vOtherValue != null && g_lang.isString(vOtherValue)) {
                    m_answer.colOther = vOtherValue;
                    return true;
                }
                return false;
            },
            
            /**
             * Check if the answer is legal or not
             * @return {string}. The error message
             */
            check : function() {
                if(m_answer.answers == null) {
                    return "答案不能为空";
                }
                var rowAns = m_answer.answers,
                    rowOptLen = m_question.rows.options.length,
                    colOptLen = m_question.cols.options.length,
                    rowAnsLen = m_question.rows.hasOtherOption ? (rowOptLen + 1) : rowOptLen,
                    colAnsLen = m_question.cols.hasOtherOption ? (colOptLen + 1) : colOptLen;
                if(rowAns.length !=  rowAnsLen) {
                    return "答案行数与选项行数无法对应";
                }
                // check row
                function _ckrow(vRowIndex) {
                    var colAns = rowAns[vRowIndex],
                        prex = "第" + (vRowIndex+1) + "行";
                    if(colAns == null) {
                        return prex + "答案不能为空";
                    }
                    if(colAns.length != colAnsLen) {
                        return prex + "答案列数与选项列数无法对应";
                    }
                    var count = 0;
                    for(var c=0; c<colAnsLen; c++) {
                        if(colAns[c] > 0) {
                            count ++;
                        }
                    }
                    if(count < m_question.cols.constrain.min){
                        return prex + "至少选择" + m_question.cols.constrain.min + "个选项";
                    }
                    if(count > m_question.cols.constrain.max){
                        return prex + "最多选择" + m_question.cols.constrain.max + "个选项";
                    }
                    return "";
                }
                var r_count = ( m_question.rows.hasOtherOption ? (rowAnsLen - 1) : rowAnsLen);
                for(var r=0; r < r_count; r++) {
                    var ckmsg = _ckrow(r);
                    if(ckmsg != "") {
                        return ckmsg;
                    }
                }
                // check col
                function _ckcol(vColIndex) {
                    var prex = "第" + (vColIndex+1) + "列",
                        count = 0;
                    for(var r=0; r<rowAnsLen; r++) {
                        if(rowAns[r][vColIndex] > 0) {
                            count ++;
                        }
                    }
                    if(count < m_question.rows.constrain.min){
                        return prex + "至少选择" + m_question.rows.constrain.min + "个选项";
                    }
                    if(count > m_question.rows.constrain.max){
                        return prex + "最多选择" + m_question.rows.constrain.max + "个选项";
                    }
                    return "";
                }
                var c_count = ( m_question.cols.hasOtherOption ? (colAnsLen - 1) : colAnsLen);
                for(var c=0; c<c_count; c++) {
                    var ckmsg = _ckcol(c);
                    if(ckmsg != "") {
                        return ckmsg;
                    }
                }
                return "";
            }
        });
        return that;
    };
})();

/**
 * The class of Input question's answer processor.
 * @class NUI.Quill.Processor.Answer.Input
 * @param vQuestion {object}. The entity of the Input question
 * @param vAnswer {object}. The init answer of the question
 */
NUI.Quill.Processor.Answer.Input = (function() {
    var g_lang = NUI.Lang,
        g_ns = NUI.Quill.Processor.Answer,
        g_type = NUI.Quill.Enum.QuestionType;
    
    return function(vQuestion, vAnswer) {
        if(vQuestion == null || !(g_type.INPUT.id == vQuestion.type)) {
            return null;
        }
            
        var m_secret = {
            question : vQuestion,
            answer : vAnswer
        };
        var that = new g_ns.Base(m_secret),
            m_question = m_secret.question,
            m_answer = m_secret.answer;
            
        NUI.Util.ObjectService.annex(that, {
            /**
             * Check if the answer is legal or not
             * @return {string}. The error message
             */
            check : function() {
                if(m_answer.answers == null) {
                    return "答案不能为空";
                }
                var types = NUI.Widget.Input.TextInputType;
                var ans = m_answer.answers,
                    count = ans.length,
                    inputs = m_question.inputs;
                if(count != inputs.length){
                    return "答案个数和输入框个数不等";
                }
                for(var i=0; i<count; i++) {
                    if(inputs[i] == null) {
                        continue;
                    }
                    var prex = "第" + (i+1) + "个输入框",
                        min = inputs[i].min,
                        max = inputs[i].max;
                    switch(inputs[i].type) {
                        case types.STRING.id :
                            if(ans[i] == null) {
                                return prex + "需要填写";
                            }
                            var value = ans[i].length;
                            if(value < min) {
                                return prex + "输入字符串长度必须大于" + min;
                            } else if(value > max) {
                                return prex + "输入字符串长度必须小于" + max;
                            }
                            break;
                        case types.INT.id :
                            var value = parseInt(ans[i], 10);
                            if(isNaN(value)) {
                                return prex + "必须输入整数";
                            } else if(value < min) {
                                return prex + "输入整数必须大于" + min;
                            } else if(value > max) {
                                return prex + "输入整数必须小于" + max;
                            }
                            break;
                        case types.FLOAT.id :
                            var value = parseFloat(ans[i]);
                            if(isNaN(value)) {
                                return prex + "必须输入小数";
                            } else if(value < min) {
                                return prex + "输入数值必须大于" + min;
                            } else if(value > max) {
                                return prex + "输入数值必须小于" + max;
                            }
                            break;
                        case types.EMAIL.id :
                            if(ans[i] == null) {
                                return prex + "需要填写";
                            }
                            var value = ans[i];
                            if(value == null) {
                                return "输入值不能为空";
                            } else {
                                var checkMail = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
                                if(!checkMail.test(value)) {
                                    return "邮箱地址不合法";
                                }
                            }
                            break;
                    }
                }
                return "";
            }
        });
        return that;
    };
})();

/**
 * The class of Rank question's answer processor.
 * @class NUI.Quill.Processor.Answer.Rank
 * @param vQuestion {object}. The entity of the Rank question
 * @param vAnswer {object}. The init answer of the question
 */
NUI.Quill.Processor.Answer.Rank = (function() {
    var g_lang = NUI.Lang,
        g_ns = NUI.Quill.Processor.Answer,
        g_type = NUI.Quill.Enum.QuestionType;
    
    return function(vQuestion, vAnswer) {
        if(vQuestion == null || !(g_type.RANK.id == vQuestion.type)) {
            return null;
        }
            
        var m_secret = {
            question : vQuestion,
            answer : vAnswer
        };
        var that = new g_ns.Base(m_secret),
            m_question = m_secret.question,
            m_answer = m_secret.answer;
            
        NUI.Util.ObjectService.annex(that, {
            /**
             * Check if the answer is legal or not
             * @return {string}. The error message
             */
            check : function() {
                if(m_answer.answers == null) {
                    return "答案不能为空";
                }
                var ans = m_answer.answers,
                    count = ans.length,
                    opts = m_question.options;
                if(count != opts.length){
                    return "答案个数和选项个数不等";
                }
                for(var i=0; i<count; i++) {
                    if(opts[i] == null) {
                        continue;
                    }
                    var prex = "第" + (i+1) + "个选项";
                    if(ans[i] <= 0) {
                        return "请给" + prex + "评分";
                    }
                    if(ans[i] > opts[i].count) {
                        return prex + "评分超出最大值";
                    }
                }
                return "";
            }
        });
        return that;
    };
})();

/**
 * The class of Sort question's answer processor.
 * @class NUI.Quill.Processor.Answer.Sort
 * @param vQuestion {object}. The entity of the Sort question
 * @param vAnswer {object}. The init answer of the question
 */
NUI.Quill.Processor.Answer.Sort = (function() {
    var g_lang = NUI.Lang,
        g_ns = NUI.Quill.Processor.Answer,
        g_type = NUI.Quill.Enum.QuestionType;
    
    return function(vQuestion, vAnswer) {
        if(vQuestion == null || !(g_type.SORT.id == vQuestion.type)) {
            return null;
        }
            
        var m_secret = {
            question : vQuestion,
            answer : vAnswer
        };
        var that = new g_ns.Base(m_secret),
            m_question = m_secret.question,
            m_answer = m_secret.answer;
            
        NUI.Util.ObjectService.annex(that, {
            /**
             * Check if the answer is legal or not
             * @return {string}. The error message
             */
            check : function() {
                if(m_answer.answers == null) {
                    return "答案不能为空";
                }
                var ans = m_answer.answers,
                    count = ans.length,
                    opts = m_question.options;
                if(count != opts.length){
                    return "答案个数和选项个数不等";
                }
                for(var i=0; i<count; i++) {
                    var prex = "第" + (i+1) + "个选项";
                    if(ans[i] < 0) {
                        return "请给" + prex + "排序";
                    }
                }
                return "";
            }
        });
        return that;
    };
})();

/**
 * The class of ConstSum question's answer processor.
 * @class NUI.Quill.Processor.Answer.ConstSum
 * @param vQuestion {object}. The entity of the ConstSum question
 * @param vAnswer {object}. The init answer of the question
 */
NUI.Quill.Processor.Answer.ConstSum = (function() {
    var g_lang = NUI.Lang,
        g_ns = NUI.Quill.Processor.Answer,
        g_type = NUI.Quill.Enum.QuestionType;
    
    return function(vQuestion, vAnswer) {
        if(vQuestion == null || !(g_type.CONSTSUM.id == vQuestion.type)) {
            return null;
        }
            
        var m_secret = {
            question : vQuestion,
            answer : vAnswer
        };
        var that = new g_ns.Base(m_secret),
            m_question = m_secret.question,
            m_answer = m_secret.answer;
            
        NUI.Util.ObjectService.annex(that, {
            /**
             * Check if the answer is legal or not
             * @return {string}. The error message
             */
            check : function() {
                if(m_answer.answers == null) {
                    return "答案不能为空";
                }
                if(m_answer.answers.length != m_question.options.length){
                    return "答案个数和选项个数不等";
                }
                return "";
            }
        });
        return that;
    };
})();


/**
 * The class of Location question's answer processor.
 * @class NUI.Quill.Processor.Answer.Location
 * @param vQuestion {object}. The entity of the Location question
 * @param vAnswer {object}. The init answer of the question
 */
NUI.Quill.Processor.Answer.Location = (function() {
    var g_lang = NUI.Lang,
        g_ns = NUI.Quill.Processor.Answer,
        g_type = NUI.Quill.Enum.QuestionType;
    
    return function(vQuestion, vAnswer) {
        if(vQuestion == null || !(g_type.LOCATION.id == vQuestion.type)) {
            return null;
        }
            
        var m_secret = {
            question : vQuestion,
            answer : vAnswer
        };
        var that = new g_ns.Base(m_secret),
            m_question = m_secret.question,
            m_answer = m_secret.answer;
            
        NUI.Util.ObjectService.annex(that, {
            /**
             * Check if the answer is legal or not
             * @return {string}. The error message
             */
            check : function() {
                if(m_answer.answers == null) {
                    return "答案不能为空";
                }
                var count = m_answer.answers.length;
                if(count < m_question.constrain.min){
                    return "请至少选择" + m_question.constrain.min + "个地区";
                }
                if(count > m_question.constrain.max){
                    return "请最多选择" + m_question.constrain.max + "个地区";
                }
                for(var i=0; i<count; i++) {
                    if(m_answer.answers[i] == null || m_answer.answers[i].country==-2 || 
                        m_answer.answers[i].province==-2 || m_answer.answers[i].city==-2){
                        return "选择地区有误";
                    }
                }
                return "";
            }
        });
        return that;
    };
})();

/**
 * The class of MatrixInput question's answer processor.
 * @class NUI.Quill.Processor.Answer.MatrixInput
 * @param vQuestion {object}. The entity of the MatrixInput question
 * @param vAnswer {object}. The init answer of the question
 */
NUI.Quill.Processor.Answer.MatrixInput = (function() {
    var g_lang = NUI.Lang,
        g_ns = NUI.Quill.Processor.Answer,
        g_type = NUI.Quill.Enum.QuestionType;
    
    return function(vQuestion, vAnswer) {
        if(vQuestion == null || !(g_type.MATRIXINPUT.id == vQuestion.type)) {
            return null;
        }
            
        var m_secret = {
            question : vQuestion,
            answer : vAnswer
        };
        var that = new g_ns.Base(m_secret),
            m_question = m_secret.question,
            m_answer = m_secret.answer;
            
        NUI.Util.ObjectService.annex(that, {
            /**
             * Set the other value of the row
             * @param vOtherValue {string}. The "other option"'s value
             */
            setRowOther : function(vOtherValue) {
                if(vOtherValue != null && g_lang.isString(vOtherValue)) {
                    m_answer.rowOther = vOtherValue;
                    return true;
                }
                return false;
            },
            
            /**
             * Set the other value of the row
             * @param vOtherValue {string}. The "other option"'s value
             */
            setColOther : function(vOtherValue) {
                if(vOtherValue != null && g_lang.isString(vOtherValue)) {
                    m_answer.colOther = vOtherValue;
                    return true;
                }
                return false;
            },
            
            /**
             * Check if the answer is legal or not
             * @return {string}. The error message
             */
            check : function() {
                if(m_answer.answers == null) {
                    return "答案不能为空";
                }
                var rowAns = m_answer.answers,
                    rowOptLen = m_question.rows.options.length,
                    colOptLen = m_question.cols.options.length,
                    rowAnsLen = m_question.rows.hasOtherOption ? (rowOptLen + 1) : rowOptLen,
                    colAnsLen = m_question.cols.hasOtherOption ? (colOptLen + 1) : colOptLen;
                if(rowAns.length !=  rowAnsLen) {
                    return "答案行数与选项行数无法对应";
                }
                // check row
                function _ckrow(vRowIndex) {
                    var colAns = rowAns[vRowIndex],
                        prex = "第" + (vRowIndex+1) + "行";
                    if(colAns == null) {
                        return prex + "答案不能为空";
                    }
                    if(colAns.length != colAnsLen) {
                        return prex + "答案列数与选项列数无法对应";
                    }
                    return "";
                }
                var r_count = ( m_question.rows.hasOtherOption ? (rowAnsLen - 1) : rowAnsLen);
                for(var r=0; r < r_count; r++) {
                    var ckmsg = _ckrow(r);
                    if(ckmsg != "") {
                        return ckmsg;
                    }
                }
                // check col
                function _ckcol(vColIndex) {
                    return "";
                }
                var c_count = ( m_question.cols.hasOtherOption ? (colAnsLen - 1) : colAnsLen);
                for(var c=0; c<c_count; c++) {
                    var ckmsg = _ckcol(c);
                    if(ckmsg != "") {
                        return ckmsg;
                    }
                }
                return "";
            }
        });
        return that;
    };
})();

