//# sourceURL=reader-core-3.2.0.js

(function (W, Q, R) {// window, jQuery, SWR

    /* 'use strict';*/
    //全局状态
    //view:正常预览状态,edit:编辑状态,select:文本选择状态
    var VIEW = 'view', EDIT = 'edit', SELECT = 'select';
    var RC = R.Common, RU = R.Util, RE = R.EjQ, L = R.Logger, Config = R.Config;

    var BA = RC.Attribute, BC = RC.CSS, BD = RC.DataName, BE = RC.EventName, BS = RC.Status, BP = RC.CmdPrefix,
        BF = RC.FileTypes;

    var NAME = 'core', EVENT = '.' + NAME,//EventNamespace
        DATA = '_' + NAME,//DataName
        BUTTON_STATUS = {
            HIDE: 'hide',
            SHOW: 'show',
            DISABLED: 'disabled',
            UNDISABLED: 'undisabled',
            SELECT: true,
            UNSELECT: false
        }, UIACTION = 'ui:action', COREACTION = 'core:action';

    var LINK = true, ALINK = true, disableMenu = Config.disableMenu, contextMenu = true;
    var fastText = Config.fastText;
    L.info('Core preparing...');

    var Rotate = function (page, dom) {
        var r = page.attr(BA.PageRotate);
        if (!Q.isNumeric(r)) {
            return;
        }
        var n = parseInt(r);
        if (isNaN(n) || n === 0) {
            return;
        }
        var transform = {};
        if (RU.iev >= 9) {
            if (n === 1) {//90deg
                transform['transform-origin'] = 'left top';
                transform['transform'] = 'rotate(90deg) translateY(-' + page.width() + 'px)';
            } else if (n === 2) {//180deg
                transform['transform-origin'] = 'center center';
                transform['transform'] = 'rotate(180deg) translateY(-' + page.height() + 'px)';
            } else if (n === 3) {//270deg
                transform['transform-origin'] = 'left top';
                transform['transform'] = 'rotate(270deg) translateX(-' + page.height() + 'px)';
            }
        } else {//IE6/7/8
            var matrix = function (d) {
                var r = d * Math.PI / 180;
                var cos = RU.round(Math.cos(r), 6);
                var sin = RU.round(Math.sin(r), 6);
                return [cos, -sin, sin, cos];//M11 M12 M21 M22
            };
            var mx;
            if (n === 1) {//90deg
                mx = matrix(90);
            } else if (n === 2) {//180deg
                mx = matrix(180);
            } else if (n === 3) {//270deg
                mx = matrix(270);
            }
            var dmm = 'progid:DXImageTransform.Microsoft.Matrix(M11=' + mx[0] + ', M12=' + mx[1] + ', M21=' + mx[2] + ', M22=' + mx[3] + ', SizingMethod="auto expand")';
            transform ['filter'] = dmm;
            transform ['-ms-filter'] = dmm;
        }
        dom.css(transform);
    };

    function _Helper(pocket, root) {
        this.fitWidth = function () {
            if (W._Origin === 'mobile') {
                return pocket.width() - 10;
            }
            return pocket.width() - 30;
        };
        this.fitHeight = function () {
            return pocket.height() - 10;
        };
        this.findPage = function (index, parent) {
            return RE.qI('_' + index, parent || root);
        };
        this.pageIndex = function (page) {
            if (RU.isNull(page)) {
                return;
            }
            if (Q.isNumeric(page)) {
                return RU.int(page);
            }
            return RU.int(Q(page).prop('id').slice(1));
        };
        this.mm2px = function (mm, dpi) {
            return RU.mm2px(mm, dpi || RC.DPI);
        };
        this.round = function (v) {
            return RU.round(v, 2);
        };
        this.pageSize = function (index, toPx) {
            var page = (index instanceof Q) ? index : this.findPage(index);
            var wm = parseFloat(page.attr(BA.PageWidth));
            var hm = parseFloat(page.attr(BA.PageHeight));
            if (toPx === true) {
                return [this.mm2px(wm), this.mm2px(hm)];
            }
            return [wm, hm];
        };

        this.doCall = function (fun, _this) {
            RU.doApply(fun, _this, Q.makeArray(arguments).slice(2));
        };
    }

    function _Do(T, req, helper) {
        /*function cssSupported(prop, value) {
         var d = document.createElement('div');
         d.style[ prop ] = value;
         return d.style[ prop ] === value;
         }*/

        /*
         处理图片  图片做背景添加url
         page表示当前页面
         data表示请求访问的参数
         event表示回调函数如失败中断等处理
         */
        this.image = function (page, data, event) {
            L.debug('Do image...');
            return req.image(R.Action.Image, data, Q.extend({}, event, {
                done: function () {
                    RE.qC(BC.Background, page).empty().append(this);
                    page.data(BD.Value, this.clientWidth)
                    RU.doApply(event.done, arguments);
                }
            }));
        };

        this.imagePart = function (part, data, event) {
            L.debug('Do Part image ...');
            return req.image(R.Action.Image, data, Q.extend({}, event, {
                done: function () {
                    part.empty().append(this);
                    RU.doData(part, BD.LoadState, true);
                    RU.doApply(event.done, this, part);
                },
                fail: function () {
                    RU.doApply(event.fail, this, part);
                }
            }));
        };

        //relayout or request
        var roq = function (page, dom, relayout, request) {
            if (!(dom && dom.length)) {
                L.warn('Dom is invalid');
            }
            var qd = Q(dom), val = qd.data(BD.Value);
            if (val && qd.attr('_ready')) {
                var dtd = Q.Deferred();
                setTimeout(function () {
                    relayout(dom);
                    dtd.resolve();
                });
                return dtd.promise();
            } else {
                return request(dom).done(function () {
                    qd.attr('_ready', true);
                });
            }
        };

        /*
         处理文字
         page表示当前页面
         data表示发送请求的参数
         event表示回调函数
         */
        this.text = function (page, data, event) {
            //L.debug('Do text...');
            var textsArry = [], texts = "";
            var content = RE.qC(BC.Content, page), w = page.width();
            var cover = RE.qC(BC.Cover, page);
            var cs = [];
            var gt = '<span class="{cls}" style="{style}" _size="{size}" _left="{left}" _top="{top}" _fontStyle="{fontStyle}">{gs}</span>';
            var parse = function (reply) {
                if (typeof reply == 'undefined') {
                    return;
                }
                Rotate(page, content);

                var calc = function (v, r) {
                    v = v * w / RC.Ratio;
                    if (r === true) {
                        v = helper.round(v);
                    }
                    return v;
                };
                var splitArray = function (array, callback) {
                    Q.each(array, function (_, a) {
                        var newArray = {
                            coord: a.coord,
                            font: a.font,
                            rect: a.rect,
                            hScale: (a['hScale'] ? a['hScale'] : null)
                        };
                        var code = a.code;
                        var start = 0, end = null, length = code.length;
                        for (var i = 0; i < length; i++) {
                            var next = i + 1;
                            if (next > length - 1) {
                                next = length - 1;
                            }
                            var ci = code[i], cn = code[next];
                            var cio = ci.offset[1], cn0 = cn.offset[1];
                            if (Math.abs(cn0 - cio) > 0.2 || cn == ci) {
                                if (end == null) {//竖排文字处理
                                    end = next;
                                    if (i != length - 1) {
                                        end -= 1;
                                    }
                                } else {
                                    if (code[next] == code[i]) {
                                        end = next
                                    }
                                }
                                newArray.code = code.slice(start, end + 1);
                                callback(newArray);
                                start = next;
                                end = null
                            } else {
                                end = next;
                            }
                        }
                    });
                };
                //添加间距
                var addLsp = function (e, gc, multiple) {
                    if (e.code.length > 1) {
                        var code = e.code;
                        var first = code[0].offset[0];
                        var last = code[code.length - 1].offset[0];
                        var ws = 0;
                        for (var i = 0; i < code.length - 1; i++) {
                            ws += code[i].size[0];
                        }
                        var temp = (last - first - ws) / (code.length - 1);
                        temp = calc(temp, true) / multiple;
                        gc['letter-spacing'] = Math.max(temp, 0) + 'px';
                    }
                };

                var uPx = function (e) {
                    var gc = {}, font = e.font;
                    var fontSize = font.size;
                    if (!Config.embed && RU.bool(font['embed'])) {
                        return;
                    }
                    addLsp(e, gc, 1);
                    var size = calc(fontSize);
                    gc['font-family'] = font.name;
                    gc['font-size'] = size;
                    gc['font-weight'] = font.weight;
                    if (RU.bool(font['italic'])) {
                        gc['font-style'] = 'italic';
                    }
                    //不显示颜色
                    /* var color = font.color;
                     if (Q.isArray(color)) {
                         gc['color'] = 'rgb(' + color.slice(1).join(',') + ')';
                     }*/
                    var hs = {}, hv = e['hScale'];
                    if (hv) {
                        hs['transform-origin'] = 0;
                        hs['white-space'] = 'nowrap';
                        hs['transform'] = 'scaleX(' + hv + ')';
                    }
                    var gs = [], ss = [], gsa = {style: gc, size: font.size, offset: {}, rect: e.rect};
                    if (Q.isArray(e.code)) {
                        var x = e.rect[0], y = e.rect[1];
                        RU.forEach(e.code, function (t, i) {
                            if (RU.isNull(t.text)) {
                                return;
                            }
                            var offset = t.offset;

                            var left = x, top = y;
                            if (Q.isArray(offset)) {
                                left += offset[0];
                                //矫正文字位置
                                top += offset[1] - t.size[1] * 0.12;
                            }

                            var textStyle = {
                                left: parseFloat(left.toFixed(2)),
                                top: parseFloat(top.toFixed(2)),
                                size: t.size,
                                fontsize: size,
                                text: t.text
                            };
                            var tc = {
                                left: calc(left, true), top: calc(top, true)
                            };
                            if (size < 12 && RU.isChrome()) { //Chrome font size min 12px
                                tc['transform-origin'] = 0;
                                tc['transform'] = 'scale(' + helper.round(size / 12) + ')';
                            } else {//if (B.Browser >= 9){//IE9+
                                tc = Q.extend({}, tc, hs);
                            }
                            if (i == 0) {
                                Q.extend(gsa.style, tc, true);
                                Q.extend(gsa.offset, textStyle, true);
                            }
                            ss.push(t.text);
                            texts += t.text;
                            textsArry.push(textStyle);
                        });
                        gs.push(formatTemplate(Q.extend(gsa, {
                            left: gsa.offset.left,
                            top: gsa.offset.top,
                            fontStyle: font.name,
                            gs: ss.join(''),
                            cls: BC.Group
                        }), gt));
                    }
                    cs.push(gs.join(''));
                };
                splitArray(RU.parseJSON(reply), uPx);
                //RU.forEach(RU.parseJSON(reply), uPx);
                content.html(cs.join(''));
                cover.data(BD.PageText, textsArry);
                content.data(BD.PageText, texts);
            };
            return roq(page, content, function (div) {
                L.debug('ReLayout text...');
                content = RE.qNv().addClass(BC.Content).data(BD.Value, div.data(BD.Value));
                div.remove();
                page.append(content);
                parse(content.data(BD.Value));
                if (T.globalState == SELECT) {
                    div.removeClass(BC.Hide);
                }
                L.log('ReLayout text finish');
                Q(T).trigger(BP.Page + 'texted', page);
            }, function (div) {
                return req.json(R.Action.Text, data, Q.extend({}, event, {
                        done: [
                            function (reply) {
                                div.data(BD.Value, reply);
                            },
                            function (reply) {
                                parse(reply);
                                RU.doApply(event.done, this);
                            }]
                    }),
                    {
                        context: T, cache: true
                    });
            });
        };
        this.textSpan = function (page, data, event) {
            //L.debug('Do text...');
            var content = RE.qC(BC.Content, page), w = page.width();
            var cs = [];
            var gt = '<span class="{cls}" style="{style}" _size="{size}">{gs}</span>';
            var st = '<span style="{style} " _left="{left}" _top="{top}">{text}</span>';
            var parse = function (reply) {
                Rotate(page, content);

                var calc = function (v, r) {
                    v = v * w / RC.Ratio;
                    if (r === true) {
                        v = helper.round(v);
                    }
                    return v;
                };

                var uPx = function (e) {
                    var gc = {}, font = e.font;
                    var fontSize = font.size;
                    if (font.name && font.name.indexOf("方正") !== -1) {
                        fontSize = fontSize * 0.8;
                    }
                    var size = calc(fontSize);
                    gc['font-family'] = font.name;
                    gc['font-size'] = size;
                    gc['font-weight'] = font.weight;
                    if (RU.bool(font['italic'])) {
                        gc['font-style'] = 'italic';
                    }
                    /* var color = font.color;
                     if (Q.isArray(color)) {
                         gc['color'] = 'rgb(' + color.slice(1).join(',') + ')';
                     }*/
                    var hs = {}, hv = e['hScale'];
                    if (hv) {
                        hs['transform-origin'] = 0;
                        hs['transform'] = 'scaleX(' + hv + ')';
                    }
                    var gs = [], ss = [], gsa = {style: gc, size: fontSize};
                    if (Q.isArray(e.code)) {
                        var x = e.rect[0], y = e.rect[1];
                        var data = {
                            left: x,
                            top: y
                        };
                        RU.forEach(e.code, function (t) {
                            if (RU.isNull(t.text)) {
                                return;
                            }
                            var offset = t.offset;
                            var left = x, top = y;
                            if (Q.isArray(offset)) {
                                left += offset[0];
                                top += offset[1];
                            }
                            if (font.name && font.name.indexOf("方正") !== -1) {
                                top = top + t.size[1] * 0.2;
                            }
                            var tc = {
                                left: calc(left, true), top: calc(top, true)
                            };
                            if (size < 12 && RU.isChrome()) { //Chrome font size min 12px
                                tc['transform-origin'] = 0;
                                tc['transform'] = 'scale(' + size / 12 + ')';
                            } else {//if (B.Browser >= 9){//IE9+
                                tc = Q.extend({}, tc, hs);
                            }
                            data = Q.extend(data, {
                                style: tc,
                                text: t.text,
                                left: left,
                                top: top
                            }, true);
                            ss.push(formatTemplate(data, st));
                        });
                        gs.push(formatTemplate(Q.extend(gsa, {
                            gs: ss.join(''),
                            cls: BC.Group
                        }), gt));
                    }
                    cs.push(gs.join(''));
                };
                RU.forEach(RU.parseJSON(reply), uPx);
                content.append(cs.join(''));
            };
            return roq(page, content, function (div) {
                L.debug('ReLayout text...');
                div.addClass(BC.Hide);
                var gs = RE.qC(BC.Group, div);
                if (gs.size() > 0) {
                    var calc = function (dom, name) {
                        return helper.round(w * parseFloat(dom.attr(name)) / RC.Ratio);
                    };
                    Rotate(page, div);
                    gs.css('font-size', function () {
                        var group = Q(this);
                        Q('span', group).css({
                            left: function () {
                                return calc(Q(this), BA.LeftScale);
                            },
                            top: function () {
                                return calc(Q(this), BA.TopScale);
                            }
                        });
                        var size = calc(group, BA.SizeScale);
                        if (RU.isChrome()) {
                            if (size < 12) { //Chrome font size min 12px
                                group.css({
                                    'transform-origin': 0,
                                    'transform': 'scale(' + size / 12 + ')'
                                });
                            } else {
                                group.css({'transform-origin': '', 'transform': ''});
                            }
                        }
                        return size;
                    });
                } else {
                    parse(content.data(BD.Value));
                }
                div.removeClass(BC.Hide);
                L.log('ReLayout text finish');
                Q(T).trigger(BP.Page + 'texted', page);
            }, function (div) {
                return req.json(R.Action.Text, data, Q.extend({}, event, {
                        done: [
                            function (reply) {
                                div.data(BD.Value, reply);
                            },
                            function (reply) {
                                parse(reply);
                                RU.doApply(event.done, this);
                            }]
                    }),
                    {
                        context: T, cache: true
                    });
            });
        };
        //页面超链接
        this.actions = function (page, data, event) {
            //L.debug('Do link...');
            var cover = RE.qC(BC.Cover, page);
            var parse = function (reply) {
                var scale = page.width() / RC.Ratio;
                var ret = RU.parseJSON(reply);
                if (Q.isArray(ret) && ret.length > 0) {
                    Rotate(page, cover);
                    Q.each(ret.filter(function (o) {
                        return o.action && o.action.length > 0;
                    }), function (_, actions) {
                        var bound = actions['bound'], action = actions['action'];
                        var ref = RE.qN('span').attr(BA.SizeScale, bound.join(',')).css({
                            left: helper.round(bound[0] * scale),
                            top: helper.round(bound[1] * scale),
                            width: helper.round(bound[2] * scale),
                            height: helper.round(bound[3] * scale)
                        }).appendTo(cover);
                        if (Q.isArray(action) && action.length) {
                            var ac = action[0], dest = ac['dest'], type = ac['type'], index = ac['page'];
                            switch (type) {
                                case 'goto':
                                    ref.attr(type, [index, dest[0], dest[1]]).attr('title', "跳转到第" + (parseInt(index) + 1) + "页");
                                    break;
                                default:
                                    ref.attr(type, index);
                                    break;
                            }
                        }
                    });
                }
            };
            return roq(page, cover, function (div) {
                L.debug('ReLayout actions...');
                div.addClass(BC.Hide);
                var ss = Q('span', div);
                if (ss.size() > 0) {
                    var scale = page.width() / RC.Ratio;
                    Rotate(page, div);
                    ss.each(function (_, link) {
                        var act = Q(link);
                        var rect = act.attr(BA.SizeScale).split(',');
                        act.css({
                            left: helper.round(rect[0] * scale),
                            top: helper.round(rect[1] * scale),
                            width: helper.round(rect[2] * scale),
                            height: helper.round(rect[3] * scale)
                        });
                    });
                } else {
                    parse(div.data(BD.Value));
                }
                div.removeClass(BC.Hide);
                L.debug('ReLayout link finish');
            }, function (div) {
                return req.json(R.Action.Actions, data, {
                    done: [
                        function (reply) {
                            div.data(BD.Value, reply);
                        },
                        function (reply) {
                            parse(reply);
                            RU.doApply(event.done, this);
                        }],
                    fail: event.fail
                }, {
                    context: T, cache: true
                });
            });
        };
        this.link = function (page, data, event) {
            //L.debug('Do link...');
            var cover = RE.qC(BC.Cover, page);
            var parse = function (reply) {
                if (!reply) return;
                var scale = page.width() / RC.Ratio, index = T.Pagination.index(page);
                var ret = RU.parseJSON(reply);
                if (Q.isArray(ret) && ret.length > 0) {
                    Rotate(page, cover);
                    Q.each(ret.filter(function (o) {
                        return o.subtype == "Link" || o.name == 'link';
                    }), function (_, actions) {
                        var bound = actions['boundary'], appearance = actions['appearance'][0],
                            action = appearance['action'];
                        var ref = RE.qN('span').attr(BA.SizeScale, bound.join(',')).css({
                            left: helper.round(bound[0] * scale),
                            top: helper.round(bound[1] * scale),
                            width: helper.round(bound[2] * scale),
                            height: helper.round(bound[3] * scale)
                        }).appendTo(cover);
                        if (Q.isArray(action) && action.length) {
                            var ac = action[0], dest = ac['dest'], type = ac['type'],
                                index = ac['page'] || ac['target'];
                            switch (type) {
                                case 'goto':
                                    ref.attr(type, [index, dest[0], dest[1]]).attr('title', "跳转到第" + (parseInt(index) + 1) + "页");
                                    break;
                                default:
                                    index.indexOf('http') != -1 ? ref.attr(type, index) : null;
                                    break;
                            }
                        }
                    });
                }
            };
            return roq(page, cover, function (div) {
                L.debug('ReLayout link...');
                div.addClass(BC.Hide);
                var ss = Q('span', div);
                if (ss.size() > 0) {
                    var scale = page.width() / RC.Ratio;
                    Rotate(page, div);
                    ss.each(function (_, link) {
                        var act = Q(link);
                        var rect = act.attr(BA.SizeScale).split(',');
                        act.css({
                            left: helper.round(rect[0] * scale),
                            top: helper.round(rect[1] * scale),
                            width: helper.round(rect[2] * scale),
                            height: helper.round(rect[3] * scale)
                        });
                    });
                } else {
                    parse(div.data(BD.DocLink));
                }
                div.removeClass(BC.Hide);
                L.debug('ReLayout link finish');
            }, function (div) {
                return req.json(R.Action.Link, data, {
                    done: [
                        function (reply) {
                            div.data(BD.DocLink, reply);
                        },
                        function (reply) {
                            parse(reply);
                            RU.doApply(event.done, this);
                        }],
                    fail: event.fail
                }, {
                    context: T, cache: true
                });
            });
        };
        this.aLink = function (texts, page, json) {
            var alt = '<span class="{cls}" style="{style}" uri="{uri}" title="{title}">{gs}</span>';
            var st = '<span class="{cls}" style="{style}"></span>';
            var cover = RE.qC(BC.Cover, page).addClass(BC.Hide), cs = [];
            Rotate(Q(page), cover);
            var ctexts = RE.qC(BC.Cover, page).data(BD.PageText);
            var w = Q(page).width();
            var calc = function (data) {
                return helper.round(w * parseFloat(data) / RC.Ratio);
            };
            var add = function (bs, target) {
                Q.each(bs, function (i, b) {
                    var height = 0;
                    Q.each(b, function (_, s) {
                        height = s.size[1];
                    });
                    var width = b[b.length - 1].left - b[0].left + b[b.length - 1].size[0];
                    var color = target.color || 'blue';
                    var rlStyle = {
                        cls: BC.ALink,
                        style: {
                            left: calc(b[0].left) + 2,
                            top: calc(b[0].top + height * 0.2),
                            width: calc(width),
                            height: calc(height),
                            color: color,
                            'border-bottom': "2px dashed " + color + ""
                        },
                        title: target.target,
                        uri: target.target
                    };
                    //IE span 元素选不中，谷歌等浏览器会报错
                    if (RU.iev <= 10) {
                        Q.extend(rlStyle.style, {
                            'background-image': 'url(about:blank)'
                        })
                    }
                    var span = formatTemplate({
                        cls: 'glyphicon glyphicon-link'
                    }, st);

                    cs.push(formatTemplate(Q.extend(rlStyle, {
                        gs: span
                    }), alt));
                });
            };
            var addLink = function (span, target) {
                var left = 0, b = [], start = 0, bs = [];
                Q.each(span, function (i, s) {
                    var sl = s.left;
                    if (left > sl) {
                        b.push(i);
                    }
                    if (i == span.length - 1) {
                        b.push(span.length);
                    }
                    left = sl;
                });
                for (var i = 0; i < b.length; i++) {
                    var end = b[i];
                    if (b.length == 1) {
                        end = end + 1;
                    }
                    if (start != end) {
                        bs.push(span.slice(start, end));
                        start = end;
                    }
                }
                add(bs, target);
            };
            RE.qC(BC.ALink, cover).remove();
            var searchText = function (text, index, target) {
                var start = texts.indexOf(text, index);
                if (start != -1) {
                    var span = ctexts.slice(start, start + text.length);
                    addLink(span, target);
                    if (start < texts.length) {
                        searchText(text, start + text.length, target);
                    }
                }
            }
            var parse = function (data) {
                for (var key in data) {
                    searchText(key, 0, data[key]);
                }
            };
            var index = helper.pageIndex(page);
            var ret = RU.parseJSON(json);
            if (Q.isArray(ret) && ret.length > 0) {
                Q.each(ret.filter(function (o) {
                    return o.name = 'alink';
                }), function (_, link) {
                    var li = link.index;
                    var ld = link.data;
                    switch (li) {
                        case 'all':
                            parse(ld);
                            break;
                        case 'even' :
                            if (index % 2 == 0) {
                                parse(ld);
                            }
                            break;
                        case 'odd' :
                            if (index % 2 == 1) {
                                parse(ld);
                            }
                            break;
                        default:
                            var li = parseInt(li);
                            if (li < 0) {
                                li = T.Pagination.count() + li;
                            }
                            if (index === li) {
                                parse(ld);
                            }
                            break;
                    }
                });
                cover.append(cs.join(''));
            }
            cover.removeClass(BC.Hide);
        };
        this.aLinkSpan = function (texts, page, json) {
            var alt = '<span class="{cls}" style="{style}" uri="{uri}" title="{title}">{gs}</span>';
            var st = '<span class="{cls}" style="{style}"></span>';
            var cover = RE.qC(BC.Cover, page).addClass(BC.Hide), cs = [];
            Rotate(Q(page), cover);
            var add = function (bs, target) {
                Q.each(bs, function (i, b) {
                    var height = 0;
                    Q.each(b, function (_, s) {
                        height = Math.max(height, Q(s).height())
                    });
                    var width = Q(b[b.length - 1]).offset().left - Q(b[0]).offset().left + Q(b[b.length - 1]).width();
                    var color = target.color || 'blue';
                    var rlStyle = {
                        cls: BC.ALink,
                        style: {
                            left: b[0].style.left,
                            top: b[0].style.top,
                            width: width,
                            height: height * 0.85,
                            color: color,
                            'border-bottom': "2px dashed " + color + ""
                        },
                        title: target.target,
                        uri: target.target
                    };
                    var sStyle = {
                        cls: 'glyphicon glyphicon-link'
                    };
                    var span = formatTemplate(sStyle, st);

                    cs.push(formatTemplate(Q.extend(rlStyle, {
                        gs: span
                    }), alt));
                });
            };
            var addLink = function (span, target) {
                var left = 0, b = [], start = 0, bs = [];
                Q.each(span, function (i, s) {
                    var sl = Q(s).offset().left;
                    if (left > sl) {
                        b.push(i);
                    }
                    if (i == span.length - 1) {
                        b.push(span.length);
                    }
                    left = sl;
                });
                for (var i = 0; i < b.length; i++) {
                    var end = b[i];
                    if (b.length == 1) {
                        end = end + 1;
                    }
                    if (start != end) {
                        bs.push(span.slice(start, end));
                        start = end;
                    }
                }
                add(bs, target);
            };
            RE.qC(BC.ALink, cover).remove();
            var searchText = function (text, index, target) {
                var start = texts.indexOf(text, index);
                if (start != -1) {
                    var group = RE.qC(BC.Group, RE.qC(BC.Content, page));
                    var span = Q('span', group).slice(start, start + text.length);
                    addLink(Q(span), target);
                    if (start < texts.length) {
                        searchText(text, start + text.length, target);
                    }
                }
            };
            var parse = function (data, page) {
                for (var key in data) {
                    searchText(key, 0, data[key]);
                }
            };
            var index = helper.pageIndex(page);
            var ret = RU.parseJSON(json);
            if (Q.isArray(ret) && ret.length > 0) {
                Q.each(ret.filter(function (o) {
                    return o.name = 'alink';
                }), function (_, link) {
                    var li = link.index;
                    var ld = link.data;
                    switch (li) {
                        case 'all':
                            parse(ld);
                            break;
                        case 'even' :
                            if (index % 2 == 0) {
                                parse(ld);
                            }
                            break;
                        case 'odd' :
                            if (index % 2 == 1) {
                                parse(ld);
                            }
                            break;
                        default:
                            var li = parseInt(li);
                            if (li < 0) {
                                li = T.Pagination.count() + li;
                            }
                            if (index === li) {
                                parse(ld);
                            }
                            break;
                    }
                });
                cover.append(cs.join('')).removeClass(BC.Hide);
            }
        };

        //添加页面元素的事件
        this.bindEvent = function (root) {
            RE.qC(BC.Cover, root).off('click', 'span').on('click', 'span', function () {
                var ref = Q(this);
                var uri = ref.attr('uri'), goto = ref.attr('goto'), sound = ref.attr('sound'),
                    movie = ref.attr('movie'), gotoa = ref.attr('goto');
                if (uri) {
                    window.open(uri, '_blank');
                }
                if (goto) {
                    var array = goto.split(',');
                    var pos = {x: 0, y: 0};
                    if (array.length > 2) {
                        pos.x = array[1] * 100 + '%';
                        pos.y = array[2] * 100 + '%';
                    }
                    T.jump(array[0], pos);
                }
                if (sound || movie) {
                    var loc = sound || movie;
                    T.fire('opt:core', ['downloadLoc', loc, null]);
                }
                /* if (gotoa) {
                     window.open('./reader?file=' + gotoa, '_blank');
                 }*/

            });
        };

        this.json = function (act, data, done, fail) {
            return req.json(act, data, {
                done: done, fail: fail
            }, {
                context: T
            });
        };
        this.checkActions = function (dom, data, event) {
            var evt = Q.extend({
                done: function () {
                    var d = dom.data(BD.DocActions);
                    Q.each(d, function (_, action) {
                        var a = action[0];
                        switch (a['type']) {
                            case 'goto':
                                T.jump(a['page'], {
                                    left: a['dest'][0],
                                    top: a['dest'][1]
                                });
                                break;
                            case 'uri':
                                window.open(a['page'], '_blank');
                                break;
                            default:
                                var loc = d['action'][0]['page'];
                                T.fire('opt:core', ['downloadLoc', loc, null]);
                                break;
                        }
                    });
                },
                fail: function () {
                    L.warn('Get Actions fail');
                }
            }, event);
            req.json(R.Action.Actions, data, {
                done: [
                    function (reply) {
                        dom.data(BD.DocActions, reply);
                    },
                    function (reply) {
                        RU.doApply(evt.done, this);
                    }],
                fail: evt.fail
            }, {
                context: T, cache: true
            });
        }
    }

    /*文字、页面超链接模板
    * */
    function formatTemplate(dta, tmpl) {
        var styles = function (style) {
            var s = '';
            for (var key in style) {
                if (typeof style[key] == 'undefined') {
                    continue;
                }
                if (key == 'left' || key == 'top' || key == 'font-size' || key == 'width' || key == 'height' || key == 'bottom') {
                    if (typeof style[key] == 'string') {
                        s += key + ':' + style[key] + ';';
                    } else {
                        s += key + ':' + style[key].toFixed(2) + 'px;';
                    }

                } else {
                    s += key + ':' + style[key] + ';';
                }
            }
            return s;
        };
        var format = {
            style: function (s) {
                var style = styles(s);
                return style;
            },
            text: function (t) {
                return t;
            },
            left: function (l) {
                return l;
            },
            top: function (t) {
                return t;
            },
            size: function (s) {
                return s;
            },
            gs: function (gs) {
                return gs;
            },
            cls: function (s) {
                return s;
            },
            uri: function (uri) {
                return uri;
            },
            title: function (t) {
                return t;
            }
        };
        return tmpl.replace(/{(\w+)}/g, function (m1, m2) {
            if (!m2) return "";
            return (format && format[m2]) ? format[m2](dta[m2]) : dta[m2];
        });
    }

    /**
     *  setting :
     *  {
     *  container : 'div id or jquery object',
     *  servlet : 'servlet url',
     *  layoutMode : 'double page or single page'
     *  viewMode : 'image text or mix'
     * }
     */
    /**
     *
     * @param setting
     * @returns {Core}
     * @constructor
     */
    function Core(setting) {
        this.uid = RU.uuid();
        this.file = false;
        this.extra = {};
        this.modified = false;
        this.globalState = VIEW;
        this.count = 1;

        var T = this, opts = {};
        var fire = function (event) {
            Q(T).trigger(event, Q.makeArray(arguments).slice(1));
        };
        var fireUI = function (setting) {
            fire(UIACTION, setting)
        };
        var fireCore = function (setting) {
            fire(COREACTION, setting)
        };
        Q(T).on(BP.Operate + NAME, function (_, cmd) {
            var fun = this[cmd] || opts[cmd];
            if (Q.isFunction(fun)) {
                var ret = RU.doApply(fun, T, Q.makeArray(arguments).slice(2));
                if (RU.isNotNull(ret)) {
                    fire(BP.Action + NAME, cmd, ret);
                }
            } else {
                L.info('Not found opt ' + cmd);
            }
        }).on(BP.Book + 'view', function () {
            var viewMode = $.makeArray(arguments).slice(1)[0];
            switch (viewMode) {
                case RC.ViewMode.Mix :
                    T.globalState = SELECT;
                    break;
                case RC.ViewMode.Text :
                    T.globalState = SELECT;
                    break;
                case RC.ViewMode.Image :
                    T.globalState = VIEW;
                    break;
            }
        });

        var IM = (W._Origin === 'mobile');
        IM && L.info('Device is mobile');
        var cfg = Q.extend({}, setting), listener = {};

        var pocket = RU.isText(cfg.container) ? RE.qI(cfg.container) : Q(cfg.container);
        pocket.css({'overflow': 'auto'});

        var doc = null, root = null, flip = null;

        var reset = function () {
            var coc = function (tar, fun) {
                if (tar) {
                    return Q(tar).removeData();
                } else {
                    return Q(fun());
                }
            };

            doc = coc(doc, function () {
                return RE.qNv().prop('id', T.uid).addClass(BC.Document).appendTo(pocket);
            });
            root = coc(root, function () {
                return RE.qNv().addClass(BC.Root).appendTo(doc);
            });
        };

        reset();

        var Rq = this.asker = new R.Request(cfg.servlet || Config.servlet);
        var Hp = new _Helper(pocket, root);
        var Do = new _Do(this, Rq, Hp);

        var build = function (index) {
            var ret = Rq.builder(T.extra).file(T.file).version(T.Pagination.version());
            var i = Hp.pageIndex(index);
            !isNaN(i) && i >= 0 && ret.page(i);
            return ret;
        };

        this.param = function (index, ext) {
            return Q.extend({}, build(index).version(this.Pagination.version()).build(), ext);
        };

        var closed = false;

        var viewMgr = new function () {
            var VM = RC.ViewMode;

			//cfg['viewMode'] ||
            var old, current =  VM.Mix;
            //强制改为图片模式
            if (RU.iev <= 9 && current == VM.Mix) {
                current = VM.Image;
            }
            var fireMode = function (nv, ov) {
                fire(BP.Book + 'view', nv, ov);
            };

            fireMode(current);

            this.isImage = function (mode) {
                if (RU.isNull(mode)) {
                    mode = current;
                }
                return mode === VM.Image || mode === VM.Mix;
            };

            this.isText = function (mode) {
                if (IM) { // mobile not support text
                    return false;
                }
                if (RU.isNull(mode)) {
                    mode = current;
                }
                return mode === VM.Text || mode === VM.Mix;
            };

            this.isMix = function (mode) {
                if (RU.isNull(mode)) {
                    mode = current;
                }
                return mode === VM.Mix;
            };

            this.value = function (mode) {
                if (RU.isNull(mode) || current === mode) {
                    return current;
                }
                old = current;
                current = mode;

                var ms = RE.qC(BC.Main, root).removeClass(BC.PageMix).removeData(BD.LoadState);
                if (this.isMix()) {
                    ms.addClass(BC.PageMix);
                    RE.qC(BC.Palette, ms).removeClass(BC.Hide);
                    RE.qC(BC.Background, ms).removeClass(BC.Hide);
                    if (RU.iev >= 10) {
                        RE.qC(BC.Content, ms).removeClass(BC.Hide);
                    } else {
                        RE.qC(BC.Content, ms).addClass(BC.Hide);
                    }
                } else if (this.isText()) {
                    RE.qC(BC.Background, ms).addClass(BC.Hide);
                    RE.qC(BC.Palette, ms).addClass(BC.Hide);
                    RE.qC(BC.Content, ms).removeClass(BC.Hide);
                } else if (this.isImage()) {
                    RE.qC(BC.Background, ms).removeClass(BC.Hide);
                    RE.qC(BC.Palette, ms).removeClass(BC.Hide);
                    RE.qC(BC.Content, ms).addClass(BC.Hide);
                }
                lazyLoad.call(T, 1);
                fireMode(current, old);
                return current;
            };
        };
        var zoomMgr = new function () {
            var base = RC.DPI, ZM = RC.ZoomMode;
            var old = cfg['zoom'] || 1;
            var current = old;//val
            var lastZoom = 1;
            var DPIs = Config.dpiRange || [48, 96, 144, 192];
            var min = 0.5, max = 64;
            var zoom = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 4, 6, 8, 16, 32, 64];
            var partBase = Config.partBase || 2000;
            var fireMode = function (nv, ov) {
                fire(BP.Book + 'zoom', nv, ov);
            };

            fireMode(current);

            var maxWidthMM = 0, maxHeightMM = 0;
            this.zoom = function () {
                return current;
            };
            this.setMaxMM = function (w, h) {
                maxWidthMM = w;
                maxHeightMM = h;

                return this;
            };

            this.maxWidth = function (dpi) {
                return Hp.mm2px(maxWidthMM, dpi);
            };
            this.maxHeight = function (dpi) {
                return Hp.mm2px(maxHeightMM, dpi);
            };

            var isFitWidth = function (v) {
                return v === ZM.FitW;
            };

            this.origin = function () {
                return base;
            };

            this.dpi = function () {
                if (layoutMgr.isFlip()) {
                    return this.compute(ZM.FitH);
                }
                var ret = this.compute(current);
                if (isFitWidth(current) && layoutMgr.isDoubleSerial()) {
                    ret /= 2;
                }
                return Math.round(ret);
            };

            this.compute = function (val) {
                var ret = 0;
                if (val === ZM.FitW) {
                    ret = RU.dpi(Hp.fitWidth(), maxWidthMM);
                } else if (val === ZM.FitH) {
                    ret = RU.dpi(Hp.fitHeight(), maxHeightMM);
                } else if (Q.isNumeric(val)) {
                    var n = parseFloat(val);
                    ret = n > 64 ? RU.dpi(n, maxWidthMM) : base * n;
                }
                return Math.round(ret);
            };

            this.reqDPI = function (dpi) {
                var n = dpi;
                if (RU.isNull(n)) {
                    n = this.dpi() * RC.DevicePixelRatio;
                }
                return DPIs.closest(n);
            };

            this.resize = function () {
                if (!layoutMgr.isSingle() && Q.isNumeric(current)) {
                    current = Math.min(2, current)
                }
                var v = this.dpi(), rv = this.reqDPI();
                rotateMgr.reset();

                //翻页模式排版
                function resizeTurn() {
                    RE.qC(BC.Main, root).removeData(BD.LoadState).each(function (_, mn) {
                        var main = Q(mn), w = main.attr(BA.PageWidth), h = main.attr(BA.PageHeight);
                        var ext = main.siblings('.' + BC.Extend), show = !ext.hasClass(BC.Hide);
                        var wpx = Hp.mm2px(w, v), scale = show ? 3 / 4 : 1;
                        main.css({
                            width: wpx * scale, height: Hp.mm2px(h, v) * scale
                        }).attr('_resize', true);

                        if (RE.qC(BC.Watermark, main).children().length > 0) {
                            RE.qC(BC.Watermark, main).empty();
                        }
                        if (show) {
                            ext.width(wpx / 4).attr('_resize', true);
                        }
                    });
                }

                //单双页排版
                function resize() {
                    if (layoutMgr.isSingle()) {
                        var main = RE.qC(BC.Main, root), w = main.attr(BA.PageWidth), h = main.attr(BA.PageHeight);
                        var ext = main.siblings('.' + BC.Extend), show = !ext.hasClass(BC.Hide);
                        var wpx = Hp.mm2px(w, rv), hpx = Hp.mm2px(h, rv), scale = show ? 3 / 4 : 1;
                        main.css({
                            width: wpx * scale, height: hpx * scale
                        }).attr('_resize', true);
                        var part = 0;
                        var table = Q('<table border="0" cellspacing="0" cellpadding="0"></table>');

                        for (var i = 0; i < hpx / (partBase * 1.415); i++) {
                            var tr = Q('<tr></tr>');
                            var pw = partBase, ph = partBase * 1.415;
                            if (ph * (i + 1) > hpx) {
                                ph = hpx - ph * i;
                            }
                            for (var j = 0; j < wpx / partBase; j++) {
                                if (pw * (j + 1) > wpx) {
                                    pw = wpx - pw * j;
                                }
                                Q('<td part="' + part + '" style="width: ' + pw + 'px;height: ' + ph + 'px"></td>').appendTo(tr);
                                part++;
                            }
                            table.append(tr);
                        }
                        RE.qC(BC.Background, main).empty().append(table);
                        main.removeData(BD.LoadState)/*.addClass(BC.PageMix)*/
                        main.data(BD.PartBase, partBase);
                    } else {
                        RE.qC(BC.Morph, root).each(function (_, mh) {
                            //var time = Q.now();
                            var total = 0, max = 0, morph = Q(mh);
                            RE.qC(BC.Main, morph).removeData(BD.LoadState).each(function (_, mn) {
                                var main = Q(mn), w = main.attr(BA.PageWidth), h = main.attr(BA.PageHeight);
                                var ext = main.siblings('.' + BC.Extend), show = !ext.hasClass(BC.Hide);
                                var wpx = Hp.mm2px(w, v), hpx = Hp.mm2px(h, v), scale = show ? 1 : 1;
                                main.css({
                                    width: wpx * scale, height: hpx * scale
                                }).attr('_resize', true);
                                main.siblings("." + BC.Extend).height(hpx * scale);
                                main.removeData(BD.PartBase);
                                if (RE.qC(BC.Watermark, main).children().length > 0) {
                                    RE.qC(BC.Watermark, main).empty();
                                }
                                if (show) {
                                    ext.width(wpx / 4).attr('_resize', true);
                                }
                                total += wpx;
                                max = Math.max(max, wpx);
                                if (show) {
                                    max += wpx / 4;
                                    total += wpx / 4;
                                }
                            });
                            morph.width(layoutMgr.isDoubleSerial() ? total + 30 : max + 10);
                            //L.debug('Resize page ' + _, Q.now() - time);
                        });
                    }
                }

                layoutMgr.isFlip() ? resizeTurn() : resize();
                lazyLoad.call(T, 1);
                if (rotateMgr.rotateValue != 0) {
                    rotateMgr.value(rotateMgr.rotateValue);
                }
            };
            this.closest = function (arr, closestTo) {
                //apply应用某一对象的一个方法，用另一个对象替换当前对象。
                var closest = Math.max.apply(null, arr); //Get the highest number in arr in case it match nothing.
                closestTo = closestTo.toString().match(/^\d+(?:\.\d{0,2})?/);
                for (var i = 0; i < arr.length; i++) { //Loop the array
                    if (arr[i] >= closestTo && arr[i] < closest) {
                        closest = arr[i]; //Check if it's higher than your number, but lower than your closest value
                    }
                }
                return closest; // return the value
            }

            this.value = function (mode, only) {
                if (mode === true) {
                    return this.dpi();
                }
                if (mode == '-') {
                    var now = this.closest(zoom, lastZoom);
                    var index = Math.max(0, $.inArray(now, zoom) - 1);
                    mode = zoom[index];
                } else if (mode == '+') {
                    var now = this.closest(zoom, lastZoom);
                    var index = Math.min(zoom.length - 1, $.inArray(now, zoom) + 1);
                    mode = zoom[index];
                }
                if (RU.isNull(mode) || isNaN(mode) || current === mode) {
                    fireMode(current, old);
                    if (mode != ZM.FitW && mode != ZM.FitH) return current;
                }
                if (Q.isNumeric(mode)) {
                    var n = parseFloat(mode);
                    mode = Math.min(max, Math.max(min, n));
                    mode = zoom.closest(mode);
                }
                if (!layoutMgr.isSingle() && mode >= 4) {
                    T.Alert('高倍放大请切换到单页模式');
                    /*layer.open({
                        content: '高倍放大请切换到单页模式'
                        , skin: 'msg'
                        , time: 4 //2秒后自动关闭
                    });*/
                    return;
                }
                old = current;
                current = mode;
                if (!only) {
                    L.info('Zoom to {0}'.format(mode));
                    this.resize();
                    lastZoom = current;
                    fireMode(current, old);
                    //if (!layoutMgr.isSingle()) {
                    var n = this.compute(current), o = this.compute(old)
                    var offset = root.offset(), docWidth = doc.width() / 2, docHeight = doc.height() / 2,
                        dw = docWidth * (n / o - 1), dt = docHeight * (n / o - 1), docOffset = doc.offset();
                    var top = Math.abs(offset.top) * (n / o), left = Math.abs(offset.left);
                    doc.scrollTop(top + dt + docOffset.top);
                    doc.scrollLeft(left + dw);
                    //}
                }
                return current;
            };

            var extShow = new RU.comparer(false);
            opts['extend'] = function (visible) {
                var es = RE.qC(BC.Extend, root);
                if (visible == "toggle") {
                    es.toggleClass(BC.Hide);
                    zoomMgr.resize();
                    return;
                }
                //清空搜索
                $('.closeSearchBtn', $('.searchBox')).click();
                if (visible) {
                    es.removeClass(BC.Hide);
                    fireUI(['edit:extend:toggle', BUTTON_STATUS.SELECT])
                } else {
                    es.addClass(BC.Hide)
                    fireUI(['edit:extend:toggle', BUTTON_STATUS.UNSELECT])
                }
                zoomMgr.resize();
            };
        };

        var rotateMgr = new function () {
            var fireRotate = function (nr, or) {
                fire(BP.Core + 'rotate', nr, or);
            };
            this.reset = function () {
                RE.qC(BC.Faker, root).removeAttr("style").removeAttr(BA.PageRotate);
                //RE.qC(BC.Morph, root).removeAttr("style");
            };
            this.rotateValue = 0;
            this.checkRotate = function (key, value) {
                var r = value;
                switch (key) {
                    case "+":
                        r += 90;
                        break;
                    case "-":
                        r -= 90;
                        break;
                    default:
                        r = this.rotateValue;
                }
                if (r < 0) {
                    r = 360 + r;
                } else if (r >= 360) {
                    r = r - 360
                }
                return r;
            }
            this.rotate = function (key, dom) {
                var r = parseInt(dom.attr(BA.PageRotate)) || 0;
                r = this.checkRotate(key, r)
                var dp = RE.qC(BC.Page, dom);
                var dw = dp.width(), dh = dp.height(), dwh = dh - dw, isTransversal = dw > dh;
                var siblings = dom.siblings(), morph = dom.closest("." + BC.Morph);
                var isFirst = parseInt(RE.qC(BC.Main, dom).prop("id").slice(1)) % 2 == 0;
                isFirst ? doF() : doS();

                function doF() {
                    var h = 0, isRotate = false, domTranslate = "";
                    if (r / 90 % 2 == 0) {
                        h += dh;
                        dom.css({
                            transform: "rotate(" + r + "deg) " + domTranslate + ""
                        }).attr(BA.PageRotate, r);
                    } else {
                        isRotate = true;
                        h += dw;
                        dom.css({
                            transform: "rotate(" + r + "deg) translateX(" + (r / 90 == 3 ? dwh : -dwh) / 2 + "px)"
                        }).attr(BA.PageRotate, r);
                    }

                    if (siblings) {
                        var sw = siblings.width(), sh = siblings.height(), swh = sh - sw, translate = "", tx = 0;
                        dh = Math.max(dh, sw);
                        var rotate = parseInt(siblings.attr((BA.PageRotate))) || 0;
                        switch (rotate) {
                            case 270:
                                h += sw;
                                isRotate ? tx = dwh + swh / 2 : tx = swh / 2;
                                translate = "translateX( " + tx + "px)";
                                break;
                            case 90:
                                h += sw;
                                isRotate ? tx = -(dwh + swh / 2) : tx = -(swh / 2);
                                translate = "translateX( " + tx + "px)";
                                break;
                            default:
                                h += sh;
                                isRotate ? tx = -dwh : tx = 0;
                                translate = "translateY( " + tx + "px)";
                                break;
                        }
                        siblings.css({
                            transform: "rotate(" + rotate + "deg) " + translate + ""
                        })
                    }
                    if (isTransversal) {
                        dh = dw
                    }
                    morph.height(h + 13).width(dh + 10);
                }

                function doS() {
                    var h = 0;
                    if (siblings) {
                        var sw = siblings.width(), sh = siblings.height(), swh = sh - sw, tx = 0,
                            sIsTransversal = sw > sh;
                        var rotate = parseInt(siblings.attr((BA.PageRotate))) || 0, isRotate = rotate / 90 % 2 == 1,
                            translate = "";

                        isRotate ? h = sw : h = sh;
                        switch (r) {
                            case 90:
                                h += dw;
                                dh = Math.max(dh, sw);
                                isRotate ? tx = -(dwh + swh / 2) : tx = -swh / 2;
                                isTransversal ? translate = "translate(" + -tx + "px," + -tx + "px)" : translate = "translateX(" + tx + "px)";
                                if (sIsTransversal) {
                                    translate = translate = "translateX(" + tx + "px)";
                                }
                                break;
                            case 270:
                                h += dw;
                                dh = Math.max(dh, sw);
                                isRotate ? tx = dwh + swh / 2 : tx = swh / 2;
                                isTransversal ? translate = "translate(" + -tx + "px," + -tx + "px)" : translate = "translateX(" + tx + "px)";
                                if (sIsTransversal) {
                                    translate = translate = "translateX(" + tx + "px)";
                                }
                                break;
                            case 0:
                                h += dh;
                                dh = Math.max(dw, sh);
                                isRotate ? tx = -dwh : tx = 0;
                                isTransversal ? translate = "translateX(" + dwh / 2 + "px)" : translate = "translateY(" + tx + "px)";
                                if (sIsTransversal) {
                                    translate = translate = "translateY(" + tx + "px)";
                                }
                                break;
                            case 180:
                                h += dh;
                                dh = Math.max(dw, sh);
                                isRotate ? tx = dwh : tx = 0;
                                isTransversal ? translate = "translateX(" + -dwh / 2 + "px)" : translate = "translateY(" + tx + "px)";
                                if (sIsTransversal) {
                                    translate = translate = "translateY(" + tx + "px)";
                                }
                                break;
                        }
                        dom.css({
                            transform: "rotate(" + r + "deg)" + translate + ""
                        }).attr(BA.PageRotate, r);
                    }
                    morph.height(h + 13).width(dh + 10);

                }

                //解决图片模糊
                var main = RE.qC(BC.Main, dom), width = Hp.mm2px(main.attr(BA.PageWidth), zoomMgr.dpi());
                if (r / 90 % 2 == 1 && width % 2 == 0) {
                    main.width(width - 1);
                } else {
                    main.width(width);
                }
            }
            this.rotateDouble = function (key) {
                var r = this.checkRotate(key, this.rotateValue);
                var domTranslate = "", maxW = 0, maxH = 0;
                Q.each(RE.qC(BC.Morph, root), function (i, m) {
                    var morph = Q(m), mw = 0, mh = 0;
                    Q.each(RE.qC(BC.Faker, morph), function (i, f) {
                        var f = Q(f), fw = f.width(), fh = f.height(), hw = (fh - fw) / 2;
                        mw = mw + fw, mh = mh + fh;
                        maxW = Math.max(fw, maxW), maxH = Math.max(fh, maxH);
                        switch (r) {
                            case 90:
                                i == 0 ? domTranslate = "translateX(" + -hw + "px) translateY(" + hw + "px)" : domTranslate = "translateX(" + -hw + "px) translateY(" + -hw + "px)"
                                break;
                            case 270:
                                i == 0 ? domTranslate = "translateX(" + hw + "px) translateY(" + -hw + "px)" : domTranslate = "translateX(" + hw + "px) translateY(" + hw + "px)"
                                break;
                        }
                        f.css({
                            transform: "rotate(" + r + "deg) " + domTranslate + ""
                        }).attr(BA.PageRotate, r);
                    })
                    if (r / 90 % 2 != 0) {
                        morph.height(maxW + 6);
                        morph.width(mh + 16);
                    } else {
                        morph.height('auto');
                        morph.width(mw + 16);
                    }
                })

            }
            this.rotateSingle = function (key) {
                var r = this.checkRotate(key, this.rotateValue);
                var faker = RE.qC(BC.Faker, root), fw = faker.width(), fh = faker.height(), hw = (fh - fw) / 2,
                    domTranslate = "";
                switch (r) {
                    case 90:
                        domTranslate = "translateX(" + hw + "px) translateY(" + -hw + "px)"
                        faker.width(fh).height(fw)
                        break;
                    case 270:
                        domTranslate = "translateX(" + hw + "px) translateY(" + -hw + "px)";
                        faker.width(fh).height(fw)
                        break;
                    default:
                        faker.width("auto").height("auto")
                }
                faker.css({
                    transform: "rotate(" + r + "deg) " + domTranslate + ""
                }).attr(BA.PageRotate, r)
            }
            this.doRotate = function (mode) {
                if (layoutMgr.isSingleSerial()) {
                    Q.each(RE.qC(BC.Faker, root), function (_, f) {
                        rotateMgr.rotate(mode, Q(f));
                    })
                } else if (layoutMgr.isDoubleSerial()) {
                    rotateMgr.rotateDouble(mode)
                } else {
                    rotateMgr.rotateSingle(mode)
                }
            }

            this.value = function (mode, dom) {
                if (layoutMgr.isFlip()) {
                    this.reset();
                    return;
                }
                switch (mode) {
                    case '++':
                        this.doRotate('+');
                        this.rotateValue += 90;
                        break;
                    case '--':
                        this.doRotate('-');
                        this.rotateValue -= 90;
                        break;
                    default:
                        if (dom) {
                            if (dom instanceof Object) {
                                rotateMgr.rotate(mode, Q(dom));
                            }
                        } else {
                            this.doRotate("")
                        }
                        break;
                }
                var or = this.rotateValue;
                if (this.rotateValue <= 0) {
                    this.rotateValue = 360 + this.rotateValue;
                } else if (this.rotateValue >= 360) {
                    this.rotateValue = this.rotateValue - 360
                }
                fireRotate(or, this.rotateValue);
                if (this.rotateValue == 0) {
                    Config.painter && fireCore(['edit', BUTTON_STATUS.UNDISABLED])
                    this.reset();
                } else {
                    Config.painter && fireCore(['edit', BUTTON_STATUS.DISABLED])
                }
            }
        }
        var RESIZE = '_resize';
        var layoutMgr = new function () {
            var LM = RC.LayoutMode;

            var old, current = cfg['layoutMode'] || LM.SingleSerial;

            var keeper = {
                root: Q(root).clone().detach()
            };

            this.swap = function () {
                var old = root.detach();
                root = keeper.root.appendTo(doc);
                keeper.root = old;
                return root;
            };

            var fireMode = function (nv, ov) {
                fire(BP.Core + 'layout', nv, ov);
            };


            this.isDoubleSerial = function (mode) {
                if (RU.isNull(mode)) {
                    mode = current;
                }
                return mode === LM.DoubleSerial;
            };
            this.isSingleSerial = function (mode) {
                if (RU.isNull(mode)) {
                    mode = current;
                }
                return mode === LM.SingleSerial;
            };
            this.isFlip = function (mode) {
                if (RU.isNull(mode)) {
                    mode = current;
                }
                return mode === LM.Double;
            };
            this.isSingle = function (mode) {
                if (RU.isNull(mode)) {
                    mode = current;
                }
                return mode === LM.Single;
            };
            this.initNavigation = function (data) {
                RU.doData(doc, BD.DocExpand, data);
                fireUI(["tab", 'init', data])
                fireUI(["tab", true])
            }
            this.hideNavigation = function () {
                fireUI(["tab", false]);
                fireCore(['edit', BUTTON_STATUS.UNDISABLED])
            }
            this.showNavigation = function () {
                var _t = this;
                fireCore(['edit', BUTTON_STATUS.DISABLED])
                var source = RU.doData(doc, BD.DocExpand);
                if (source && source.length > 0) {
                    Q('.tab-list').children().removeClass('actived');
                    fireUI(["tab", true])
                } else {
                    Do.json(R.Action.Expand, build(), function (ret) {
                        if (ret != null && ret.length > 0) {
                            _t.initNavigation(ret)
                        }
                    }, function (ret) {
                        var count = T.Pagination.count(), prefix = T.extra['prefix'], result = [];
                        for (var i = 0; i < count; i++) {
                            result.push({"text": (prefix || "第") + (i + 1) + "页", "value": i});
                        }
                        _t.initNavigation(result);
                        L.warn(ret.responseText + " use defult data")
                    });
                }
            }

            this.value = function (mode) {
                if (RU.isNull(mode) || current === mode) {
                    return current;
                }
                var index = RU.doData(doc, BD.PageIndex);
                var of = this.isFlip(), nf = this.isFlip(mode), os = this.isSingle(), ns = this.isSingle(mode);
                old = current;
                current = mode;
                if (rotateMgr.rotateValue != 0) {
                    rotateMgr.value(rotateMgr.rotateValue);
                }
                if (!ns && of || nf) {
                    this.swap();
                    if (root.children().length <= 0 || T.modified) {
                        reLayout();
                    }
                    if (of) {
                        reLayout();
                        zoomMgr.resize();
                    }
                } else if (!nf && os || ns) {
                    if (of) {
                        this.swap();
                    }
                    reLayout();
                    zoomMgr.resize();
                } else if (!this.isSingle()) {
                    if (of || os) {
                        reLayout();
                    }
                    zoomMgr.resize();
                }
                if (!this.isSingle()) {
                    this.hideNavigation();
                    zoomMgr.value(Math.min(2, zoomMgr.value()));
                } else {
                    this.showNavigation();
                }
                if (!Config.painter) {
                    fireCore(['edit', BUTTON_STATUS.HIDE]);
                }
                T.jump(index)
                fireMode(current, old);
                return current;

            };
            fireMode(current);
        };

        //初始化翻书模式
        var initFlip = function () {
            var dpi = zoomMgr.compute(RC.ZoomMode.FitH);
            root.addClass('rDocumentTurn').turn({
                display: 'double',
                pages: T.Pagination.count(),
                width: zoomMgr.maxWidth(dpi) * 2,
                height: zoomMgr.maxHeight(dpi),
                elevation: 50,
                gradients: true,
                //autoCenter : true,
                when: {
                    missing: function (e, pages) {
                        //Log.debug('Missing', pages);
                    },
                    turning: function (e, page) {
                        RU.doData(doc, BD.PageIndex, page - 1);
                    },
                    turned: function (e, page) {
                        loadPage(page - 1);
                        page % 2 == 0 ? indexChange(Math.min(T.Pagination.count(), page - 1)) : indexChange(Math.max(0, page - 2));
                    }
                }
            });
        };

        var resetPageArea = function (page, area) {
            var w = area[0], h = area[1], r = rotate(area[2]), v = zoomMgr.dpi();
            page.attr(BA.PageWidth, w).attr(BA.PageHeight, h).attr("_retry", false);
            if (r) {
                page.attr(BA.PageRotate, r);
            }
            var ext = page.siblings('.' + BC.Extend), show = !ext.hasClass(BC.Hide);
            var wpx = Hp.mm2px(w, v), hpx = Hp.mm2px(h, v), scale = show ? 1 : 1;
            page.css({
                width: wpx * scale, height: hpx * scale
            }).attr('_resize', true);
            var faker = page.closest('.' + BC.Faker), width = wpx, total = width;
            if (faker) {
                width = Math.max(faker.width(), wpx), total = wpx + faker.width();
            }
            page.closest('.' + BC.Morph).width(layoutMgr.isDoubleSerial() ? total + 20 : width + 10);
        }

        var indexChange = function (page) {
            fire(BP.Page + 'index', Hp.pageIndex(page));
        };
        //加载页,并预加载前后页
        var loadPage = function (index, count) {
            RU.doData(doc, BD.PageIndex, index);
            doPage(Hp.findPage(index, doc).removeData(BD.LoadState));
            setTimeout(function () {
                var c = count || T.Pagination.count();
                for (var i = -2; i <= 3; i++) {
                    if (i === 0) {
                        continue;
                    }
                    var page = Hp.findPage(Math.min(c - 1, Math.max(0, index + i)), doc);
                    if (page.prop('id') != '_' + index) {
                        page.removeData(BD.LoadState);
                        if (page.length > 0) {
                            doPage(page);
                        }
                    }
                }
            });
        };
        /*
         加载页面
         page表示当前页面
         加载页面同时处理图片处理文字
         */
        var doPage = function (page) {
            var _LS = BD.LoadState, pb = page.data(BD.PartBase);
            if (RU.isNotNull(RU.doData(page, _LS))) {
                if (pb) {
                    Q('td', page).each(function (_, td) {
                        var p = Q(td), port = p.attr('part');
                        if (RU.inViewport(pocket, p)) {
                            p.trigger('show');
                        }
                    })
                }
                return;
            }
            var si = viewMgr.isImage(), st = viewMgr.isText(), sw = true;
            RU.doData(page, _LS, (si ? 1 : 0) + (st ? 1 : 0));

            var index = Hp.pageIndex(page), retry = page.attr('_retry') == 'true';
            var hide = T.extra["hidePage"];
            if (hide) {
                hide = hide.split(';').map(function (value) {
                    return parseInt(value)
                })
                if (hide.includes(index)) {
                    page.closest("." + BC.Faker).remove();
                    return;
                }
            }
            L.info('Page {0} loading...'.format(index));
            var data = build(page).version(T.Pagination.version());

            fire(BP.Page + 'loading', page);

            var decrease = function () {
                T.resetRequestMax();
                RU.doData(page, _LS, RU.doData(page, _LS) - 1);
            };
            var checkFinish = function () {
                var v = RU.doData(page, _LS);
                if (v <= 0 || v == 2 && typeof v != 'undefined') {
                    //L.info('State is {0}'.format(v));
                    L.info('Page {0} loaded...'.format(index));
                    page.css('background-image', 'none');
                    if (!layoutMgr.isFlip()) {
                        fire(BP.Page + 'loaded', page, index);
                    } else {
                        Do.bindEvent(page);
                    }
                }
            };
            if (si) {
                var dpi = zoomMgr.reqDPI();
                var ie = {
                    done: function () {
                        decrease();
                        if (!layoutMgr.isFlip() && !layoutMgr.isSingle()) {
                            fire(BP.Page + 'imaged', page, index, this);
                        }
                    },
                    fail: function () {
                        var arg = Q.makeArray(arguments);
                        L.warn(arg);
                        var reload = function () {
                            L.warn('Page {0} image need retry after {1}'.format(index, RC.RequestDelay));
                            setTimeout(function () {
                                Do.image(page, data.clone().dpi(dpi), ie).always(checkFinish);
                            }, RC.RequestDelay);
                        };
                        Q.get(Q(this).prop('src')).then(reload, function (jqXHR) {
                            doFail(jqXHR, page, reload, function (jqXHR) {
                                decrease();
                                checkFinish();
                                L.error('Load page {0} image fail : '.format(index), jqXHR);
                            });
                        });
                    },
                    abort: function () {
                        decrease();
                        L.warn('Load page {0} image abort'.format(index));
                    }
                };
                var partIe = {
                    done: function () {
                        var p = Q(arguments[0]);
                        console.log(RU.doData(p, _LS))
                    },
                    fail: function () {
                        var arg = Q.makeArray(arguments);
                        var p = Q(arg[0]), part = p.attr("part");
                        var reload = function () {
                            L.warn('Page {0} image part {1} need retry after {2}'.format(index, part, RC.RequestDelay));
                            setTimeout(function () {
                                p.trigger("show");
                            }, RC.RequestDelay);
                        };
                        Q.get(Q(this).prop('src')).then(reload, function (jqXHR) {
                            doFail(jqXHR, p, reload, function (jqXHR) {
                                L.error('Load page {0} image fail : '.format(index), jqXHR);
                            });
                        });
                    },
                    abort: function () {
                        decrease();
                        L.warn('Load page {0} image abort'.format(index));
                    }
                };

                function doPart() {
                    Q('td', page).each(function (_, td) {
                        var p = Q(td), part = p.attr('part');
                        p.on('show', function () {
                            p.removeClass(BC.Hide);
                            if (!RU.doData(p, _LS)) {
                                Do.imagePart(p, data.part(part).partBase(pb).clone().dpi(dpi), partIe);
                            }
                        }).on('hide', function () {
                            p.addClass(BC.Hide)
                        })
                        if (RU.inViewport(pocket, p, null, true)) {
                            p.trigger('show');
                        }
                    })
                    //ie.done();
                    // RE.qC(BC.Palette, page).trigger('resize');
                }

                if (pb) {
                    doPart();
                } else {
                    if (retry) {
                        getArea({index: index}, {
                            done: function (ret) {
                                resetPageArea(page, ret[0]);
                                Do.image(page, data.clone().dpi(zoomMgr.reqDPI()), ie).always(checkFinish);
                            }
                        })
                    } else {
                        Do.image(page, data.clone().dpi(zoomMgr.reqDPI()), ie).always(checkFinish);
                    }
                }
            }
            if (st && !IM) {
                var te = {
                    done: function () {
                        var div = RE.qC(BC.Content, page);
                        decrease();
                        fire(BP.Page + 'texted', page, index, div.data(BD.PageText));
                    },
                    fail: function (jqXHR) {
                        doFail(jqXHR, page, function () {
                            L.debug('Page {0} text need retry after {1}'.format(index, RC.RequestDelay));
                            setTimeout(function () {
                                Do.text(page, data, te).always(checkFinish);
                            }, RC.RequestDelay);
                        }, function () {
                            decrease();
                            L.warn('Load page {0} text fail : '.format(index), jqXHR.responseText);
                        });
                    }
                };
                page.one('mouseover', function () {
                    if (fastText == 'true') {
                        Do.text(page, data, te).always(checkFinish);
                    } else {
                        Do.textSpan(page, data, te).always(checkFinish);
                    }
                })
                if (!viewMgr.isImage()) {
                    page.mouseover();
                }
            }

            if (LINK) {
                var linkEvent = {
                    done: function () {
                        L.debug('Do link end');
                    },
                    fail: function (jqXHR) {
                        if (doFail(jqXHR, page, function () {
                            L.debug('Page {0} link need retry after {1}'.format(index, RC.RequestDelay));
                            setTimeout(function () {
                                Do.link(page, data, linkEvent);
                            }, RC.RequestDelay);
                        }, false) !== true) {
                            L.warn('Page {0} Link load fail : '.format(index), jqXHR.responseText);
                        }
                    }
                };
                var actionsEvent = {
                    done: function () {
                        L.debug('Do actions end');
                    },
                    fail: function (jqXHR) {
                        if (doFail(jqXHR, page, function () {
                            L.debug('Page {0} Actions need retry after {1}'.format(index, RC.RequestDelay));
                            setTimeout(function () {
                                Do.actions(page, data.type('click'), linkEvent);
                            }, RC.RequestDelay);
                        }, false) !== true) {
                            L.warn('Page {0} Actions load fail : '.format(index), jqXHR.responseText);
                        }
                    }
                };
                Do.checkActions(page, data);
                Do.actions(page, data.type('click'), actionsEvent);
                Do.link(page, data, linkEvent)
            }
        };
        /*
        * 页面超链接
        * */
        if (ALINK) {
            var at = {
                done: function (ret) {
                    if (typeof ret == 'object') {
                        Q(T).on(BP.Page + 'texted', function () {
                            var page = arguments [1];
                            var texts = arguments [3];
                            if (typeof texts == 'undefined') {
                                texts = RE.qC(BC.Content, page).data(BD.PageText);
                            }
                            if (fastText) {
                                Do.aLink(texts, page, ret);
                            } else {
                                Do.aLinkSpan(texts, page, ret);
                            }

                        }).on(BP.Book + 'zoom', function () {
                            RE.qC(BC.ALink, doc).remove();
                        })
                    } else {
                        console.log("数据类型错误")
                    }
                },
                file: function (ret) {
                    console.log(ret);
                }
            }
            Q(T).on(BP.Book + 'opened', function () {
                Rq.json(R.Action.Alink, build(), at);
            })
        }

        var fillContextMenu = function (config) {
            if (Q.isEmptyObject(config)) {
                config = {
                    "menu": RU.baseMenu()
                }
            }
            var txt;
            var copy = function () {
                if (RU.iev <= 11) {
                    window.clipboardData.setData('text', txt);
                } else {
                    document.execCommand("copy");
                }
            };
            var search = function (options) {
                var target = options.items.search.target;
                if (target) {
                    target = target.replace('${selected}', txt);
                    window.open(target)
                }
            }
            var doClick = function (key, options) {
                if (txt.length <= 0) {
                    alert("未选中任何文字!");
                    return;
                }
                switch (key) {
                    case 'copy':
                        copy();
                        break;
                    case 'search':
                        search(options);
                        break;
                    default:
                        doCategoryClick(key, options)
                        return;
                        var script = options.items[key]['script'];
                        if (script) {
                            var values = {text: txt}
                            var page = options.$trigger.find('.' + BC.Main);
                            if (page) {
                                values['index'] = parseInt(page.attr('id').slice(1)) + 1;
                            }
                            script = script.replace("${values}", JSON.stringify(values));
                            try {
                                eval(script);
                            } catch (e) {
                                alert(e.message);
                                console.log(e)
                            }
                        }
                }
                T.callAfter([{key: key, text: txt, extra: T.extra}]);
            }
            var doCategoryClick = function (key, options) {
                var oldKey = options['item'] && options['item'][0], text = options['data'] && options['data'].text;
                switch (key) {
                    case 'cancel':
                        fire(BP.Operate + "ops", 'search', 'cancelColor', [options['item']]);
                        break;
                    default:
                        fire(BP.Operate + "ops", 'search', 'changeCategory', [options['item'], key, txt]);
                }
                T.callAfter({data: {newKey: key, oldKey: oldKey, text: txt || text}, extra: T.extra});
            }

            RU.contextMenu({
                selector: '.' + BC.Main,
                build: function ($trigger, e) {
                    var target = e['target'], item = Q(target).attr(BA.Category);
                    Q.map(config.menu, function (v, key) {
                        //if (T.callBefore(key) === false) {
                        config.menu[key]['disabled'] = false;
                        //}
                    })

                    if (item) {
                        var menu = config.menu[item[0]];
                        item = item.split("_");
                        menu ? menu['disabled'] = true : null;
                    } else {
                        config.menu['cancel'] ? config.menu['cancel']['disabled'] = true : null;
                    }
                    txt = window.getSelection ? window.getSelection().toString() : document.selection.createRange().text.toString();
                    if (txt.length <= 0) {
                        if (target && Q(target).attr(BA.Category)) {
                            return {
                                callback: doCategoryClick,
                                items: config.menu,
                                item: item,
                                data: RU.doData(Q(target), BD.Value)
                            }
                        }
                        if (Config.painter) {
                            return false;
                        }
                        return {
                            callback: function (key) {
                                rotateMgr.value(key, Q(e.currentTarget));
                            },
                            items: RU.rotateMenu()
                        }
                    } else {
                        return {
                            callback: doClick,
                            items: config.menu
                        }
                    }

                }
            });
        }
        if (!disableMenu && !IM) {
            document.oncontextmenu = document.body.oncontextmenu = function () {
                return false;
            };
            var ac = {
                done: function (ret) {
                    //RU.doData(doc, BD.DocContextMenu, ret);
                    if (typeof ret == 'object') {
                        fillContextMenu(RU.parseJSON(ret));
                    }
                },
                file: function (ret) {
                    console.log(ret);
                }
            };
            Q(T).on(BP.Book + 'opened', function () {
                Rq.json(R.Action.ContextMenu, build(), ac);
            });
        } else {
            document.oncontextmenu = document.body.oncontextmenu = function () {
                return false;
            };
        }

        /*
         加载inView的page
         */
        var doLoad = function () {
            if (closed) {
                return;
            }
            //L.debug('Traversal pages');
            var first, prev = [], show = [], next = [];
            RE.qC(BC.Main, doc).each(function (_, e) {
                var page = Q(e);
                if (RU.inViewport(pocket, page, null, layoutMgr.isSingle() || layoutMgr.isDoubleSerial())) {
                    show.push(page);
                    first = first || page;
                } else {
                    first ? next.push(page) : prev.push(page);
                }
            });
            if (first) {
                var index = Hp.pageIndex(first);
                RU.doData(doc, BD.PageIndex, index);

                Q.isNumeric(index) ? indexChange(index) : null;
            }
            var hide = function (e) {
                if (!IM) {
                    e.children().addClass(BC.Hide);
                }
            };
            if (next.length) {
                RU.forEach(next.slice(1), hide);
                show.push(next[0]);
            }
            if (prev.length) {
                RU.forEach(prev.slice(0, prev.length - 1), hide);
                show.push(prev[prev.length - 1]);
            }
            RU.forEach(show, function (e) {
                setTimeout(function () {
                    /*if (viewMgr.isText() && !viewMgr.isMix()) {
                        e.children('.' + BC.Background).addClass(BC.Hide);
                        e.children('.' + BC.Content).removeClass(BC.Hide);
                    } else if (T.globalState == EDIT) {
                        e.children('.' + BC.Background).removeClass(BC.Hide);
                        e.children('.' + BC.Content).addClass(BC.Hide);
                    } else if (T.globalState == VIEW && RU.iev < 10) {
                        e.children('.' + BC.Background).removeClass(BC.Hide);
                        e.children('.' + BC.Content).addClass(BC.Hide);
                    } else if (viewMgr.isImage() && RU.iev <= 8) {
                        e.children('.' + BC.Background).removeClass(BC.Hide);
                        e.children('.' + BC.Content).addClass(BC.Hide);
                    } else {
                        e.children('.' + BC.Background).removeClass(BC.Hide);
                        e.children('.' + BC.Content).removeClass(BC.Hide);
                    }*/
                    //e.children('.' + BC.Palette).removeClass(BC.Hide);
                    if (viewMgr.isMix()) {
                        e.children('.' + BC.Background).removeClass(BC.Hide);
                        e.children('.' + BC.Palette).removeClass(BC.Hide);
                        e.children('.' + BC.Content).removeClass(BC.Hide);
                    } else if (viewMgr.isImage()) {
                        e.children('.' + BC.Background).removeClass(BC.Hide);
                        e.children('.' + BC.Palette).removeClass(BC.Hide);
                        e.children('.' + BC.Content).addClass(BC.Hide);
                    } else if (viewMgr.isText()) {
                        e.children('.' + BC.Background).addClass(BC.Hide);
                        e.children('.' + BC.Palette).addClass(BC.Hide);
                        e.children('.' + BC.Content).removeClass(BC.Hide);
                    }
                    e.children('.' + BC.Cover).removeClass(BC.Hide);
                    e.children('.' + BC.Watermark).removeClass(BC.Hide);
                    doPage(e);
                    RU.forEach([e, e.siblings('.' + BC.Extend)], function (d) {
                        if (RU.bool(d.attr(RESIZE))) {
                            d.attr(RESIZE, false).children().addBack().trigger('resize');
                        }
                    });
                });
            });
        };
        /*
         加载页面
         */
        var loading;
        var lazyLoad = function (delay) {
            loading && clearTimeout(loading);
            loading = setTimeout(doLoad, parseInt(delay) || RC.RequestMerge);
        };
        doc.resize(lazyLoad).scroll(lazyLoad);

        //处理请求失败
        var doFail = function (jqXHR, page, retry, fail) {
            var code = parseInt(jqXHR.status), errorMessage = Config.errorMessage;
            if (isNaN(code)) {
                code = -1;
            }
            if (code === BS.RetryWith && T.count++ < RC.RequestMax()) {
                RU.doApply(retry, T);
                return true;
            } else if (fail !== false) {
                T.resetRequestMax();
                var errorHtml = '<!DOCTYPE html>' +
                    '<html>' +
                    '<head>' +
                    '<meta charset="utf-8" />' +
                    '</head>' +
                    '<body>' +
                    '<div  style="margin: 2px">' +
                    '    <img src="./reader/static/image/error.png" >' +
                    '</div>' +
                    '<br>' +
                    '<div ><span style="font-size: 18px">' + errorMessage + '</span></div>' +
                    /* '<div><a id="click" style="text-decoration: underline">出错了,点击查看详情</a></div>' +*/
                    '<div id="message" style="display: none" >${msg}</div>' +
                    '<script type="text/javascript">' +
                    '$("body").click(function () {' +
                    '        window.location.reload();' +
                    '    }); ' +
                    '</script>' +
                    '</body>' +
                    '</html>', msg = jqXHR.responseText, html = '';
                var text = msg ? msg.split(':')[1] : false;
                if (code === BS.NotFound) {
                    html = (text || '文档无法访问') + '<br>可能的原因:&nbsp;没有设置file参数;&nbsp;file无法正确获取;&nbsp;file不是合法的OFD文件';
                } else if (code === BS.Forbidden) {
                    html = (text || '没有访问权限') + '<br>可能的原因:&nbsp;没有设置user参数;&nbsp;user没有资源的权限';
                } else if (code === BS.Error) {
                    html = text || '服务器端错误';
                } else if (code === 200) {
                    html = text || '客户端无法处理服务器返回的数据(gzip)';
                } else {
                    html = msg + '(' + code + ')';
                }
                var show = false;
                if (msg && msg.indexOf("Decrypt file failed") != -1) {
                    html = "解密失败";
                    show = !show;
                }
                html = errorHtml.replace('${msg}', html);
                if (RU.isNull(page) || page === -1) {
                    RE.qNv().html(html).addClass(BC.Message).appendTo(root).attr('title', "点击刷新页面");
                    show ? Q('#message').show() : null;
                    Q('.head').hide();
                } else {
                    var p = page;
                    if (Q.isNumeric(page)) {
                        p = Hp.findPage(page);
                    }
                    RE.qC(BC.Message, p).remove();
                    //页面不抛出错误
                    //RE.qNv().html(html).addClass(BC.Message).appendTo(p);
                }

                fire(BP.Book + 'opened');
                RU.doApply(fail, T, [jqXHR]);
            }
        };
        var rotate = function (r) {
            if (!Q.isNumeric(r)) {
                return 0;
            }
            r = parseInt(r);
            var n = Math.round(r / 90);
            if (n === 0) {
                return 0;
            }
            while (n < 0) {
                n += 4;
            }
            while (n > 4) {
                var i = n - 4;
                if (i < 0) {
                    break;
                }
                n = i;
            }
            return n;
        };
        //处理页面
        var reLayout = function (forceEmpty) {
            if (forceEmpty) {
                root.empty();
            }

            var unselect = '';
            Q.each({
                unselectable: 'on', userSelect: 'none', draggable: false,
                onselectstart: 'function(){return false;}',
                ondragstart: 'function(){return false;}'
            }, function (n, v) {
                unselect += n + '="' + v + '" ';
            });
            //page html template
            var tpl = '<div class="' + BC.Faker + '">' +
                '<div class="' + BC.Page + '">' +
                '   <div class="' + BC.Main + '">' +
                '       <div class="' + BC.Background + '" ' + unselect + '></div>' +
                '       <div class="' + BC.Content + '"></div>' +
                '       <div class="' + BC.Cover + '"></div>' +
                '       <div class="' + BC.Watermark + '"></div>' +
                '       <div class="' + BC.Palette + '"><canvas/></div>' +
                '   </div>' +
                '   <div class="' + BC.Extend + ' ' + BC.Hide + '"><div></div></div>' +
                '</div></div>';

            var info = RU.doData(doc, BD.DocInfo);
            var count = info.count, size = info.size, area = info.area, mains = [], lif = layoutMgr.isFlip(),
                lis = layoutMgr.isSingle();
            var parent = root.empty();
            var mwm = 0, mhm = 0;
            var first = (T.extra && T.extra['first']) || false;//首页凸显
            for (var index = 0; index < count && !lis; index++) {
                if (first == 'true') {
                    if (index == 0) {
                        parent = RE.qNv().addClass(BC.Morph).appendTo(root);
                    } else {
                        if (index % 2 === 1 && !lif) {
                            parent = RE.qNv().addClass(BC.Morph).appendTo(root);
                        }
                    }
                } else {
                    if (index % 2 === 0 && !lif) {
                        parent = RE.qNv().addClass(BC.Morph).appendTo(root);
                    }
                }
                var rect = area ? area[index] : size[index];
                var w = 0, h = 0, r = 0, retry = false;
                if (rect) {
                    w = rect[0], h = rect[1], r = rotate(rect[2]);
                } else {
                    if (area.length >= 2) {
                        w = area[1][0] , h = area[1][1], r = rotate(area[1][2]);
                    } else {
                        w = area[0][0] , h = area[0][1], r = rotate(area[0][2]);
                    }
                    retry = true
                }
                w <= 0 ? w = 210 : null;
                h <= 0 ? h = 297 : null;
                mwm = Math.max(mwm, w);
                mhm = Math.max(mhm, h);

                var main = RE.qC(BC.Main, parent.append(tpl)).last()
                    .prop('id', '_' + index).attr(BA.PageWidth, w).attr(BA.PageHeight, h).attr("_retry", retry);
                if (lif) {
                    main.addClass('own-size').addClass('p' + (index + 1)).addClass(Config.flipType);
                }
                if (viewMgr.isMix()) {
                    main.addClass(BC.PageMix);
                }
                if (r !== 0) {
                    main.attr(BA.PageRotate, r);
                }
                mains.push(main);
            }
            if (lif) {
                RE.qC(BC.Palette, root).remove();
                zoomMgr.setMaxMM(mwm, mhm).resize();
                root = parent.empty().append(mains);
                initFlip();
                Do.bindEvent(root);
            } else if (lis) {
                root = parent.empty().append(tpl);
                RE.qC(BC.Palette, root).remove();
                var index = T.Pagination.current();
                // getArea({index: index}, {
                //     done: function (ret) {
                //         var area = ret[0], w = area[0], h = area[1];
                var pageRect = area ? area[index] : size[index], w = pageRect[0], h = pageRect[1];
                RE.qC(BC.Main, root).prop('id', '_' + index).attr(BA.PageWidth, w).attr(BA.PageHeight, h);
                if (viewMgr.isMix()) {
                    RE.qC(BC.Main, root).addClass(BC.PageMix)
                }
                zoomMgr.setMaxMM(w, h).resize();
                Do.bindEvent(root);
                // }
                //})
            } else {
                zoomMgr.setMaxMM(mwm, mhm).resize();
                Do.bindEvent(root);
            }
        };

        /*
         打开文档
         data表示页面的参数
         done表示回调函数
         */
        var doOpen = function (data, callback) {
            var id = T.file;
            if (closed) {
                Hp.doCall(callback, T, id, -1);
                return;
            }

            fire(BP.Book + 'opening', id, data);
            var info = RU.parseJSON(data);
            var count = info.count, name = info['Title'] || info.name || Config.appName;
            L.debug('Document has {0} pages'.format(count));

            RU.doData(doc, BD.PageCount, count);
            RU.doData(doc, BD.DocInfo, info);
            if (info['type'] && info.type != BF.PDF && info.type != BF.OFD) {
                switch (info.type) {
                    case BF.HTML:
                        doc.empty().append('<iframe class="' + BC.Content + '" src="./resource/' + info.hash + "/" + info.version + '/index.html" style="width: 100%;height:100%;"></iframe>')
                        doc.css({
                            overflow: "hidden"
                        })
                        break;
                    case BF.IMAGE:
                        doc.empty().append('<div class="' + BC.Content + '"  style="width: 100%;height:100%;"><img src="./resource/' + info.hash + "/" + info.version + '/image.dat"></div>')
                        fireUI(['print', BUTTON_STATUS.DISABLED]);
                        break;
                }
                fire(BP.Book + 'opened', name, count, root, info);
                fireCore(['html', BUTTON_STATUS.DISABLED]);
                Hp.doCall(callback, T, id, count, name);
            } else {
                reLayout.call(T, true);
                if (layoutMgr.isSingle()) {
                    layoutMgr.showNavigation();
                }
                fire(BP.Book + 'opened', name, count, root, info);
                fire(BP.Core + 'layout', layoutMgr.value());
                fire(BP.Book + 'zoom', zoomMgr.zoom());
                Hp.doCall(callback, T, id, count, name);
                //doWatermark(T.param());
                LINK && Do.checkActions(root, build().page(-1).type(""))
                if (info['type'] && info.type == BF.PDF) {
                    setTimeout(function () {
                        fireCore(['edit', BUTTON_STATUS.HIDE]);
                    });
                }
            }
            Config.checkPerm && T.checkPermission();
            if (!Config.painter || info['decrypt']) {
                fireCore(['edit', BUTTON_STATUS.HIDE]);
            } else {
                RU.listenerBeforeunload();
            }
        };

        var doOpening;
        /*
         查询文档信息
         成功执行doOpen,失败轮询doOpen
         data表示发送请求的参数
         event表示回调函数
         */
        var doInfo = function (data, event) {
            if (closed) {
                doOpening && clearTimeout(doOpening);
                return;
            }
            L.debug('Request info...');

            function getPassword(value) {
                data.del(true);
                data.decrypt(value);
                doInfo(data, event)
            }

            Do.json(R.Action.Info, data, function (reply) {
                if (reply['isEncrypt']) {
                    T.messageBox("文件已加密!", "请输入密码", {
                        yes: getPassword,
                        no: function () {
                            console.log("click no")
                        }
                    });
                    return;
                }
                if (Q.isPlainObject(reply) && reply['retry'] != true || T.count >= RC.RequestMax()) {
                    if (Config.infoExceptionOpen || reply['retry'] != true) {
                        checkValidity.call(this, Q.extend({
                            decrypt: data.decrypt()
                        }, reply), event);
                    } else {
                        fire(BP.Book + 'opened');
                        alert("获取文档信息异常!")
                    }
                } else {
                    doFail({status: 555}, -1, function () {
                        L.debug('Retry info after {0}'.format(RC.RequestDelay));
                        doOpening = setTimeout(function () {
                            if (T.count == RC.RequestMax()) {
                                data.del(false);
                            } else {
                                data.del(true);
                            }
                            doInfo(data, event);
                        }, RC.RequestDelay);
                    }, event.fail);
                }

            }, function (jqXHR) {
                doFail(jqXHR, -1, function () {
                    L.debug('Retry info after {0}'.format(RC.RequestDelay));
                    doOpening = setTimeout(function () {
                        doInfo(data, event);
                    }, RC.RequestDelay);
                }, event.fail);
            });
        };
        /*检查文档有效期*/
        var checkValidity = function (reply, event) {
            var date = this.getResponseHeader('x-date') || this.getResponseHeader('date');
            var now = new Date(date).getTime();
            var permission = reply['permission'];
            if (permission) {
                var start = permission['StartDate'], end = permission['EndDate'];
                if (start && end) {
                    if (new Date(start).getTime() < now && now < new Date(end).getTime()) {
                        doOpen(reply, event.done);
                    } else {
                        alert('请在有效期内(' + start + '-' + end + ')阅读此文件');
                    }
                } else {
                    doOpen(reply, event.done);
                }
            } else {
                doOpen(reply, event.done);
            }
        }
        /*
        添加水印信息
        成功执行添加水印,失败轮询doWatermark
        data表示发送请求的参数
        event表示回调函数
        */
        var doWatermark = function (data) {
            var pages = [], waterMarkData;
            var fireWatermark = function (setting) {
                T.trigger(BP.Operate + 'ops', ['watermark', 'add', setting, function (status) {
                    //console.log(status);
                }]);
            };
            var we = {
                done: function (data) {
                    waterMarkData = data;
                    Q.each(pages, function (_, page) {
                        fireWatermark(Q.extend({index: Hp.pageIndex(page)}, waterMarkData))
                    });
                },
                file: function (jqXHR) {
                    L.error(jqXHR);
                }
            };
            T.on(BP.Page + 'loaded', function () {
                pages.push(arguments[1]);
                if (waterMarkData) {
                    fireWatermark(Q.extend({index: arguments[2]}, waterMarkData))
                }
            });

            Do.json(R.Action.Watermark, data, function (data) {
                we.done(data);
            }, function (jqXHR) {
                we.file(jqXHR)
            });
        };

        var getArea = function (data, event) {
            var area = function (d) {
                return {
                    x: d.x || 0,
                    y: d.y || 0,
                    w: d.w || 0,
                    h: d.h || 0
                }
            };
            var e = Q.extend({
                done: function (ret) {
                    L.info(ret)
                },
                fail: function (jqXHR) {
                    L.error(jqXHR)
                }
            }, event, true);

            data = Q.extend(area(data), build(data.index || 0).build());
            Do.json(R.Action.Area, data, function (ret) {
                e.done(ret);
            }, function (jqXHR) {
                e.fail(jqXHR)
            });
        };
        /*
         打开文档
         */
        //core.fire('opt:core', ['open', {file:xxx}]);
        this.open = function (data, event) {
            closed = false;
            var file, evt = Q.extend({
                done: function (count) {
                    L.info('Open file done, page count is {0}'.format(count));
                },
                fail: function () {
                    L.warn('Open file fail');
                }
            }, event);

            if (Q.isPlainObject(data)) {
                Q.each(['file', 'docID', 'ticket'], function (_, n) {
                    file = encodeURIComponent(data[n]);
                    return RU.isNull(file);
                });
                var skip = ['file'];//, 'width', 'page' ];
                Q.each(data, function (n, v) {
                    if (Q.inArray(n, skip) !== -1) {
                        return;
                    }
                    T.extra[n] = v;
                });
            } else if (RU.isText(data)) {
                file = data;
            }
            if (!file || file.length === 0) {
                var msg = 'file id invalid';
                fire(BP.Book + 'opened', false, msg);
                Hp.doCall(evt.fail, this, msg);
            } else {
                L.log('Open document ' + file);
                this.file = file;
                zoomMgr.value(parseFloat(data.dpi), true);
                doInfo(build(), evt);
            }
            return this;
        };
        //关闭文档
        //core.fire('opt:core', ['close']);
        this.close = function (callback) {
            closed = true;
            if (doOpening) {
                clearTimeout(doOpening);
            }
            fire(BP.Book + 'closed', this.file);
            reset();
            Hp.doCall(callback, this);
            return this;
        };
        //页码相关 总页数、当前页
        this.Pagination = (function (core) {
            var o = {
                count: function () {
                    var c = parseInt(RU.doData(doc, BD.PageCount));
                    return isNaN(c) ? 0 : c;
                },
                current: function () {
                    var c = parseInt(RU.doData(doc, BD.PageIndex));
                    return isNaN(c) ? 0 : c;
                },
                pageAt: function (index) {
                    return {
                        self: function () {
                            return Hp.findPage(index, root);
                        },
                        text: function (callback) {
                            var page = Hp.findPage(index);
                            var ct = RE.qC(BC.Content, page);
                            if (ct.length > 0 && ct.attr(BA.LoadFlag) === BA.Loaded) {
                                callback(RE.qC(BC.Text, page).text(), index);
                            } else {
                                var fun = function (text, page) {
                                    if (index === page) {
                                        var cbs = listener[BE.PageText];
                                        if (cbs) {
                                            cbs.remove(fun);
                                        }
                                        callback(text, index);
                                    }
                                };
                                T.listen(BE.PageText, fun);
                                doPage(page);
                            }
                        }
                    };
                },
                page: function (index) {
                    return this.pageAt(index).self();
                },
                version: function (v) {
                    var info = RU.doData(doc, BD.DocInfo);
                    if (!info) {
                        return -1;
                    }
                    if (Q.isNumeric(v)) info.version = v;
                    return info.version;
                },
                index: function (page) {
                    return Hp.pageIndex(page);
                },
                info: function () {
                    return RU.doData(doc, BD.DocInfo);
                },
                perm: function () {
                    return RU.doData(doc, BD.DocPerm);
                },
                dpi: function () {
                    return zoomMgr.dpi();
                },
                reload: function (index) {
                    T.modified = true;
                    var is = [];
                    if (Q.isNumeric(index)) {
                        is.push(index);
                    } else if (Q.isArray(index)) {
                        is = is.concat(index);
                    }
                    if (is.length > 0) {
                        is.forEach(function (i) {
                            doPage(Hp.findPage(i, doc).removeData(BD.LoadState));
                        });
                    }
                }
            };
            Q.each({
                First: '|<', Last: '>|', Next: '>', Previous: '<'
            }, function (n, v) {
                o['to' + n] = function () {
                    core.jump(v);
                };
            });
            return o;
        })(this);

        var scroll = function (target, offset, index) {
            var setting = {};
            if (Q.isPlainObject(offset)) {
                var fixValue = function (v) {
                    if (Q.isNumeric(v)) {
                        v = parseFloat(v);
                        if (Math.abs(v) < 2) {//兼容
                            v *= target.width();
                        }
                    } else if (v.charAt(v.length - 1) === '%') {
                        v = parseFloat(v);
                        if (isNaN(v)) {
                            v = 0;
                        } else {
                            v = v * target.width() / 100;
                        }
                    } else {
                        v = 0;
                    }
                    return v;
                };
                setting.offset = {
                    left: fixValue(offset.left != undefined ? offset.left : offset.x),
                    top: fixValue(offset.top != undefined ? offset.top : offset.y)
                };
            }
            if (target.is(':hidden')) {//隐藏的无法直接跳转
                target.parents('.' + BC.Main).children().show();
            }
            doc.scrollTo && doc.scrollTo(target, setting);
            return index;
        };
        /*
         跳转
         target表示目标页面的索引
         offset表示当前位置参数
         */
        //core.fire('opt:core', ['jump', '>']);
        this.jump = function (target, offset, page) {
            if (target instanceof Q) {
                if (root.turn('is')) {
                    var id, index;
                    if (target.hasClass(BC.Main)) {
                        id = target.attr('id');
                    } else {
                        id = target.closest('.' + BC.Main).attr('id');
                    }
                    if (id) {
                        index = id.slice(1);
                    } else {
                        return;
                    }
                    return root.turn('page', parseInt(page || index) + 1);
                } else {
                    return scroll(target, offset);
                }
            }
            var count = this.Pagination.count();
            if (count === 0) {
                L.log('Has no pages to jump');
                return this;
            }
            // 目标的页面的id
            var index = parseInt(target), last = count - 1, current = this.Pagination.current();
            if (isNaN(index)) index = current;

            if (Q.isNumeric(target)) {
                index = RU.int(target);
            } else if (target === '>') {
                index += layoutMgr.isDoubleSerial() || layoutMgr.isFlip() ? 2 : 1;
            } else if (target === '<') {
                index -= layoutMgr.isDoubleSerial() || layoutMgr.isFlip() ? 2 : 1;
            } else if (target === '|<') {
                index = 0;
            } else if (target === '>|') {
                index = last;
            }
            if (index < 0) {
                index = count + index;
            }
            index = Math.max(0, Math.min(index || 0, last));
            if (root.turn('is')) {
                root.turn('page', index + 1);
            } else if (layoutMgr.isSingle()) {
                RE.qC(BC.Main, root).attr("id", "_" + index);
                if (index != RU.doData(doc, BD.PageIndex)) {
                    RU.doData(doc, BD.PageIndex, index);
                    reLayout();
                }
            } else {
                return scroll(Hp.findPage(index), offset, index);
            }


        };
        //缩放
        //core.fire('opt:core', ['zoom', 1]);
        this.zoom = function (val) {
            return zoomMgr.value(val);
        };
        this.zoomScale = function (w, h, index) {
            zoomMgr.setMaxMM(w, h);
            loadPage(index);
        };
        this.zoomRatio = function () {
            return zoomMgr.dpi() / zoomMgr.origin();
        };
        /*
         文档下载
         */
        //core.fire('opt:core', ['download']);
        this.download = function (load, decrypt) {
            /* if (!RU.bool(this.Pagination.perm(), true)) {
                 L.info('No permission for downloading...');
                 return;
             }*/
            if (!Q('iframe').is('.downloader')) {
                Q(W.document.body).append('<iframe class="downloader" style="display:none;"></iframe>');
            }
            var data = build();
            if (decrypt) {
                data.decrypt(decrypt);
            }
            Q('iframe.downloader').on('load', function () {
                if (!Q.isFunction(load)) {
                    load = Q.noop;
                }
                var text = Q.trim(Q('body', Q(this)[0].contentDocument).text());
                if (text && text.length > 0) {
                    var code = parseInt(text.match(/\d+/gm)[0]);
                    L.warn('Download code {0}'.format(code));
                    if (code === RC.Status.Forbidden) {
                        layer.msg('没有下载权限', function () {
                        });
                        load.call(T, 'Forbidden');
                    } else if (code === RC.Status.NotFound) {
                        layer.msg('未找到相关资源', function () {
                        });
                        load.call(T, 'NotFound');
                    } else {
                        layer.msg('错误代码:' + code, function () {
                        });
                        load.call(T, code);
                    }
                } else {
                    load.call(T, 'OK');
                }
            }).prop('src', Rq.action(R.Action.Down) + '?' + data.serialize() + '&_' + Q.now());
        };
        /*
         附件下载
         */
        //core.fire('opt:core', ['downloadLoc']);
        this.downloadLoc = function (loc, name, callback, noLayer) {
            if (!loc) return;
            if (name == null) {
                if (loc.startsWith("Doc") && loc) {
                    name = loc.substring(loc.lastIndexOf("/") + 1, loc.length);
                }
            }

            function doDownLoad() {
                if (!Q('iframe').is('.downloader')) {
                    Q(W.document.body).append('<iframe class="downloader" style="display:none;"></iframe>');
                }
                var data1 = "&name=" + encodeURIComponent(name) + "&loc=" + encodeURIComponent(loc);
                var data = build().serialize() + data1;
                Q('iframe.downloader').on('load', function () {
                    if (!Q.isFunction(callback)) {
                        callback = Q.noop;
                    }
                    var text = Q.trim(Q('body', Q(this)[0].contentDocument).text());
                    if (text && text.length > 0) {
                        var code = parseInt(text.match(/\d+/gm)[0]);
                        L.warn('Download code {0}'.format(code));
                        if (code === RC.Status.Forbidden) {
                            layer.open({
                                content: '没有下载权限'
                                , btn: '关闭'
                            });
                            callback.call(T, 'Forbidden');
                        } else if (code === RC.Status.NotFound) {
                            layer.open({
                                content: '未找到相关资源'
                                , btn: '关闭'
                            });
                            callback.call(T, 'NotFound');
                        } else {
                            layer.open({
                                content: '错误代码:' + code
                                , btn: '关闭'
                            });
                            callback.call(T, code);
                        }
                    } else {
                        callback.call(T, 'OK');
                    }
                }).prop('src', Rq.action(R.Action.DownLoc) + '?' + data + '&_' + Q.now());
            }

            if (noLayer) {
                doDownLoad();
            } else {
                layer.open({
                    type: 1 //此处以iframe举例
                    , title: '下载资源'
                    , shade: 0
                    , offset: [
                        Math.random() * ($(window).height() - 300)
                        , Math.random() * ($(window).width() - 390)
                    ]
                    , content: '<div>是否下载资源（' + name + ')</div>'
                    , btn: ['下载', '取消'] //只是为了演示
                    , yes: function (index) {
                        doDownLoad();
                        layer.close(index);
                    }
                    , no: function (index) {
                        layer.close(index);
                    }
                })
            }
        };
        this.openLoc = function (loc, name, callback) {
            var _t = this;
            if (closed) {
                doOpening && clearTimeout(doOpening);
                return;
            }
            L.debug('Request info...');
            var data1 = "&name=" + encodeURIComponent(name) + "&loc=" + encodeURIComponent(loc);
            var data = build().serialize() + data1;
            Do.json(R.Action.OPENLOC, data, function (reply) {
                callback && callback.call(_t, reply);
            }, function (jqXHR) {
                doFail(jqXHR, -1, function () {
                    L.debug('Retry info after {0}'.format(RC.RequestDelay));
                    doOpening = setTimeout(function () {
                        _t.openLoc(loc, name, callback);
                    }, RC.RequestDelay);
                }, event.fail);
            });
        }
        this.thumbnail = function (page, event) {
            var data = build(page);
            Rq.image(R.Action.Thumb, data, event);
            return this;
        };
        //core.fire('opt:core', ['layout', '==']);
        this.layout = function (mode) {
            return layoutMgr.value(mode);
        };
        //core.fire('opt:core', ['view', ViewMode.Text]);
        this.view = function (mode) {
            return viewMgr.value(mode);
        };
        this.area = function (data, event) {
            return getArea(data, event);
        };
        this.rotate = function (mode, dom) {
            rotateMgr.value(mode, dom);
        }
        this.resetRequestMax = function () {
            T.count = 1;
        }
        //core.fire('opt:core', ['print', [type, page], callback]);
        this.print = function (args, cb) {
            if (this.callBefore('print') === false) {
                return;
            }
            if (!args) return;
            var calcRange = function (array, start, end, deal) {
                var v0 = parseInt(start), v1 = parseInt(end);
                if (v0 < v1) {
                    for (; v0 <= v1; v0++) {
                        var v = v0;
                        if ($.isFunction(deal)) {
                            v = deal(v);
                        }
                        array.push(v);
                    }
                } else {
                    for (; v0 >= v1; v0--) {
                        var v = v0;
                        if ($.isFunction(deal)) {
                            v = deal(v);
                        }
                        array.push(v);
                    }
                }
            };
            var v = args[0], param = T.asker.builder(T.extra, T.Pagination.version()).file(T.file).build();
            var page = [], count;
            if (v === 'all') {
                count = page = T.Pagination.count();
            } else if (v === 'current') {
                page.push(T.Pagination.current());
                count = 1
            } else if (v === 'assign') {
                var ret = args[1].split(',');
                for (var i = 0; i < ret.length; i++) {
                    var n = ret[i];
                    var index = n.indexOf('-');
                    if (index === -1) {
                        page.push(Math.max(0, parseInt(n) - 1));
                    } else {
                        var na = n.split('-');
                        calcRange(page, na[0], na[1], function (vi) {
                            return Math.max(0, vi - 1);
                        });
                    }
                }
                count = page.length
            }
            if (Q.isArray(page)) {
                page = page.filter(function (value) {
                    return value <= T.Pagination.count() - 1;
                })
                if (page.length == 0) {
                    cb && cb(false);
                    return;
                }
            }
            window.updateProgress = cb;
            window.updateProgress && window.updateProgress(0, count);
            param['scope'] = page;
            param['file'] = T.file;

            var f = $('#printIframe');
            if (f.length) {
                f.remove();
            }
            f = $('<iframe id="printIframe"/>').css({
                position: 'absolute',
                width: '0px', height: '0px',
                left: '-600px', top: '-600px'
            }).appendTo(document.body);
            f.attr('src', window.Servlet.folder + '/preview.html?' + $.now() + '#' + encodeURIComponent(JSON.stringify(param)));

        }
        this.addEventListenerMessage = function () {
            T.actions = {
                copy: true,
                search: true,
                print: true
            }
            window.addEventListener && window.addEventListener('message', function (e) {
                var data = e.data;
                if (data) {
                    var keys = data[0], value = data[1];
                    if (Q.isArray(keys)) {
                        Q.each(keys, function (k, v) {
                            T.actions[v] = value;
                            if (v == 'print') {
                                value ? fireUI([v, BUTTON_STATUS.UNDISABLED]) : fireUI([v, BUTTON_STATUS.DISABLED])
                            }
                        })
                    }
                }
            }, true);
        }
        this.callBefore = function (action) {
            if (T['actions'] && typeof T['actions'][action] == "boolean") {
                return T['actions'][action];
            }
            return true;
        }
        this.callAfter = function (action) {
            window.parent && window.parent.postMessage && window.parent.postMessage(JSON.stringify(action), '*');
        }
        //core.fire('opt:core', ['Alert', [message, type]);默认info
        this.Alert = function (message, type) {
            fireUI(['message', {type: 'message', data: {type: type || 'info', message: message}}]);
        }
        this.Loading = function (message) {
            fireUI(['message', {type: 'loading', data: {type: 'loadingOpen', message: message}}]);
        }
        this.messageBox = function (title, message, event) {
            fireUI(['message', {
                type: 'messageBox',
                data: {title: title || '标题', message: message || "提示信息", call: event}
            }]);
        }
        this.appVersion = function () {
            return Config.appVersion;
        }
        this.checkPermission = function () {
            /*用户权限检查*/
            Do.json(R.Action.Perm, T.param(), function (perm) {
                /*
                perm 为接口返回的权限
                permission 为文档权限和接口返回权限的合集，接口权限大于文档权限
                */
                var permission = Q.extend(T.Pagination.info()['permission'], perm);
                /*根据文档属性对其相应的功能按钮是否可用*/
                Q.each(permission, function (type, value) {
                    if (value == "false" || value == 'true') {
                        permission[type] = value = value === 'true'
                    }
                    switch (type) {
                        case 'Export':
                            !value && fireUI(['download', BUTTON_STATUS.DISABLED]);
                            break;
                        case 'Printable':
                            !value && fireUI(['print', BUTTON_STATUS.DISABLED]);
                            break;
                        case 'Signature':
                            !value && fireUI(['seal', BUTTON_STATUS.DISABLED]);
                            break;
                        case 'Annot':
                        case 'Edit':
                            !value && fireCore(['edit', BUTTON_STATUS.HIDE]);
                            break;
                        case 'Copy':
                            !value && fireUI(['view', BUTTON_STATUS.DISABLED]);
                            break;
                    }
                });
                RU.doData(doc, BD.DocPerm, permission);
            });
        }
        return this;
    }

    function Reader(setting) {
        var ins = this.core = new Core(setting);
        ins.addEventListenerMessage();

        Q(W.document).trigger('NewSWR', ins).trigger(BP.Core + 'init', ins);

        var RC = R.Context;
        if (RC) {
            RC.instance[ins.uid] = ins;
            RC.active = ins;
            RC.listener.fire(ins);
        }

        var qi = Q(ins);
        ins.fire = ins.trigger = function () {
            return qi.trigger.apply(qi, Q.makeArray(arguments));
        };
        ins.bind = ins.on = function () {
            return qi.on.apply(qi, Q.makeArray(arguments));
        };
        ins.unbind = ins.off = function () {
            return qi.off.apply(qi, Q.makeArray(arguments));
        };

        return ins;
    }

    W.Reader = R.Reader = Reader;

    R.Supports = Q.extend(R.Supports, {
        core: {
            name: NAME, key: DATA, namespace: EVENT, body: Reader, cmd: RU.command(Core)
        }
    });

    R.Ops = Q.extend(R.Ops, {
        _Tool: {
            Rotate: Rotate
        }
    });

    L.info('Core ready');

})(window, window.jQuery, window.SWR);
