(function (window, undefined) {
    //正则
    var xinQiWindow,
    //关键字（A、B、1、A：这种开头的选项，全部过滤掉）
        optionFilter = /^\b([a-z]|\d+)(:|\uff1a|\.|\u3001)/i,
    //一组数组，用于把索引转换为字母（标识题目选项）
    opArray = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];
    //对外开放的对象
    var document = window.document,
        jQuery = $ = window.jQuery,
        typeString = '[object Queue]',
    //一套工具函数——————————————————————————————
    //参数化拼接字符串，请参考C# string.format()方法
        stringformat = function () {
            if (arguments.length < 1 || !arguments[0]) return '';
            if (arguments.length === 1) return arguments[0] + '';
            //index索引对齐
            var result = arguments[0] + '', args = arguments, index = 1;
            //两个参数，第二个参数为数组
            if (arguments.length === 2 && arguments[1] instanceof Array) {
                args = arguments[1];
                index--;
            }
            for (var i = 0, len = args.length; i < len; i++, index++) {
                if (args[index] || args[index] == 0) {
                    var reg = new RegExp("{[" + i + "]}", "g");
                    result = result.replace(reg, args[index]);
                }
            }
            return result;
        },
        StringBuilder = function (initStr) {
            /// <summary>
            ///     1: StringBuffer对象，需要在page.initial()方法中初始化本对象数据
            ///     &#10;    1.1 - StringBuilder() - 初始化字符串拼接对象
            ///     &#10;    1.2 - StringBuilder(initStr) - 根据指定的字符串初始化字符串拼接对象
            /// </summary>
            /// <param name="initStr" type="String">
            ///     初始化字符串
            /// </param>
            /// <returns type="void" />
            this._strings = new Array();
            if (initStr) {
                this._strings[0] = initStr;
            }
            return this._strings.join('');
        };
    //初始化内部对象
    StringBuilder.prototype.append = function (str) {
        this._strings.push(str);
    }
    StringBuilder.prototype.toString = function () {
        return this._strings.join('');
    }
    //————————————————————工具模块end

    var templentQueObj = {//题目对象参数模板
        id: undefined,
        type: 0,
        title: undefined,
        dis: undefined,
        score: -1,
        option: [],
        answer: [],
        child: undefined,
        index: 0,
        html: undefined,
        source: undefined,
        queTag: undefined
    },
        typeList = {}, //表示题型集合，从0开始，暴露在window下
    templentQueType = {
        typeName: undefined,
        container: '<ul>{0}</ul>',
        title: '',
        option: '',
        dis: '<li class="op_Discription"><fieldset><legend>' + lgzhushi + '</legend><div>{0}</div></fieldset></li>',
        answer: '<li class="op_Result">' + lgdaan + '：<label class="question_Ttitle">{0}</label></li>',
        score: '',
        child: undefined,
        queTag: '<li class="op_Result">' + lgbaioqian + '：<label class="question_Ttitle">{0}</label></li>',   
        //默认的生成HTML
        toHTML: function (item) {
            var html = new StringBuilder(), typeObj = this;
            for (var i = 0, len = item.title.length; i < len; i++) {
                html.append(stringformat(typeObj.title, item.index, item.index + 1, item.title[i]));
            }
            for (var i = 0, len = item.option.length; i < len && len; i++) {
                html.append(stringformat(typeObj.option, i, item.index, item.option[i], opArray[i]));
            }
            for (var i = 0, len = item.answer.length; i < len && len; i++) {
                html.append(stringformat(typeObj.answer, item.answer[i]));
            }
            if (item.score) {
                var regPaixuCheck = /^[0-9]*$/; //题目分数
                if (!regPaixuCheck.test(item.score)) {
                    showTipsMsg(lgquefenshu);
                }
                html.append(stringformat(typeObj.score, item.score));
            }            
            if (item.queTag) {
                html.append(stringformat(typeObj.queTag, item.queTag));
            }
            if (item.dis) {
                html.append(stringformat(typeObj.dis, item.dis));
            }
            return stringformat(typeObj.container, html.toString());
        },
        //将一组HTML转换成题目对象
        //一定意义上的此法分析工具，该方法可以被重写
        //该方法可以优化出更强劲的词法分析
        toObj: function (textStr, id) {
            //编辑模式下id不为空，添加模式id为空
            var data, result, item, i = j = 0;
            if (!textStr) return;
            var arr = [], newQue = new Queue(); //分割后的每一道题的数组            
            var vvvv = new RegExp('\\n(\\s)+?\\n');
            var daan = textStr.match(vvvv);
            if (textStr.indexOf("\n\n") >= 0) {//多题
                if (id) return; //编辑题目的时候不允许产生多题
                arr = textStr.split(/\n\n/g);
            } else if (vvvv.test(textStr)) {
                if (id) return; //编辑题目的时候不允许产生多题
                arr = textStr.split(daan[0]);
            } else {//一题
                arr.push(textStr);
            }
            //多题
            while ((data = arr[i++]) !== undefined) {
                if (!data) continue;
                var obj = {
                    id: id,
                    type: this.typeName,
                    title: [],
                    dis: undefined,
                    score: 0,
                    option: [],
                    answer: [],
                    queTag: undefined,
                    source: function () {
                        return data.indexOf('\n') === 0 ? data.substring(1, data.length) : data;
                    } ()
                },
                    result = (data + '').indexOf("\n") >= 0 ? data.split(/\n/g) : [data],
                    index = -1;
                j = 0; //重置j
                while ((item = result[j++]) !== undefined) {
                    if (!item) continue;

                    //分解出题目
                    if (!item || !jQuery.trim(item)) continue;
                    if (item.indexOf(lgdaan + "：") >= 0 || item.indexOf(lgdaan + ":") >= 0) {
                        item = item.replace(/\s/g, "");
                        obj.answer.push(item.replace(lgdaan + "：", "").replace(lgdaan + ":", "")); //保存答案
                        continue;
                    }
                    if (item.indexOf(lgbaioqian+"：") >= 0 || item.indexOf(lgbaioqian+":") >= 0) {
                        obj.queTag = item.replace(lgbaioqian+"：", "").replace(lgbaioqian+":", ""); //标签
                        continue;
                    }
                    if (item.indexOf(lgzhushi + "：") >= 0 || item.indexOf(lgzhushi + ":") >= 0) {
                        obj.dis = item.replace(lgzhushi + "：", "").replace(lgzhushi + ":", ""); //注释
                        continue;
                    }

                    

                    if (item.indexOf(lgfenshu + "：") >= 0 || item.indexOf(lgfenshu + ":") >= 0) {
                        obj.score = item.replace(lgfenshu + "：", "").replace(lgfenshu + ":", ""); //注释
                        continue;
                    }
                    index++;
                    if (index === 0) {
                        obj.title.push(item.replace(optionFilter, '')); //将标题中的题号去掉
                    }
                    else {
                        if (item != null && item != "" && item != undefined) {
                            item = item.replace(/(^\s*)|(\s*$)/, "");
                            obj.option.push(item.replace(optionFilter, '')); //过滤A之类的东西
                        }
                    }
                }
                //添加到数组中
                newQue.add(new QueObj(obj));
            }
            return newQue;
        },
        //参数item表示被验证的对象, 返回false表示验证通过，否则返回验证不通过的警告字符串(或true)
        fnCheck: function (item, i) { return false; }
    };

    //——————————————————————————————

    //———————————————题目类型对象—————————————
    QueType = function (typeName, container, title, option, dis, answer, toHTML, toObj, fnCheck, child, queTag) {
        ///	<summary>
        //这个对象的作用是自定义和扩展题型，并将该题型的题目对象生成为HTML
        //每new一个新题型，自动追加到数组中，重复的typeName，将覆盖原题型
        //如果需要扩展题型，扩展这个对象即可
        //题目对象在本对象的模型下工作
        ///	</summary>
        ///	<returns type="string" />
        if (typeof (typeName) === 'object') {
            jQuery.extend(true, this, templentQueType, typeName);
            typeList[this.typeName] = this;
        } else {
            var temp = this;
            this.typeName = typeName;
            this.container = container;
            this.title = title;
            this.option = option;
            this.answer = answer;
            this.toHTML = toHTML;
            this.dis = dis;
            this.toObj = '';
            this.queTag = queTag;
            this.fnCheck = fnCheck;
            this.child;
            if (child.toString && child.toString() === typeString)
                this.child = child.toList();
            typeList[typeName] = this;
        }

    };

    //——————————————————————————————————

    //——————————————题目————————————————
    var QueObj = function (id, type, title, dis, score, option, answer, child, index, queTag) {
        ///	<summary>
        ///     题目对象
        ///	</summary>
        ///	<returns type="self" />
        if (typeof (id) === 'object') {//可以是一个对象
            jQuery.extend(true, this, templentQueObj, id);
        } else if (typeof (id) === 'string' && type && id.length != 36) {
            //可以是一组html，注意是简单的HTML,例如阅读题不允许这种形式
            if (typeList[type]) {
                return type instanceof QueType === true ? QueType.toObj(id) : typeList[type].toObj(id);
            }
        } else {
            //题目对象索引（自动维护）
            this.index = index || 0;
            this.id = id; //题目ID
            this.title = title; //题目title（允许为一个对象）
            this.dis = dis; //题目备注
            this.type = type; //题目类型
            this.queTag = queTag;
            this.score = typeof (score) === 'number' ? score > 0 ? score : -1 : -1; //题目分数
            this.answer = answer || []; //题目答案（数组）
            this.option = option || []; //题目选项（数组）
            this.child = child;
            //为了性能，这里没有调用toHTML()方法
            this.html;
        }
    };
    //将题目对象转换成HTML
    QueObj.prototype.toHTML = function () {
        ///	<summary>
        ///     将题目对象生成HTML
        ///	</summary>
        ///	<returns type="string" />
        var type = typeList[this.type];
        if (!type) return '';
        //根据题型生成
        if (this.type && type.toHTML)
            return type.toHTML(this);
        return '';
    };

    QueObj.prototype.check = function () {
        ///	<summary>
        //检查这个对象是否合法
        //这个check方法有点特殊，如果验证通过则返回false
        //否则返回验证失败后的警告字符串，即，true代表验证失败
        ///	</summary>
        ///	<returns type="string" />

        return typeList[this.type] ? typeList[this.type].fnCheck(this, this.index) : false;
    };

    QueObj.prototype.extend = function () {
        //类扩展（实例方法重载）
        if (arguments.length < 1) return;
        jQuery.extend(true, this, arguments);
    }

    QueObj.extend = function () {
        //类扩展（会被继承）
        if (arguments.length < 1) return;
        jQuery.extend(true, QueObj.prototype, arguments);
    };

    //——————————————————————————————————
    //题目集合
    var Queue = function () {
        var list = [],
            errorList, //错误对象
            self = {
                each: function () {
                    ///	<summary>
                    ///     循环Queue对象，并运行委托的一个方法
                    ///	</summary>
                    ///	<returns type="self" />

                    //循环题目集合并运行委托的函数Callback
                    //Callback的第一个参数是元素，第二个参数是索引
                    return Array.prototype.forEach ? function (fn) {//w3c
                        if (!jQuery.isFunction(fn)) return this;
                        list.forEach(function (item, i) {
                            fn.call(item, item, i);
                        });
                        return this;
                    } : function (fn) {//ie678
                        if (!jQuery.isFunction(fn)) return this;
                        for (var i = 0, len = list.length; i < len; i++) {
                            if (!list[i]) {
                                list.splice(i, 1);
                                continue;
                            }
                            fn.call(list[i], list[i], i);
                        }
                        return this;
                    };

                } (), //预编译
                add: function (obj) {
                    ///	<summary>
                    ///     根据图片对象和指定的参数按比例缩放图片
                    ///     &#10;1: resizeimg(obj, maxW, maxH) - 根据图片对象和指定的参数按比例缩放图片
                    ///	</summary>
                    ///	<param name="obj" type="ImageObject">图片对象</param>
                    ///	<param name="maxW" type="int">最大宽度</param>
                    ///	<param name="maxH" type="int">最大高度</param>
                    ///	<returns type="string" />
                    if (obj.toString && obj.toString() === typeString) {
                        obj.each(function (item) {
                            list.push(item);
                        });
                        return this;
                    }

                    if (!obj === QueObj) return this;
                    list.push(obj);
                    return this;
                },
                remove: function (index, count) {
                    ///	<summary>
                    ///     从Queue中移除一个题目对象
                    ///	</summary>
                    ///	<returns type="string" />
                    index = typeof (index) === 'number' ? index : 0;
                    count = typeof (index) === 'number' ? count : 0;
                    list.splice(index, count);
                    return this;
                },
                check: function () {
                    ///	<summary>
                    ///     检查题目对象是否通过验证，false表示验证通过，true表示验证不通过并且返回警告字符串
                    ///     该方法返回一个数组，里面包含了一组对象{key:错误对象索引,value:错误信息}
                    ///     如果数组长度为0，则表示严正通过，否则这个数组表示相关错误信息
                    ///	</summary>
                    ///	<returns type="Array" />
                    if (!this.length) return true;
                    var result;
                    errorList = [];
                    this.each(function (item, index) {
                        var result = item.check();
                        if (result) {
                            errorList.push({ key: index, value: result });
                            //alert(result);
                        }
                    });
                    return errorList;
                },
                length: function () {
                    ///	<summary>
                    ///     获取Queue对象长度
                    ///	</summary>
                    ///	<returns type="Int" />
                    return list.length;
                },
                toHTML: function (cache) {
                    ///	<summary>
                    ///     将集合对象生成HTML
                    ///	</summary>
                    ///	<param name="cache" type="boolean">是否使用缓存读取</param>
                    ///	<returns type="string" />
                    if (!list.length) return '';
                    var result = new StringBuilder();
                    this.each(function (item, index) {
                        //每次toHTML的时候都会修正索引（这个索引只是为了页面呈现）
                        item.index = index;
                        //优化性能，从cache里读取数据
                        result.append(item.html && cache ? item.html : (item.html = item.toHTML()));
                    });
                    return result.toString();
                },
                replace: function (index, newObj) {
                    ///	<summary>
                    ///     根据图片对象和指定的参数按比例缩放图片
                    ///     &#10;1: resizeimg(obj, maxW, maxH) - 根据图片对象和指定的参数按比例缩放图片
                    ///	</summary>
                    ///	<param name="obj" type="ImageObject">图片对象</param>
                    ///	<param name="maxW" type="int">最大宽度</param>
                    ///	<param name="maxH" type="int">最大高度</param>
                    ///	<returns type="string" />
                    if (!newObj || typeof (index) !== 'number') return this;
                    if (newObj instanceof QueObj)
                        list.splice(index, 1, newObj);
                    if (newObj.toString && newObj.toString() === typeString) {
                        newObj.each(function (item) {
                            list.splice(index, 1, item);
                        });
                    }
                    return this;
                },
                inQueue: function () {
                    ///	<summary>
                    ///     查找Queue中是否有对应的题目对象，并返回索引
                    ///     &#10;1: Queue.inQueue(obj) - 查找Queue中是否有对应的题目对象，并返回索引
                    ///	</summary>
                    ///	<param name="obj" type="ImageObject">要查找的题目对象</param>
                    ///	<returns type="string" />
                    if (!arguments.length) return -1;
                    for (var i in list) {
                        if (arguments[0] === list[i])
                            return i;
                    }
                    return -1;
                },
                child: function () {
                    ///	<summary>
                    ///     用于获取一个题目对象，或给题目对象覆盖深层的题目对象（子项）
                    ///     &#10;1: Queue.child() - 获取该题目集合的list
                    ///     &#10;2: Queue.child(index) - 获取该索引的题目对象
                    ///     &#10;3: Queue.child(index,QueObj[,...]) - 为该索引的题目覆盖，基于QueObj对象
                    ///     &#10;4: Queue.child(index,Queue) - 为该索引的题目覆盖子项，基于Queue（集合）对象
                    ///	</summary>
                    ///	<param name="index" type="ImageObject">要操作的题目对象的索引</param>
                    ///	<param name="Queobj" type="QueObj">题目对象</param>
                    ///	<param name="Queoue" type="Queue">题目集合对象</param>
                    ///	<returns type="string" />

                    //第一个参数表示对应的题目对象索引
                    //后面的参数（如果有的话），则把对象追加到该题目的子项中
                    var index = arguments[0],
                        i = 1,
                        length = arguments.length,
                        item = list[+(index || 0)],
                        obj;
                    if (!length) return list;
                    if (!item) return this;
                    if (length === i) return list[index];
                    for (; i < length; i++) {
                        obj = arguments[i];
                        if (item.child == null) {
                            item.child = new Queue();
                        }
                        item.child.add(obj);
                        //                        if (obj instanceof QueObj) {
                        //                            alert("qobj");
                        //                            item.child.add(obj);
                        //                        }
                        //                        else if (obj.toString && obj.toString() === typeString) {
                        //                           
                        //                        }
                        //                        else {
                        //                            //QueObj
                        //                            alert("qobj3" + obj.toString());
                        //                        }

                    }
                    return this;
                },
                insert: function (index, newObj) {
                    ///	<summary>
                    ///     将对象插入数组制定位置
                    ///	</summary>
                    if (!index || !newObj || typeof (index) !== 'number' || !newObj instanceof QueObj) return this;
                    list.splice(index, 0, newObj);
                },
                toString: function () {
                    return typeString;
                },
                toArray: function () {
                    ///	<summary>
                    ///     将Queue转换为原生数组
                    ///	</summary>
                    var _newList = list.slice(0);
                    this.each(function (item, i) {
                        if (item.child && item.child.lenght != 0 && _newList[i].child) {
                            //_newList[i].child = Array.prototype.slice.call(item.child, 0);
                            //_newList[i].child.push(item.child);

                            _newList[i].child = Array.prototype.slice.call(item.child.toArray(), 0);
                        }
                    });
                    return _newList;
                }
            };
        return self;
    };

    window._ = {};
    window._.Queue = Queue;
    window._.QueObj = QueObj;
    window._.QueType = QueType;
    window._.StringBuilder = StringBuilder;
    window._.stringformat = stringformat;
    window._.TypeList = typeList;
})(window);

