function MarkControl(option) {
    this.option = option;

    this.maxPrefetchCount = parseInt(option.prefetchCount);
    this.maxPrefetchCount = this.maxPrefetchCount != undefined && this.maxPrefetchCount > 2 ? this.maxPrefetchCount : 2;

    this.container = option.container;
    this.context = {
        imageServer: option.imageServer,
        staticServer: option.staticServer,
        isFinish: false,
        prefetching: false,
        prefetchTask: []
    };
    // 初始化容器结构
    this.initContainer();
    // 初始化事件监听
    this.initTriggers(option);
    // 初始化功能模块
    this.initModules(option);
    // 初始化成功回调方法
    // console.log('MarkControl init success!');
    // if (option.success != undefined && typeof(option.success) == 'function')
	// {
    // option.success();
    // }
}

MarkControl.prototype.initContainer = function() {
    var height = this.option.height;
    if (height == undefined) {
        height = $(window).height();
    }
    this.container = getDom(this.main_row_dom, this).appendTo(this.container);

    if (this.option.enableSidear != false) {
        this.container.sidebar = getDom(this.sidebar_dom, this).appendTo(this.container);
        this.container.sidebar.css('max-height', height);
    }
    this.container.center = getDom(this.center_dom, this).appendTo(this.container);
    this.container.header = getDom(this.center_header_dom, this).appendTo(this.container.center).find('.header');
    this.container.centerContainer = getDom(this.center_content_dom, this).appendTo(this.container.center);
    this.container.centerContent = this.container.centerContainer.find('.image-content');
    this.container.centerNavbar = this.container.centerContent.find('nav');
    this.container.centerList = [];
    this.navNumber = 0;

    this.container.height(height);
    this.container.centerContent.css('height', height - this.container.header.parent().height());

    this.initHeaderAndAssistant();
}

MarkControl.prototype.initHeaderAndAssistant = function() {
    var self = this;
    this.container.header.find('#mark-user-name').html(this.option.userName);
    if (this.option.logoutTitle != undefined) {
        this.container.header.find('#logout-title').html(this.option.logoutTitle);
    }
    this.container.header.find('#logout-link').click(function() {
        self.trigger('logout.link.click');
        return true;
    })

    this.container.assistant = getDom(this.assistant_dom, this).appendTo(this.container);
    this.container.assistant.positionSet = false;
    this.container.assistantButton = this.container.header.find('#assistant-button');

    this.container.assistantButton.click(this, function(event) {
        if (self.container.assistant.positionSet == false) {
            self.container.assistant.offset({
                top: self.container.assistantButton.position().top + self.container.assistantButton.height() + 5,
                left: self.container.assistantButton.position().left - 85
            });
            self.container.assistant.positionSet = true;
        }
        self.container.assistant.toggle();
    });

}

MarkControl.prototype.initMarkFunction = function() {
    var functionList = this.container.assistant.functionList;
    if (functionList == undefined) {
        functionList = getDom(this.mark_function_dom, this).appendTo(this.container.assistant).find('#function-list');
        this.container.assistant.functionList = functionList;
    }
}

MarkControl.prototype.addNavGroup = function(title, content){
    var self = this;
    self.navNumber++;
    var nav = $('<a href="#"><span>'+title+'</span></a>').appendTo(self.container.centerNavbar);
    nav.attr('data-number', self.navNumber);
    content.attr('data-number', self.navNumber);
    nav.click(function(){
        self.container.centerNavbar.find('a').removeClass('selected');
        $(this).addClass('selected');
        
        for(var i in self.container.centerList){
        	var dom = self.container.centerList[i];
        	if(dom.attr('data-number')==$(this).attr('data-number')){
        		dom.show();
        	}else{
        		dom.hide();
        	}
        }
    });
    self.container.centerList.push(content);
    return nav;
}

// 增加某个事件的监听方法
MarkControl.prototype.on = function(eventName, caller, callback, async) {
    if (eventName && callback && eventName.length > 0 && typeof(callback) == 'function') {
        if (async) {
            this.container.bind(eventName, callback);
        } else {
            if (this.triggers[eventName] == undefined) {
                this.triggers[eventName] = new Array();
            }
            this.triggers[eventName].push({
                caller: caller,
                callback: callback
            });
        }
    }
}

// 触发某个事件，并传递事件相关内容
MarkControl.prototype.trigger = function(eventName, eventObject) {
    var result = true;
    if (eventName && eventName.length > 0) {
        var array = this.triggers[eventName];
        if (array != undefined && array.length > 0) {
            var event = {
                name: eventName
            }
            for (var i in array) {
                result = result & array[i].callback.call(array[i].caller, event, this.context, eventObject);
            }
        }
        this.container.trigger(eventName, this.context, eventObject);
    }
    return result;
}

// 初始化事件监听
MarkControl.prototype.initTriggers = function(option) {
    if (this.triggers == undefined) {
        this.triggers = {};
    }
    if (option != undefined && option.on != undefined) {
        for (var name in option.on) {
            this.on(name, option.on[name]);
        }
    }

    var self = this;
    this.on('mark.sidebar.open', this, function(event, context, eventObject) {
        this.container.assistant.hide();
        if (this.container.center.hasClass('span12')) {
            this.container.center.removeClass('span12');
            this.container.center.addClass('span10');
        } else if (this.container.center.hasClass('span7')) {
            this.container.center.removeClass('span7');
            this.container.center.addClass('span5');
        }
        this.trigger('center.width.change');
    });
    this.on('mark.sidebar.close', this, function(event, context, eventObject) {
        this.container.assistant.hide();
        if (this.container.center.hasClass('span10')) {
            this.container.center.removeClass('span10');
            this.container.center.addClass('span12');
        } else if (this.container.center.hasClass('span5')) {
            this.container.center.removeClass('span5');
            this.container.center.addClass('span7');
        }
        this.trigger('center.width.change');
    });
    this.on('task.load.finish', this, function(event, context, eventObject) {
        self.container.centerNavbar.find('a:first').trigger('click');
    });
    this.on('task.get.finish', this, function(event, context, eventObject) {
        context.prefetchCallback = undefined;
    });
    this.on('task.get.none', this, function(event, context, eventObject) {
        self.getStatus();
        if (context.task == undefined && self.option.clearUrl != undefined) {
            $.post(self.option.clearUrl, {}, function() {});
        }
        context.prefetchCallback = function() {
            context.prefetchCallback = undefined;
            if (self.context.task == undefined && self.context.prefetchTask.length > 0) {
                self.getTask();
            }
        }
    });
    this.on('task.prefetch.success', this, function(event, context, eventObject) {
        if (context.prefetchCallback != undefined) {
            context.prefetchCallback();
        }
        setTimeout(function() {
            self.prefetch();
        }, 500);
    });
    this.on('task.prefetch.error', this, function(event, context, eventObject) {
        setTimeout(function() {
            self.prefetch();
        }, 500);
    });
    this.on('task.prefetch.none', this, function(event, context, eventObject) {
        if (context.prefetchCallback != undefined) {
            context.prefetchCallback();
        }
        if (context.isFinish != true) {
            setTimeout(function() {
                self.prefetch();
            }, 1000);
        }
    });
    this.on('task.prefetch.finish', this, function(event, context, eventObject) {
        self.getTask();
    });
    this.on('task.submit.before', this, function(event, context, eventObject) {
        context.submitting = true;
    });
    this.on('task.submit.success', this, function(event, context, eventObject) {
        context.submitting = false;
        context.task = undefined;
        self.getTask();
    });
    this.on('task.submit.error', this, function(event, context, eventObject) {
        context.submitting = false;
    });
    this.on('task.pass.success', this, function(event, context, eventObject) {
        if (context.task != undefined && self.option.clearUrl != undefined) {
            $.post(self.option.clearUrl, {
                libraryId: context.task.libraryId
            });
        }
        context.task = undefined;
        self.getTask();
    });
    this.on('task.load.finish', this, function(event, context, eventObject) {
        var timestamp = new Date().getTime();
        context.task.spent = timestamp;
    });

    $(document).keypress(this, function(event) {
        if (self.context.listenKeyboard != false) {
            return self.trigger('key.press', event);
        }
    });
    $(document).keydown(this, function(event) {
        if (self.context.listenKeyboard != false) {
            return self.trigger('key.down', event);
        }
    });
    $(document).keyup(this, function(event) {
        if (self.context.listenKeyboard != false) {
            return self.trigger('key.up', event);
        }
    });

    window.onbeforeunload = function(e) {
        if (self.option.clearUrl != undefined) {
            $.post(self.option.clearUrl);
        }
    }
}

// 初始化功能模块
MarkControl.prototype.initModules = function(option) {
    if (this.modules == undefined) {
        this.modules = {};
    }
    var names = [];
    var options = [];
    for (var name in this.defaultModules) {
        names.push(name);
        options[name] = this.defaultModules[name];
    }

    if (option.modules != undefined) {
        for (var name in option.modules) {
            if (options[name] == undefined) {
                names.push(name);
                options[name] = {};
            }
            $.extend(options[name], option.modules[name]);
        }
    }

    this.initModule(names, options, this.option.success);
    // initModule(this, names, 0, options);
}

// 指定初始化某个名称的模块
MarkControl.prototype.initModule = function(names, options, success) {
    for (var i in names) {
        var name = names[i];
        var option = options[name];
        var moduleInit = name.replace(/-/g, '_');
        if (option == undefined || typeof(option) != 'object') {
            option = {};
        }
        option.markControl = this;
        eval('this.modules[name]=' + moduleInit + '(option, function(){})');
    }
    if (success != undefined && typeof(success) == 'function') {
        success();
    }
}

function initModuleAsync(markControl, names, index, option) {
    if (index < names.length) {
        var name = names[index];
        var moduleOption = option[name];
        var moduleUrl = 'modules/' + name + '.js';
        var moduleInit = name.replace(/-/g, '_');
        var modules = markControl.modules;
        if (modules[name] == undefined) {
            if (typeof(moduleOption) != 'object') {
                moduleOption = {};
            }
            moduleOption.markControl = markControl;
            $.getScript(moduleUrl, function() {
                var success = function() {
                    initModule(markControl, names, index + 1, option);
                }
                eval('modules[name]=' + moduleInit + '(moduleOption, success)');
            });
        } else {
            initModule(markControl, names, index + 1, option);
        }
    } else {
        if (markControl.option.success != undefined && typeof(markControl.option.success) == 'function') {
            markControl.option.success();
        }
    }
}

MarkControl.prototype.start = function(taskOption) {
    taskOption.markControl = this;
    var markControl = this;
    taskOption.success = function() {
        markControl.context.prefetchCallback = function() {
            markControl.context.prefetchCallback = undefined;
            markControl.getTask();
        }
        markControl.context.statusCallback = function() {
            markControl.context.statusCallback = undefined;
            markControl.prefetch();
        }
        markControl.getStatus();
    };
    taskOption.error = function(message) {
        alert('初始化失败，请刷新页面重新加载');
    };
    this.taskControl = new TaskControl(taskOption);
    this.taskControl.init();
}

// task预加载
MarkControl.prototype.prefetch = function() {
    var taskControl = this.taskControl;
    var markControl = this;
    var context = this.context;
    var imageBuilder = this.modules['image-builder'];

    if (context.isFinish != true) {
        if (taskControl.isFinish()) {
            context.isFinish = true;
        } else if (context.prefetchTask.length >= markControl.maxPrefetchCount) {
            markControl.trigger('task.prefetch.success');
        } else if (context.prefetching == false) {
            context.prefetching = true;
            markControl.trigger('task.prefetch.before');

            taskControl.fetch(function(task) {
                if (imageBuilder != undefined) {
                    imageBuilder.build(task, function(error) {
                        if (error) {
                            context.prefetching = false;
                            markControl.trigger('task.prefetch.error');
                        } else {
                            context.prefetchTask.push(task);
                            context.prefetchStatus = undefined;
                            context.prefetching = false;
                            markControl.trigger('task.prefetch.success');
                        }
                    });
                } else {
                    context.prefetchTask.push(task);
                    context.prefetchStatus = undefined;
                    context.prefetching = false;
                    markControl.trigger('task.prefetch.success');
                }
            }, function(task) {
                context.prefetchStatus = task.message;
                context.prefetching = false;
                markControl.trigger('task.prefetch.none');
            }, function() {
                context.prefetching = false;
                markControl.trigger('task.prefetch.none');
            });
        }
    } else {
        markControl.trigger('task.prefetch.finish');
    }
}

MarkControl.prototype.getStatus = function() {
    if (this.taskControl == undefined) {
        return;
    }
    var self = this;
    this.taskControl.status(function(status) {
        self.context.status = status;
        if (status != undefined) {
            self.context.isFinish = status.blockTotalCount > 0 && status.blockTotalCount == (status.blockMarkedCount + status.blockExceptionCount);
        }
        if (self.context.statusCallback != undefined) {
            self.context.statusCallback();
        }
        self.trigger('mark.status.change', status);
    })
}

MarkControl.prototype.getTask = function() {
    if (this.taskControl == undefined) {
        return;
    }
    var markControl = this;
    var context = this.context;
    markControl.trigger('task.get.before');

    if (context.isFinish == true) {
        markControl.trigger('task.get.finish');
        return;
    } else if (context.task != undefined) {
        markControl.trigger('task.get.success');
        return;
    } else if (context.waitTask != undefined) {
        // 优先选择因回评等操作处于等待状态的任务
        context.task = context.waitTask;
        context.waitTask = undefined;
        markControl.trigger('task.get.success');
    } else if (context.prefetchTask.length > 0) {
        // 判断是否有任务已预加载完毕
        context.task = context.prefetchTask.shift();
        markControl.trigger('task.get.success');
    } else if (context.prefetchStatus != undefined) {
        // 判断是否有在无预加载任务的情况下的消息提示
        markControl.trigger('task.get.none', context.prefetchStatus);
    } else {
        markControl.trigger('task.get.none');
    }
}

MarkControl.prototype.getHistory = function(data) {
    if (this.taskControl == undefined) {
        return;
    }
    this.taskControl.history(data, function(result) {
        data.result = result;
        this.option.markControl.trigger('history.get.success', data);
    }, function(message) {
        data.message = message;
        this.option.markControl.trigger('history.get.error', data);
    });
}

MarkControl.prototype.setTask = function(task) {
    var imageBuilder = this.modules['image-builder'];
    var self = this;

    if (this.context.task != undefined && !this.context.task.previous && this.context.waitTask == undefined) {
        this.context.waitTask = this.context.task;
    }
    this.trigger('task.get.before');
    if (imageBuilder != undefined && task != undefined) {
        imageBuilder.build(task, function(error) {
            self.context.task = task;
            self.trigger('task.get.success');
        });
    } else {
        self.context.task = task;
        if (task != undefined) {
            this.trigger('task.get.success');
        }
    }
}

MarkControl.prototype.submitTask = function(submitUrl) {
    var task = this.context.task;
    var markControl = this;
    var submitUrl = submitUrl != undefined && submitUrl.length > 0 ? submitUrl : this.option.submitUrl;

    if (task != undefined && this.context.submitting != true) {
        task.markStepList = undefined;
        task.pictureUrls = undefined;
        task.sheetUrls = undefined;
        task.imageData = undefined;
        task.markFinish = undefined;
        task.markTime = undefined;
        task.paperUrl = undefined;
        task.answerUrl = undefined;
        var timestamp = new Date().getTime();
        task.spent = timestamp - task.spent;
        this.trigger('task.submit.before');
        this.trigger('mark.specialTag.before');
        if (this.taskControl != undefined) {
            // 已定义任务引擎
            this.taskControl.submit(task, function(status) {
                if (status != undefined && status.valid == true) {
                    markControl.context.status = status;
                    markControl.trigger('mark.status.change', status);
                }
                // markControl.context.task = undefined;
                markControl.trigger('task.submit.success');
                markControl.trigger('mark.specialTag.success');
                // markControl.getTask();
            }, function(message) {
                markControl.trigger('task.submit.error', message);
            });
        } else if (submitUrl != undefined && submitUrl.length > 0) {
            // 未定义任务引擎，依赖定义/传入的提交地址
            $.ajax({
                url: submitUrl,
                type: 'POST',
                data: task,
                success: function(result) {
                    if (result.success == true) {
                        // markControl.context.task = undefined;
                        markControl.trigger('task.submit.success');
                        markControl.trigger('mark.specialTag.success');
                        // markControl.getTask();
                    } else {
                        markControl.trigger('task.submit.error', result.message);
                    }
                },
                error: function(message) {
                    markControl.trigger('task.submit.error', message);
                }
            });
        } else {
            markControl.trigger('task.submit.success');
            markControl.trigger('mark.specialTag.success');
            // markControl.getTask();
        }
    }
}

// 默认要初始化的模块名称
MarkControl.prototype.defaultModules = {
    'image-builder': {}
};

MarkControl.prototype.main_row_dom = '<div class="row-fluid"></div>';

MarkControl.prototype.sidebar_dom = '<div class="mark-sidebar span2 hide"></div>';

MarkControl.prototype.center_dom = '<div class="center-content span12"></div>';

MarkControl.prototype.center_header_dom = '<div class="row-fluid"><div class="header"><p class="tips">\
<em><a href="/mark/index?mode=common" class="btn">切换到普通模式</a>\
<a href="javascript:void(0)" id="assistant-button" class="btn"><i class="icon-wrench"></i> 小助手</a></em>\
<a class="useinfo" href="#"><i class="icon-user icon-white"></i><i id="mark-user-name"></i></a>\
<a class="logout" id="logout-link" href="{logoutUrl}"><i class="icon-off icon-white"></i> <i id="logout-title">退出</i></a>\
</p></div></div>';

MarkControl.prototype.center_content_dom = '<div class="row-fluid"><div class="image-content span9"><nav></nav></div></div>';

MarkControl.prototype.assistant_dom = '<div class="popover bottom assistant"><div class="arrow"></div></div>';

MarkControl.prototype.mark_function_dom = '<h3 class="popover-title">评卷功能</h3>\
<div class="popover-content"><p id="function-list" class="popover-list">\
</p></div>';

// 其他通用方法
String.prototype.startWith = function(prefix) {
    return this.indexOf(prefix) === 0;
}
String.prototype.endWith = function(suffix) {
    return this.match(suffix + "$") == suffix;
};

// 日期格式化
Date.prototype.format = function(fmt) { // author: meizz
    var o = {
        "M+": this.getMonth() + 1, // 月份
        "d+": this.getDate(), // 日
        "h+": this.getHours(), // 小时
        "m+": this.getMinutes(), // 分
        "s+": this.getSeconds(), // 秒
        "q+": Math.floor((this.getMonth() + 3) / 3), // 季度
        "S": this.getMilliseconds() // 毫秒
    };
    if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (var k in o) {
        if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
    }
    return fmt;
}

function getDom(content, markControl) {
    if (markControl != undefined && markControl.option.staticServer != undefined) {
        content = content.replace(/{staticServer}/g, markControl.option.staticServer);
    }
    if (markControl != undefined && markControl.option.logoutUrl != undefined) {
        content = content.replace(/{logoutUrl}/g, markControl.option.logoutUrl);
    }
    return $(content);
}

function isArray(obj) {
    return obj != undefined && Object.prototype.toString.call(obj) === '[object Array]';
}