var audioUrlPrefix = "/audio/";//音频文件的路径，后面跟文件名
var imageUrlPrefix = "/image/";//图片文件的路径，后面跟文件名
var wsUrl = "/CourseDemo";//webService的路径
var fmsUrl = "rtmp://media.aispeech.com/aid200906";//fms的路径
var paypalUrl = "http://aid200906/CourseDemo";
var avatarUrlPrefix = "/avatar/";
var autoplay = {
    start: "/mt/mt-static/themes/aid200906/sound/ding.mp3",
    startMs: 626,
    right: "/mt/mt-static/themes/aid200906/sound/right.mp3",
    wrong: "/mt/mt-static/themes/aid200906/sound/wrong.mp3",
    clickButton: "/mt/mt-static/themes/aid200906/sound/buttoneffect.mp3"
}

var commonError = {
    "101": "Username must not be left blank",
    "102": "This username is not available",
    "103": "Password must not be left blank",
    "104": "Passwords do not match",
    "105": "Password incorrect",
    "106": "Email must not be left blank",
    "107": "Email format incorrect",
    "108": "Username does not match email account",
    "201": "Insufficient points",
    "202": "You don't need to pay twice"
}

var scoreIcon = {
    getScore: function(detail){
        return Math.floor(0.67 * detail.score + 0.33 * detail.tonescore);
    },
    
    getIcon: function(detail){
        // detail is an object like this:
        // {char: "bai", score: 100, phone: [["b", 100], ["ai", 100]], tone: 3, tonescore: 100, confidence: [0, 0, 0, 100, 0] }
        var i = 0.67 * detail.score + 0.33 * detail.tonescore;
        if (i < 20) {
            return scoreIcon.attention;
        } else if (i < 40) {
            return scoreIcon.notbad;
        } else if (i < 60) {
            return scoreIcon.ok;
        } else if (i < 80) {
            return scoreIcon.good;
        } else if (i <= 100) {
            return scoreIcon.excellent;
        } else {
            return;
        }
    },
    
    getSmallIcon: function(detail){
        return this.getIcon(detail);
    },
    
    getPhone: function(score){
        if (score < 20) {
            return scoreIcon.attention;
        } else if (score < 40) {
            return scoreIcon.notbad;
        } else if (score < 60) {
            return scoreIcon.ok;
        } else if (score < 80) {
            return scoreIcon.good;
        } else if (score <= 100) {
            return scoreIcon.excellent;
        } else {
            return;
        }
    },
    
    //58x45
    excellent: '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" width="58" height="45"><param name="movie" value="/mt/mt-static/themes/aid200906/swf/excellent.swf" /><param name="quality" value="high" /><param name="wmode" value="transparent" /><param name="bgcolor" value="" /><embed src="/mt/mt-static/themes/aid200906/swf/excellent.swf" quality="high" wmode="transparent" bgcolor="" width="58" height="45" align="" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed></object>',//80-100
    good: '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" width="58" height="45"><param name="movie" value="/mt/mt-static/themes/aid200906/swf/good.swf" /><param name="quality" value="high" /><param name="wmode" value="transparent" /><param name="bgcolor" value="" /><embed src="/mt/mt-static/themes/aid200906/swf/good.swf" quality="high" wmode="transparent" bgcolor="" width="58" height="45" align="" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed></object>',//60-79
    ok: '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" width="58" height="45"><param name="movie" value="/mt/mt-static/themes/aid200906/swf/ok.swf" /><param name="quality" value="high" /><param name="wmode" value="transparent" /><param name="bgcolor" value="" /><embed src="/mt/mt-static/themes/aid200906/swf/ok.swf" quality="high" wmode="transparent" bgcolor="" width="58" height="45" align="" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed></object>',//40-59
    notbad: '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" width="58" height="45"><param name="movie" value="/mt/mt-static/themes/aid200906/swf/notbad.swf" /><param name="quality" value="high" /><param name="wmode" value="transparent" /><param name="bgcolor" value="" /><embed src="/mt/mt-static/themes/aid200906/swf/notbad.swf" quality="high" wmode="transparent" bgcolor="" width="58" height="45" align="" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed></object>',//20-39
    attention: '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" width="58" height="45"><param name="movie" value="/mt/mt-static/themes/aid200906/swf/attention.swf" /><param name="quality" value="high" /><param name="wmode" value="transparent" /><param name="bgcolor" value="" /><embed src="/mt/mt-static/themes/aid200906/swf/attention.swf" quality="high" wmode="transparent" bgcolor="" width="58" height="45" align="" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed></object>' //0-19
}

function getUserTone(confidence){
    //return int
    var userTone = -1;
    var maxNumber = -1;
    for (var i = confidence.length - 1; i >= 0; i--) {
        if (confidence[i] > maxNumber) {
            maxNumber = confidence[i];
            userTone = i;
        }
    }
    return userTone;
}

var tips = {
    pron: {
        "a": "When it is pronounced by itself, it is a central vowel. The tongue remains in a natural, relaxed position.",
        "o": "o is a rounded semi-high back vowel. The lips are rounded when pronouncing.",
        "e": "e is an unrounded semi-high back vowel. First pronounce o, then change the the shape of the mounth from rounded to unrounded. At the same time spread the lips apart, as if you are smiling.",
        "i": "i is an unrounded high front vowel. Try to squeeze a smile and pull the corner of your mouth straight back.",
        "u": "u is a rounded high back vowel. Pucker up your lips when pronouncing this sound.",
        "ü": "ü is a rounded high front vowel. To pronounce it, first position the tongue as if to pronounce i, then round the lips.",
        "b": "b is different from its English counterpart. It is not voiced, as the vocal cords do not vibrate.",
        "p": "p is aspirated. There is a strong puff of breath when the consonant is pronounced. It is also voiceless.",
        "m": "m is produced in the same manner as the English m. It is voiced.",
        "f": "f is produced in the same manner as the English f.",
        "d": "The tip of the tongue touches the gum of the upper teeth. The tongue is raised more to the back than it would be to pronounce their English counterparts. It is voiceless.",
        "t": "t is pronounced in the same manner as d, but it is aspirate.",
        "n": "n is pronounced in the same manner as d/t, but it is nasal.",
        "l": "The tip of the tongue should touch the palate.",
        "g": "g is unaspirate and voiceless, when pronounce it, the back of the tongue is raised against the soft palate.",
        "k": "k is aspirate and voiceless, when pronounce it, the back of the tongue is raised against the soft palate.",
        "h": "h is voiceless, when pronounce it, the back of the tongue is raised against the soft palate. The friction is noticeable.",
        "j": "First raise the flat center of the tongue to the roof of the mouth and position the lips of the tongue against the back of the bottom teeth, and then loose the tongue and let the air squeeze out through the channel thus made. It is unaspirate the vocal cords do not vibrate.",
        "q": "q is pronounced in the same manner as j, but it is unaspirate.",
        "x": "First raise the flat center of the tongue toward (but not touching) the hard palate and then squeeze out. The vocal cords do not vibrate.",
        "z": "z is similar to the English ds sound as in \"lids\".",
        "c": "c is similar to the English ts sound as in \"student.\" It is aspirated.",
        "s": "s is similar to the English s sound.",
        "zh": "First curl up the tip of the tongue against the hard palate, then loosen it and let the air squeeze out the channel thus made. It is unaspirate the vocal cords do not vibrate.",
        "ch": "ch is pronounced in the same manner as zh, but it is aspirate.",
        "sh": "Turn up the lip of the tongue toward (but not touching) the hard palate and then let the air squeeze out. The vocal cords do not vibrate.",
        "r": "r is pronounced in the same manner as sh, but it is voiced, therefore the vocal cords vibrates."
    },
    tone: {
        "1": "Tone 1 is high and level.",
        "2": "Tone 2 starts medium in tone, then rises to the top",
        "3": "Tone 3 starts low, dips to the bottom, then rises toward the top",
        "4": "Tone 4 Starts at the top, then falls sharp and strong to the bottom",
        "3to2": "When two consecutive characters are both in tone 3, you should pronounce the first character in tone 2",
        "1to4": "When the character “one” is followed by a character with any tone rather than 4, you should pronounce the character “one” as tone 4 instead of tone 1",
        "1to2": "When the character “one” is followed by a character with tone 4, you should pronounce the character “one” as tone 2 instead of tone 1",
        "4to2": "When the character \"no\" is followed by a character with tone 4, you should pronounce the character \"no\" as tone 2 instead of tone 4"
    },
    getFisrtToneTip: function(character, userTone, correctTone){
        return "Your pronunciation of char " + character + " is most likely to be tone " + userTone + ". However, the correct tone is " + correctTone + ".";
    }
}

var errorTimeoutId = null;
var error = {
    "500": {
        "-1": function(){//Internal Server Error
            $("#error500-1").dialog({
                bgiframe: true,
                width: 440,
                height: 280,
                modal: true,
                closeOnEscape: false,
                resizable: false
            });
            $("#error500-1").dialog('open');
        },
        "1": function(){//audio invalid
            if (errorTimeoutId != null) {
                window.clearTimeout(errorTimeoutId);
                $(".error500_1").hide();
            }
            var sHTML = '<div class="text">Your record is incomplete.</div>';
            $(".recordOff .error500_1").html(sHTML);
            $(".recordOff .error500_1").show();
            errorTimeoutId = window.setTimeout(function(){
                $(".error500_1").hide();
            }, 2000);
        },
        "3": function(){//url error
            alert("error: invalid url");
        },
        "4": function(){//unPaid
            $("#error500_4").dialog({
                bgiframe: true,
                width: 440,
                height: 280,
                modal: true,
                closeOnEscape: false,
                resizable: false
            });
            $("#error500_4").dialog('open');
        },
        "5": function(){//session timeout
            $("#error500_5").dialog({
                bgiframe: true,
                width: 440,
                height: 280,
                modal: true,
                closeOnEscape: false,
                resizable: false
            });
            $("#error500_5").dialog('open');
        },
        "6": function(){//for guest only
            $("#error500_6").dialog({
                bgiframe: true,
                width: 440,
                height: 280,
                modal: true,
                closeOnEscape: false,
                resizable: false
            });
            $("#error500_6").dialog('open');
        },
        "7": function(){//音量太高
            //alert("音量太高");
            if (errorTimeoutId != null) {
                window.clearTimeout(errorTimeoutId);
                $(".error500_1").hide();
            }
            var sHTML = '<div class="text">Your sounds is too loud, please make lower.</div>';
            $(".recordOff .error500_1").html(sHTML);
            $(".recordOff .error500_1").show();
            errorTimeoutId = window.setTimeout(function(){
                $(".error500_1").hide();
            }, 2000);
        },
        "8": function(){
            //alert("音量太低");
            if (errorTimeoutId != null) {
                window.clearTimeout(errorTimeoutId);
                $(".error500_1").hide();
            }
            var sHTML = '<div class="text">Your sounds is too low,please make louder.</div>';
            $(".recordOff .error500_1").html(sHTML);
            $(".recordOff .error500_1").show();
            errorTimeoutId = window.setTimeout(function(){
                $(".error500_1").hide();
            }, 2000);
        },
        "9": function(){
            //alert("媒体服务器没有保存");
            if (errorTimeoutId != null) {
                window.clearTimeout(errorTimeoutId);
                $(".error500_1").hide();
            }
            var sHTML = '<div class="text">The sounds have not been preserved.</div>';
            $(".recordOff .error500_1").html(sHTML);
            $(".recordOff .error500_1").show();
            errorTimeoutId = window.setTimeout(function(){
                $(".error500_1").hide();
            }, 2000);
        },
        "10": function(){
            //alert("噪音太大");
            if (errorTimeoutId != null) {
                window.clearTimeout(errorTimeoutId);
                $(".error500_1").hide();
            }
            var sHTML = '<div class="text">The sounds is too noisy to hear.</div>';
            $(".recordOff .error500_1").html(sHTML);
            $(".recordOff .error500_1").show();
            errorTimeoutId = window.setTimeout(function(){
                $(".error500_1").hide();
            }, 2000);
        },
        "11": function(){
            //alert("用户的读音不饱满");
            if (errorTimeoutId != null) {
                window.clearTimeout(errorTimeoutId);
                $(".error500_1").hide();
            }
            var sHTML = '<div class="text">Your sounds is not full enough.</div>';
            $(".recordOff .error500_1").html(sHTML);
            $(".recordOff .error500_1").show();
            errorTimeoutId = window.setTimeout(function(){
                $(".error500_1").hide();
            }, 2000);
        },
        "12": function(){
            //alert("用户的朗读不完整");
            if (errorTimeoutId != null) {
                window.clearTimeout(errorTimeoutId);
                $(".error500_1").hide();
            }
            var sHTML = '<div class="text">Recording incomplete. Please try again.</div>';
            $(".recordOff .error500_1").html(sHTML);
            $(".recordOff .error500_1").show();
            errorTimeoutId = window.setTimeout(function(){
                $(".error500_1").hide();
            }, 2000);
        },
        "13": function(){//Server busy
            $("#error500-13").dialog({
                bgiframe: true,
                width: 440,
                height: 280,
                modal: true,
                closeOnEscape: false,
                resizable: false
            });
            $("#error500-13").dialog('open');
        }
    }
}

function gotoMyUrl(str){
    if (str == undefined) {
        str = "";
    }
    var searchStr = window.location.search;
    window.location.href = "/my/" + str + searchStr;
}

function gotoStudyUrl(str){
    if (str == undefined) {
        str = "";
    }
    var searchStr = window.location.search;
    window.location.href = "/study/" + str + searchStr;
}

function gotoCourseUrl(str){
    if (str == undefined) {
        str = "";
    }
    var searchStr = window.location.search;
    window.location.href = "/course/" + str + searchStr;
}

function gotoGpsUrl(str){
    if (str == undefined) {
        str = "";
    }
    var searchStr = window.location.search;
    window.location.href = "/gps/" + str + searchStr;
}

function ajaxError(XMLHttpRequest, textStatus, errorThrown){
    if (XMLHttpRequest.status == 200 && textStatus == "parsererror") {
        openLoginDialog("Please login:)", function(){
            var url = window.location.href;
            window.location.replace(url);
        });
        /*window.location.replace("/error.html");*/
    } else if (XMLHttpRequest.status == 500) {
        try {
            eval("var obj=" + XMLHttpRequest.responseText);
            /* 
             * error code:
             * -1 内部错误
             * 1 用户读音质量不好
             * 3 请求的url不正确
             * 4 未购买
             * 5 会话超时
             * 6 只有匿名用户才能用(注册时)
             * 7 音量太高
             * 8 音量太低
             * 9 媒体服务器没有保存用户录音
             * 10 噪音太大
             * 11 用户的读音不饱满
             * 12 用户的朗读不完整
             * 13 服务器正忙
             */
            switch (obj.err) {
                case "-1":
                    error["500"]["-1"]();
                    break;
                case "1":
                    error["500"]["1"]();
                    break;
                case "3":
                    error["500"]["3"]();
                    break;
                case "4":
                    error["500"]["4"]();
                    break;
                case "5":
                    error["500"]["5"]();
                    break;
                case "6":
                    error["500"]["6"]();
                    break;
                case "7":
                    error["500"]["7"]();
                    break;
                case "8":
                    error["500"]["8"]();
                    break;
                case "9":
                    error["500"]["9"]();
                    break;
                case "10":
                    error["500"]["10"]();
                    break;
                case "11":
                    error["500"]["11"]();
                    break;
                case "12":
                    error["500"]["12"]();
                    break;
                case "13":
                    error["500"]["13"]();
                    break;
                default:
                    break;
            }
        } 
        catch (e) {
            alert("error: " + XMLHttpRequest.status + " " + XMLHttpRequest.statusText);
        }
    } else if (XMLHttpRequest.status != 0) {
        alert("error: " + XMLHttpRequest.status + " " + XMLHttpRequest.statusText);
    }
}

/**
 * 修改function的原型，这样就可以在jquery的ajax回调里使用this指针了
 * @param {Object} thisObj
 */
Function.prototype.myApply = function(thisObj){
    var _method = this;
    return function(){
        // arguments是javascript内部默认的参数列表
        return _method.apply(thisObj, arguments);
    };
}

/**
 * 如果页面请求等待时间过长可以启用此等待动画
 */
function Loading(){

    function _getWidth(){
        // handle IE 6
        if ($.browser.msie && $.browser.version < 7) {
            var scrollWidth = Math.max(document.documentElement.scrollWidth, document.body.scrollWidth);
            var offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth);
            
            if (scrollWidth < offsetWidth) {
            
                return $(window).width() + 'px';
            } else {
            
                return scrollWidth + 'px';
            }
            // handle "good" browsers
        } else {
        
            return $(document).width() + 'px';
        }
    }
    
    function _getHeight(){
        // handle IE 6
        if ($.browser.msie && $.browser.version < 7) {
            var scrollHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
            var offsetHeight = Math.max(document.documentElement.offsetHeight, document.body.offsetHeight);
            
            if (scrollHeight < offsetHeight) {
            
                return $(window).height() + 'px';
            } else {
            
                return scrollHeight + 'px';
            }
            // handle "good" browsers
        } else {
        
            return $(document).height() + 'px';
        }
    }
    
    function _setPosition(){
        $("#loading").css({
            width: 0,
            height: 0
        }).css({
            width: _getWidth(),
            height: _getHeight()
        });
        $("#loading .flash").css("padding-top", parseFloat(_getHeight()) / 2 - 40);
    }
    
    this.enable = function(){
        _setPosition();
        $("#loading").ajaxStart(function(){
            $(this).show();
        });
        $("#loading").ajaxStop(function(){
            $(this).hide();
        });
        
        $(window).resize(function(){
            _setPosition();
        });
    }
    
    this.disable = function(){
        $("#loading").ajaxStart(function(){
            // no animation here
        });
        $("#loading").ajaxStop(function(){
            // no animation here
        });
    }
};

/**
 * 信号量
 *
 * 当condition为true时结束信号量并执行callback
 *
 * @param {Object} condition 信号条件
 * @param {Object} callback 回调
 * @param {Object} timeout 超时，默认为60000ms
 */
function Signal(condition, callback, timeout){

    var _signalId = -1;
    var _intervalId = -1;
    var _timeoutId = -1;
    
    var _condition = condition;
    var _callback = callback;
    var _timeout = timeout;
    
    this.wait = function(){
    
        if (typeof(_timeout) == "undefined") {
            _timeout = 60000;
        }
        
        if (typeof(_condition) != "function" || typeof(_callback) != "function" || typeof(_timeout) != "number") {
        
            //使用信号量的html页面不一定包含了log4js.js
            if (typeof(logger) == "object") {
                logger.debug("illegal arguments, fail to set signal");
            }
            
        } else {
        
            _signalId = new Date().getTime();
            _intervalId = setInterval(function(){
            
                if (typeof(logger) == "object") {
                    logger.debug("waiting for singal[" + _signalId + "]");
                }
                
                if (_condition()) {
                    if (typeof(logger) == "object") {
                        logger.debug("signal[" + _signalId + "] is ok");
                    }
                    clearInterval(_intervalId);
                    clearTimeout(_timeoutId);
                    _callback();
                    
                }
                
            }, 50);
            
            _timeoutId = setTimeout(function(){
            
                if (typeof(logger) == "object") {
                    logger.debug("singal[" + _signalId + "] timeout");
                }
                clearInterval(_intervalId);
                
            }, _timeout);
            
            if (typeof(logger) == "object") {
                logger.debug("singal[" + _signalId + "] is setted");
            }
            
        }
    }
    
    this.clear = function(){
    
        if (_signalId == -1) {
        
            if (typeof(logger) == "object") {
                logger.debug("there's no signal");
            }
            
        } else {
        
            clearInterval(_intervalId);
            clearTimeout(_timeoutId);
            
            if (typeof(logger) == "object") {
                logger.debug("signal[" + _signal + "] is cleared");
            }
            
        }
        
    };
}

/**
 * 工具类
 */
function Util(){

    function _containsUnit(units, unitId){
        var _contains = false;
        if (util.isValid(units)) {
            for (var i = 1; i <= units.length; i++) {
                if (units[i].id == unitId) {
                    _contains = true;
                    break;
                }
            }
        }
        return _contains;
    };
    
    this.isValid = function(data){
        var _is = false;
        if (typeof(data) != "undefined" && data != null) {
            _is = true;
        }
        return _is;
    };
    
    this.isPaidUnit = function(unitId){
        return _containsUnit(ajax.paidUnits, unitId);
    };
    
    this.isFavoriteUnit = function(unitId){
        return _containsUnit(ajax.favoriteUnits, unitId);
    };
    
    this.isInCartUnit = function(unitId){
        return _containsUnit(ajax.inCartUnits, unitId);
    };
    
    this.isOnline = function(){
        return this.isValid(ajax.currentUser);
    };
}

/*
 * Ajax类，对jquery的ajax进行了封装，统一管理与服务器的通信
 */
function Ajax(){

    this.currentUser = undefined;
    this.allBooks = undefined;
    this.paidBooks = undefined;
    this.favoriteBooks = undefined;
    this.latestBooks = undefined;
    
    this.inCartUnits = undefined;
    this.favoriteUnits = undefined;
    this.paidUnits = undefined;
    
    function _ajax(settings){
    
        var ajaxSettings = {
            cache: "true",
            dataType: "json",
            error: function(XMLHttpRequest, textStatus, errorThrown){
                if (XMLHttpRequest.status != 200) {
                    ajaxError(XMLHttpRequest, textStatus, errorThrown);
                }
            }
        };
        
        $.extend(ajaxSettings, settings);
        
        //append context-path
        ajaxSettings.url = "/CourseDemo/" + ajaxSettings.url;
        
        $.ajax(ajaxSettings);
    }
    
    /**
     * 用户登陆
     * @param {Object} username
     * @param {Object} password
     * @param {Object} rememberme
     * @param {Object} complete
     */
    this.login = function(username, password, rememberme, complete){
    
        var data = "j_username=" + username;
        data += "&j_password=" + password;
        data += "&_spring_security_remember_me=" + rememberme;
        
        _ajax({
            cache: false,
            type: "post",
            url: "j_spring_security_check",
            data: data,
            complete: (function(){
                this.getCurrentUser(function(){
                    if (typeof(complete) == "function") {
                        complete();
                    }
                });
            }).myApply(this)
        });
        
        return;
    };
    
    /**
     * 用户退出
     * @param {Object} success
     */
    this.logout = function(complete){
    
        _ajax({
            cache: false,
            type: "post",
            url: "j_spring_security_logout",
            complete: (function(){
                this.getCurrentUser(function(){
                    if (typeof(complete) == "function") {
                        complete();
                    }
                });
            }).myApply(this),
            error: function(){
            },
            complete: complete
        });
        
        return;
    };
    
    /**
     * 获得当前登陆用户
     * @param {Object} complete
     */
    this.getCurrentUser = function(complete){
    
        this.currentUser = undefined;
        
        _ajax({
            cache: false,
            url: "current-user",
            dateType: undefined,
            success: (function(data){
                if (typeof data != "object") {
                    this.currentUser = null;// offline
                } else {
                    this.currentUser = data;// online
                }
            }).myApply(this),
            complete: (function(XMLHttpRequest, textStatus){
                if (this.currentUser == undefined) {
                    this.currentUser = null;
                }
                if (typeof complete == "function") {
                    complete();
                }
            }).myApply(this)
        });
        return;
    };
    
    /**
     * 获得所有book
     * @return books json
     */
    this.getAllBooks = function(complete){
    
        this.allBooks = undefined;
        
        _ajax({
            url: "all-books",
            success: (function(data){
                this.allBooks = data.books
            }).myApply(this),
            complete: complete
        });
        
        return;
    };
    
    /**
     * 获得最新的books
     * @return books json
     */
    this.getLatestBooks = function(complete){
    
        this.latestBooks = undefined;
        
        _ajax({
            url: "latest-books",
            success: (function(data){
                this.latestBooks = data.books
            }).myApply(this),
            complete: complete
        });
        
        return;
    };
    
    /**
     * 获得热门的books
     * @return books json
     */
    this.getHotBooks = function(complete){
    
        this.hotBooks = undefined;
        
        _ajax({
            url: "hot-books",
            success: (function(data){
                this.hotBooks = data.books
            }).myApply(this),
            complete: complete
        });
        
        return;
    };
    
    /**
     * 获得paid-books的数据
     * @return books json
     */
    this.getPaidBooks = function(complete){
    
        this.paidBooks = undefined;
        
        _ajax({
            url: "paid-books",
            success: (function(data){
                this.paidBooks = data.books
            }).myApply(this),
            complete: complete
        });
        
        return;
    };
    
    /**
     * 获得favorite-books的数据
     * @return books json
     */
    this.getFavoriteBooks = function(complete){
    
        this.favoriteBooks = undefined;
        
        _ajax({
            url: "favorite-books",
            success: (function(data){
                this.favoriteBooks = data.books
            }).myApply(this),
            complete: complete
        });
        
        return;
    };
    
    /**
     * 获得购物车数据
     * @param {object} userId
     * @return 购物车数据
     */
    this.getInCartUnits = function(complete){
    
        this.inCartUnits = undefined;
        
        _ajax({
            cache: false,
            url: "cart",
            success: (function(data){
                this.inCartUnits = data;
            }).myApply(this),
            complete: complete
        });
        
        return;
    };
    
    /**
     * 添加多个unit到购物车
     * @param {object} unitIds unitId的数组
     */
    this.addUnitsToCart = function(unitIds, complete){
    
        this.inCartUnits = undefined;
        var data = "isAdd=true";
        data += "&unitId=" + unitIds.join("&unitId=");
        
        _ajax({
            cache: false,
            type: "post",
            data: data,
            url: "cart",
            success: (function(data){
                this.inCartUnits = data;
            }).myApply(this),
            complete: complete
        });
        
        return;
    };
    
    /**
     * 从购物车中移除unit
     * @param {object} unitIds
     */
    this.removeUnitsFromCart = function(unitIds, complete){
    
        this.inCartUnits = undefined;
        
        var data = "isAdd=false";
        data += "&unitId=" + unitIds.join("&unitId=");
        
        _ajax({
            cache: false,
            type: "post",
            data: data,
            url: "cart",
            success: (function(data){
                this.inCartUnits = data;
            }).myApply(this),
            complete: complete
        });
        
        return;
    };
    
    /**
     * 添加多个unit到购物车
     * @param {object} unitIds unitId的数组
     */
    this.addFavoriteUnits = function(unitIds, complete){
    
        this.favoriteUnits = undefined;
        var data = "isAdd=true";
        data += "&unitId=" + unitIds.join("&unitId=");
        
        _ajax({
            cache: false,
            type: "post",
            data: data,
            url: "favorite-units",
            success: (function(data){
                this.favoriteUnits = data;
            }).myApply(this),
            complete: complete
        });
        
        return;
    };
    
    /**
     * 移除favorite unit
     * @param {object} unitIds
     */
    this.removeFavoriteUnits = function(unitIds, complete){
    
        this.favoriteUnits = undefined;
        
        var data = "isAdd=false";
        data += "&unitId=" + unitIds.join("&unitId=");
        
        _ajax({
            cache: false,
            type: "post",
            data: data,
            url: "favorite-units",
            success: (function(data){
                this.favoriteUnits = data;
            }).myApply(this),
            complete: complete
        });
        
        return;
    };
    
    /**
     * 获得购买的单元
     * @param {object} userId
     * @return 已购买的单元
     */
    this.getPaidUnits = function(complete){
    
        this.paidUnits = undefined;
        
        _ajax({
            cache: false,
            url: "paid-units",
            success: (function(data){
                this.paidUnits = data;
            }).myApply(this),
            complete: complete
        });
        
        return;
    };
    
    /**
     * 获得已收藏的单元
     * @return 已经收藏的单元
     */
    this.getFavoriteUnits = function(complete){
    
        this.favoriteUnits = undefined;
        
        _ajax({
            cache: false,
            url: "favorite-units",
            success: (function(data){
                this.favoriteUnits = data;
            }).myApply(this),
            complete: complete
        });
        
        return;
    };
    
}

var util = new Util();
var ajax = new Ajax();
var loading = new Loading();

