(function (W, D, Q, R) {
    var U = R.Util,
        C = R.Common,
        G = R.Logger,
        E = R.EjQ,
        Config = R.Config;
    var BA = C.Attribute,
        BC = C.CSS,
        BL = C.Level,
        BD = C.DataName;

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

    var doCall = function (fun, _this) {
        U.doApply(fun, _this, Array.from(arguments).slice(2));
    };

    var findPage = function (reader, index) {
        return reader.Pagination.pageAt(index).self();
    };
    /*
    添加选中标示
    page表示搜索内容所在页面
    rect表示搜索内容的位置数组
    flag标示这是第几个搜索结果
    */
    var addSignImage = function (page, rect, base64) {
        var image = new Image();
        image.src = base64
        var mark = E.qNv().css({
            position: 'absolute',
            left: rect[0],
            top: rect[1]
        }).addClass("rSignImage").append(image).appendTo(page);
        return mark
    }

    var addMark = function (page, rect, flag, isSemantic) {
        var group = E.qC(BC.Cover, page);

        if (group.children().length === 0) {
            //group = R.Ops._Tool.Append(page, E.qNv().attr(BA.Level, BC.Cover).addClass(BC.Cover));
            R.Ops._Tool.Rotate(page, group);
        }

        var bc = BC.Mark;

        if (isSemantic) {
            bc = BC.Semantic;
        }

        var mark = E.qNv().addClass(bc).css({
            left: rect[0],
            top: rect[1],
            width: rect[2],
            height: rect[3]
        }).appendTo(group);

        if (Q.isNumeric(flag)) {
            mark.attr(BA.MarkFlag, flag);
        }
        return mark;
    };
    /*
    * 验章*/
    var Sign = function () {
        var sip = Sign.prototype;

        function Sign(reader) {
            this.core = reader;
            this.R = Q(reader);
            this.req = this.core.asker;
        }

        sip.result = null;
        sip.createNode = function (node, target, isSign) {
            var _t = this;
            var name = node['name'], time = node['time'], pages = node['pages'], id = node['id'];
            var picture = node['picture'];
            var item = Q('<div class="Sign-">' +
                '<div class="Sign-up">' +
                '<div class="Sign-left">' +
                '<div class="Sign-left-img" style="width: ' + picture.width + 'px;height: ' + picture.height + 'px">' +
                '<img src="data:image/' + picture.type + ';base64,' + picture.data + '" alt="" style="width: ' + picture.width + 'px;height: ' + picture.height + 'px"/>' +
                '</div>' +
                '<div class="Sign-left-span">' +
                '<div class="Sign-result">未验证！</div>' +
                '<div class="Sign-descript"></div>' +
                '</div>' +
                '</div>' +
                '<div class="Sign-right">' +
                '<button class="Sign-single" style="display: none;">验章</button>' +
                '<a href="javascript:;" class="details">详情</a>' +
                '</div>' +
                '</div>' +
                '<div class="Sign-down">' +
                '<div>' +
                '<span>签章人：</span><span class="Sign-name">' + name + '</span>' +
                '</div>' +
                '<div>' +
                '<span>签章时间：</span><span class="Sign-time">' + time + '</span>' +
                '</div>' +
                '<div>' +
                '<span>域：</span><span class="Sign-area">位于第' + pages + '页</span>' +
                '</div>' +
                '</div>' +
                '</div>').appendTo(target);

            function changeStatus(ret) {
                var result = $('.Sign-result', item);
                var descript = $('.Sign-descript', item);
                if (ret.success) {
                    result.text("验章成功").css("color", "#333");
                    descript.text("该签章有效").css("color", "#333");
                } else {
                    result.text("验章失败")
                    descript.text(ret.data[id] == 2 ? "该签章有效性未知" : ret.data[id]);
                }
                Q('.details', item).click(function () {
                    Manager.fireUI(['dialog', Q.extend({result: ret.data[id]}, node)]);
                }).show()
                !function setDetailsCss() {//计算详情按钮位置，与左侧垂直底部对齐
                    var height_up = parseInt(Q('.Sign-up', item).height());
                    var height_span = parseInt(Q('.Sign-left-span', item).outerHeight());
                    var up_diff_span = height_up - height_span;
                    var height_details = parseInt(Q('.details', item).outerHeight());
                    var span_diff_details = height_span - height_details;
                    span_diff_details = span_diff_details < 0 ? 0 : span_diff_details;
                    var padding_top = up_diff_span / 2 + span_diff_details;
                    Q('.Sign-right', item).css('padding-top', padding_top);
                }()
                button.hide();
            }

            var button = Q('button', item).click(function () {
                var allResult = sip.result, thisResult = allResult && allResult.data[id];
                if (thisResult) {
                    changeStatus({success: (thisResult == "成功" ? true : false), data: allResult.data});
                } else {
                    _t.verify({sid: id}, function (ret) {
                        changeStatus(ret);
                    })
                }
            })
            !function setButtonCss() {//计算验章按钮位置，与左侧垂直居中对齐
                var height_up = parseInt(Q('.Sign-up', item).height());
                var height_button = parseInt(button.outerHeight());
                var height_diff = height_up - height_button;
                Q('.Sign-right', item).css('padding-top', parseInt(height_diff / 2));
            }()
            isSign ? button.click() : button.show();
            if (!Q.isEmptyObject(node.stamp)) {
                var stamp = node.stamp[0];
                Q('.Sign-left-img', item).click(function () {
                    var index = stamp.page;
                    var rect = stamp.rect;
                    _t.select(index, rect);
                })
            }

        }
        sip.formatDate = function (time) {
            var format = "yyyy/MM/dd hh:mm:ss";
            if (time.indexOf("T") != -1) {
                time = time.replace("T", " ");
            }
            if (time && time.indexOf("-") == -1 && Q.isNumeric(time)) {
                var yyyy = time.substr(0, 4), MM = time.substr(4, 2), dd = time.substr(6, 2);
                var hh = time.substr(8, 2), mm = time.substr(10, 2), ss = time.substr(12, 2)
                time = yyyy + "-" + MM + "-" + dd + " " + hh + ":" + mm + ":" + ss
            }
            if (time.indexOf("-") != -1) {
                var d = new Date(time)
                if (d.getTime()) {
                    return d.Format(format);
                }
                return time;
            }
            return time;
        }
        sip.parseData = function (i, d, div) {
            var seal = d['seal'], info = d['info'], sn = sv = sc = svs = sve = cn = "", pt = pd = "",
                pw = ph = 42, time = d['signatureDateTime'] || "";
            if (info) {
                try {
                    info = JSON.parse(info), certinfo = info['certinfo'];
                    if (certinfo) {
                        if (!Q.isPlainObject(certinfo)) {
                            certinfo = JSON.parse(certinfo)
                        }
                        cn = certinfo['subject_commonName'] || ""
                        sv = certinfo['subject_organizationName'] || ""
                    }
                    sn = info['sealname'] || ""
                    pt = info['imagetype'] || ""
                    pd = info['sealimage'] || ""
                    sc = info['signeddate'] || ""
                    svs = info['validstart'] || ""
                    sve = info['validend'] || ""
                } catch (e) {
                    console.log(e)
                }
            } else {
                G.warn("info is null");
            }
            if (seal) {
                var pictrue = seal && seal['pictrue'];

                if (pictrue) {
                    pt = pictrue['type'], pd = pictrue['data'], pw = pictrue['width'], ph = pictrue['height'];
                }
                sv = sv || seal['vid'] || ""
                sn = seal['name'] || ""
                sc = sc || seal['createDate'] || ""
                svs = svs || seal['validStart'] || ""
                sve = sve || seal['validEnd'] || ""
            } else {
                G.warn("seal is null");
            }
            return {
                name: cn,//签章人
                time: this.formatDate(time), //签章时间
                pages: (d.stamp && d.stamp[0].page + 1) || "",
                stamp: d.stamp && d.stamp,//位置信息
                id: d['id'],//章id
                picture: {
                    type: pt,//图片类型
                    data: pd,//图片base64 数据
                    width: pw,//图片宽
                    height: ph//图片高
                },
                sealInfo: {
                    name: sn,//印章名称
                    date: this.formatDate(svs) + " - " + this.formatDate(sve),//有效期
                    createDate: this.formatDate(sc),//制章日期
                    vid: sv //制章单位
                }
            }
        }

        sip.display = function (target, event, isSign) {
            var _t = this;
            this.target = target;
            var data = this.req.builder(this.core.extra).file(this.core.file).version(this.core.Pagination.version());
            this.req.json(R.Action.Sign, data, {
                done: function done(ret) {
                    if (Q.isArray(ret)) {
                        $.each(ret, function (i, d) {
                            _t.createNode(_t.parseData(i, d), target, isSign)
                        })
                        sip.count = ret.length;
                        event && doCall(event, this, [sip.count]);
                    }
                },
                fail: function fail(jqXHR) {
                    if (jqXHR.status === R.Common.Status.RetryWith) {
                        setTimeout(function () {
                            _t.display(target, event);
                        }, R.Common.RequestDelay);
                    } else {
                        event && doCall(event, this, jqXHR);
                    }
                }
            }, {
                context: this,
                cache: true
            });
        };

        sip.verify = function (setting, event, isAll) {
            var data = this.req.builder({
                sid: setting.sid
            }).file(this.core.file).version(this.core.Pagination.version());
            this.req.json(R.Action.Verify, data, {
                done: function done(ret) {
                    var result = {success: true, data: {}, result: [0, 0]}
                    Q.each(ret, function (k, v) {
                        switch (v) {
                            case "Document is NULL":
                                v = "文档为空";
                                break;
                            case "Signature is NULL":
                                v = "签章为空";
                                break;
                            case "Stamp is empty":
                                v = "签章为空";
                                break;
                            case "OES not found":
                            case "Plugin not found":
                                v = "未找到签章插件";
                                break;
                            case "Plugin open failed":
                                v = "签章插件打开失败";
                                break;
                            case "Verify reference digest failed":
                                v = "验证引用摘要失败";
                                break;
                            case "Verify digest failed":
                                v = "验证摘要失败";
                                break;
                            case "Decode signature data failed":
                                v = "解析签章数据失败";
                                break;
                            case "TBS is NULL":
                                v = "TBS为空";
                                break;
                            case "Verify signature failed":
                                v = "验证签章失败";
                                break;
                            case "Unknown":
                                v = 2;
                                break;
                            default:
                                v = 1;
                                break;
                        }
                        if (result.success && v != 1) {
                            result.success = false
                        }
                        v == 1 ? result.result[0]++ : result.result[1]++
                        ret[k] = v;
                    })
                    result.data = ret;
                    isAll ? sip.result = result : null;
                    doCall(event, this, result);
                },
                fail: function fail(jqXHR) {
                    if (jqXHR.status === R.Common.Status.RetryWith) {
                        setTimeout(function () {
                            sip.verify(setting);
                        }, R.Common.RequestDelay);
                    } else {
                        doCall(event.done, this, jqXHR);
                    }
                }
            }, {
                context: this,
                cache: true
            });
        };
        sip.select = function (index, rect) {
            sip.clear();
            this.core.jump(index);
            var page = findPage(this.core, index), w = page.width();
            var group = R.EjQ.qC(BC.Cover, page);

            var m = R.EjQ.qNv().addClass(BC.Mark).css({
                left: rect[0] * w, top: rect[1] * w, width: rect[2] * w, height: rect[3] * w, background: 'none',
                border: '1px solid #84cdfa'
            }).appendTo(group);
            Manager.listenResize(m, {
                rect: rect,
                page: page
            }, this.core)
        };
        sip.all = function (setting, event) {
            !sip.result && this.verify({sid: -1}, event, true);
            Q('button', Q(this.target)).filter(function () {
                return !Q(this).is(':hidden');
            }).click();
        };
        sip.clear = function () {
            Q('.' + BC.Mark).remove();
        }

        return Sign;
    }();
    /*
        搜索
        reader表示Reader
        book表示选中的文本所在父容器
        request表示Request请求
        data表示请求的参数
        */


    var Search = function () {
        var sep = Search.prototype;

        function Search(reader) {
            sep.core = reader;
            sep.R = Q(reader);
            sep.req = this.core.asker;
            sep.extra = reader.extra
            sep.category = [];
            var pageSearchAllColor = reader.extra['pageSearchColor'];
            if (pageSearchAllColor) {
                pageSearchAllColor = pageSearchAllColor.split(";");
            }
            sep.pageSearchAllColor = pageSearchAllColor;
        }


        sep._fillMark = function (result, ls, top, second) {
            var _t = this;
            var flag = sep.count || 0;
            U.forEach(ls, function (line) {
                var mark = {
                    text: '',
                    page: -1,
                    target: []
                };
                U.forEach(line, function (item, i) {
                    var index = flag;

                    if (i === 0) {
                        mark.page = item.page;
                        index += 1;
                    }

                    mark.text += item.text;
                    mark.target.push(index);
                    var page = findPage(_t.core, item.page),
                        w = page.width();
                    var b = _t.pageSearchAllColor && _t.pageSearchAllColor[top];
                    if (b) {
                        flag = -1;
                    }
                    var m = addMark(page, Q.map(item.rect, function (v) {
                        return v * w;
                    }), flag).attr("rect", item.rect).attr('title', item.text);
                    if (b) {
                        m.css({
                            background: b
                        })
                        m.attr(BA.Category, top + "_" + second);
                    }
                    U.doData(m, BD.Value, mark)
                    Manager.listenResize(m, {
                        rect: item.rect,
                        page: page
                    }, _t.core);
                });
                if (!top && !second) {
                    flag++
                }
                result.push(mark);
            });
            sep.count = flag;
        };

        /*
         搜索所有页
         发送请求后执行回调函数
         data请求时传到后台的参数
         event表示回调函数
         */
        sep._doRemote = function (param, event, top, second, noTips) {
            var _t = this;

            this.req.json(R.Action.Search, param, {
                done: function (ret) {

                    function doSelect() {
                        var select = event['select'];
                        if (false && !select) {
                            var page = _t.core.Pagination.page(_t.core.Pagination.current());
                            var st = E.qC(BC.Cover, page).children('div').first();
                            if (st.length > 0) {
                                select = st.attr(BA.MarkFlag);
                            } else {
                                select = 0;
                            }
                        }
                        select = parseInt(select);
                        if (Q.isNumeric(select)) {
                            if (select < 0) {
                                select = sep.count + select;
                            }
                            _t.select(select);
                            sep.current = select;
                        }
                        return sep.current;
                    }

                    if (ret.length == 0) {
                        !noTips && Manager.Alert('未搜索到任何数据', 'warning');
                        doCall(event.done, _t.core, ret);
                    } else {
                        var json = U.parseJSON(ret["0-0"]) || U.parseJSON(ret);
                        if (Q.isArray(json)) {
                            var array = [];
                            _t._fillMark(array, json, top, second);
                            doCall(event.done, _t.core, doSelect(), sep.count);
                        } else {
                            (function () {
                                var size = json.size,
                                    count = json.count,
                                    uid = json.uid;
                                var d = _t.req.builder(_t.extra).file(_t.core.file).build();
                                d.uid = uid;
                                var ds = [],
                                    ls = new Array(size);
                                for (var i = 0; i < count; i++) {
                                    d.index = i;
                                    ds.push(_t.req.json(R.Action.Search, d, {
                                        done: function done(r) {
                                            var o = U.parseJSON(r);
                                            var array = [];
                                            _t._fillMark(array, o.line, top, second);
                                            ls[o.index] = array;
                                        }
                                    }));
                                }

                                Q.when.apply(Q, ds).always(function () {
                                    var array = [];
                                    ls.forEach(function (e) {
                                        if (Q.isArray(e) && e.length > 0) {
                                            array = array.concat(e);
                                        }
                                    });
                                    doCall(event.done, _t.core, doSelect(), sep.count);
                                });
                            })();
                        }
                    }
                },
                fail: event.fail || Q.noop
            }, {
                context: this.core
            });
        };

        /*
         搜索
         setting表示搜索参数如区分大小写等
         event表示回调函数
         */
        sep.search = function (setting, event, noClear, Tips) {
            if (sep.find == setting['find'] && sep.caseSensitive == setting['caseSensitive'] && sep.wholeWord == setting['wholeWord']) {
                sep.count > 0 ? Manager.showCover(this.core) : null;
                return;
            }
            sep.current = 0;
            !noClear && this.clear();
            var cfg = Q.extend({
                find: '',
                index: this.core.Pagination.current(),
                count: 1,
                caseSensitive: false,
                wholeWord: false
            }, setting), event = Q.extend({
                done: function () {
                }, fail: function () {
                }
            }, event);
            if (this.core.layout() == C.LayoutMode.Single) {
                cfg.index = this.core.Pagination.current();
                cfg.count = 1;
            }
            var find = Q.trim(cfg.find),
                index = Math.max(cfg.index, 0),
                count = cfg.count,
                cst = !!setting.caseSensitive,
                wholeWord = cfg.wholeWord,
                ignoreChars = (sep.extra && sep.extra['ignoreChars']) || (cfg['ignoreChars']);


            if (find.length === 0) {
                doCall(event.fail, this, 'Search nothing...');
                return;
            }
            sep.find = find;
            sep.caseSensitive = cst;
            sep.wholeWord = wholeWord;
            var _t = this;
            Q.each(find.split(';'), function (top, value) {
                Q.each(value && value.split(','), function (second, f) {
                    var parm = _t.req.builder(_t.extra).file(_t.core.file).page(index).count(count)
                        .find(encodeURIComponent(f)).cst(cst).wholeWord(wholeWord);
                    if (ignoreChars) {
                        parm.ignoreChars(decodeURIComponent(ignoreChars));
                    }
                    //sep.category[top] = second;
                    _t._doRemote(parm, event, "", "", Tips);
                })

            })
        };
        sep.searchAll = function (key, noTips) {
            if (!key) {
                return;
            }
            this.clearSerachAllResult();
            var setting = {
                caseSensitive: false,
                count: -1,
                find: key,
                index: 0,
                wordMatch: false
            }, _t = this, ignoreChars = (sep.extra && sep.extra['ignoreChars']);
            var parm = _t.req.builder(_t.extra).file(_t.core.file).page(setting.index).count(setting.count)
                .find(encodeURIComponent(setting.find));
            if (ignoreChars) {
                parm.ignoreChars(decodeURIComponent(ignoreChars));
            }
            this.req.json(R.Action.Search, parm, {
                done: function (ret) {
                    var json = U.parseJSON(ret);
                    Q.each(json, function (key, value) {
                        var array = [];
                        key = key.split("-");
                        sep.category[key[0]] = key[1];
                        _t._fillMark(array, U.parseJSON(value), key[0], key[1]);
                    })
                }
            })
            //this.search(setting, null, null, noTips);
        };

        /*
         为搜索结果添加选中标示
         如果是第一页则跳转
         执行回调函数
         */
        sep.select = function (index, event) {
            if (!Manager.coverShow) {
                Manager.showCover(this.core);
            }
            E.qC(BC.MarkSelect, document).removeClass(BC.MarkSelect);
            var target, next, prev;

            if (typeof index == 'object') {
                target = mark;
            } else if (typeof index == 'number') {
                target = Q('.rMark[_mi="' + index + '"]');
                /* next = Q('.rMark[_mi="' + index + 1 + '"]')
                 prev = Q('.rMark[_mi="' + index - 1 + '"]')*/
            }
            if (!Q.isEmptyObject(target)) {
                target.addClass(BC.MarkSelect);
                sep.SELECT = target;
                Manager.goto(sep.core, target);
            }
            sep.change();
            event && doCall(event.done, this, index, sep.count);
        } //清空选中标示
        sep.changeCategory = function (category) {
            var oldCategory = category[0], newCategory = category[1], text = category[2], _t = this;
            if (oldCategory) {
                var newColor = sep.pageSearchAllColor[newCategory], nc = sep.category[newCategory];
                if (typeof nc == "undefined") {
                    sep.category[newCategory] = 0
                }
                var ns = ++sep.category[newCategory]
                E.qC(BC.Mark, Q("." + BC.Cover)).each(function (k, v) {
                    var c = Q(v).attr(BA.Category), o = oldCategory[0] + "_" + oldCategory[1];
                    if (c && c == o) {
                        Q(v).css({
                            background: newColor
                        }).attr(BA.Category, newCategory + "_" + ns)
                    }
                })

            } else if (newCategory && text) {
                var parm = _t.req.builder({}).file(_t.core.file).page(0).count(-1)
                    .find(encodeURIComponent(text));
                var s = ++sep.category[newCategory];
                _t._doRemote(parm, {}, newCategory, s);
            }
        }
        sep.cancelColor = function (category) {
            var oldCategory = category[0];
            E.qC(BC.Mark, Q("." + BC.Cover)).each(function (k, v) {
                var c = Q(v).attr(BA.Category), o = oldCategory[0] + "_" + oldCategory[1];
                if (c && c == o) {
                    Q(v).remove()
                }
            })

        }
        sep.prev = function (_, event) {
            if (sep.count <= 0) return;
            sep.current -= 1;
            if (sep.current < 0) {
                sep.current = sep.count - Math.abs(sep.current);
            }

            sep.select(sep.current, event);
        };
        sep.next = function (_, event) {
            if (sep.count <= 0) return;
            sep.current += 1;
            if (sep.current >= sep.count) {
                sep.current = -sep.count + sep.current;
            }
            sep.select(sep.current, event);
        };
        /*
        添加章*/
        sep.add = function (setting) {
            var ts = sep.SELECT;
            if (!sep.find || !ts) {
                this.addSignDiv(setting);
                return;
            }
            var rect = ts.attr('rect'), page = ts.closest('.' + BC.Main);
            if (rect && page.length > 0) {
                rect = rect.split(',');
                var index = page.attr('id').slice(1);
                this.core.trigger(CP.Operate + NAME, ['oes', 'add', {
                    oes: setting && setting['oes'],
                    place: [{
                        page: index,
                        x: parseFloat(rect[0]) + parseFloat(rect[2] / 2),
                        y: parseFloat(rect[1]) + parseFloat(rect[3] / 2),
                    }],
                    /*keyword: sep.find || "",
                    index: sep.current || 0*/
                }])
            }
        }
        /*
        * 应用章*/
        sep.apply = function (setting) {
            this.core.trigger(CP.Operate + NAME, ['oes', 'apply', setting]);
        }
        sep.addSignDiv = function (setting) {
            var isContinuous = Config.sealContinuous;
            var root = Q("." + BC.Root), t = this;
            var mark = addSignImage(root, [0, 0, 50, 50], setting.oes.image);
            var signs = E.qC(BC.Watermark, root).addClass(BC.Sign);

            function cancelSignMode() {
                signs.off("mousedown")
                signs.off("mousemove")
                signs.removeClass(BC.Sign)
                mark.remove();
            }

            signs.on("mousemove", function (e) {
                var dpi = t.core.Pagination.dpi(), w = U.mm2px(42, dpi), h = U.mm2px(42, dpi);
                var offset = root.offset(), left = e.clientX - offset.left - w / 2,
                    top = e.clientY - offset.top - w / 2;
                mark.css({
                    left: left,
                    top: top,
                    width: w,
                    height: w
                })
            }).on("mousedown", function (e) {
                var which = e && e.which;
                if (which == 1) {//左键
                    var target = Q(e.currentTarget).parent();
                    var index = t.core.Pagination.index(target), width = target.width(), x = (e.offsetX) / width,
                        y = (e.offsetY) / width;
                    t.core.trigger(CP.Operate + NAME, ['oes', 'add', {
                        oes: setting && setting['oes'],
                        place: [{
                            page: index + "",
                            x: x,
                            y: y,
                        }],
                    }])
                    if (!isContinuous) {
                        cancelSignMode()
                    }
                } else if (which = 3) {//右键
                    cancelSignMode()
                }
            })
        }
        sep.change = function (dom) {
            if (dom) {
                sep['dom'] = dom
            }
            sep['dom'] && Q(sep.dom).text(sep.current + 1);

        }
        sep.clearSerachAllResult = function () {
            E.qC(BC.Mark, Q('.' + BC.Document)).filter(function (i, v) {
                return Q(v).attr(BA.Category)
            }).remove();
        }
        sep.clear = function () {
            sep['current'] = 0;
            sep['find'] = null;
            sep['count'] = 0;
            Manager.clearAll();
            //E.qC(BC.Mark, document).remove();
            var div = Q('#div-placeholder').hide();
            Q('span:even', div).text('0');
        };

        return Search;
    }();
    /*
    * 大纲*/
    var Outline = function () {
        function Outline(reader) {
            this.core = reader;
            this.R = Q(reader);
            this.req = this.core.asker;
        }

        var op = Outline.prototype;

        op._loop = function (o) {
            var _t = this;

            var item = {
                name: o.title,
                target: {},
                children: []
            };
            Q.each(o.action, function (_, a) {
                if (a.type === 'goto') {
                    // igone other type
                    item.target = Q.extend({
                        index: a.page || a.target
                    }, item.target);

                    if (Q.isArray(a.dest) && a.dest.length >= 2) {
                        item.target = Q.extend({
                            offset: [a.dest[0], a.dest[1]]
                        }, item.target);
                    } else if (Q.isArray(a.region) && a.region.length >= 2) {
                        item.target = Q.extend({
                            offset: [a.region[0], a.region[1]]
                        }, item.target);
                    }

                    return false;
                }
            });
            Q.each(o.children, function (_, child) {
                item.children.push(_t._loop(child));
            });
            item.children.length == 0 ? delete item.children : "";
            return item;
        };

        op.bg = function (id) {
            var ul_width = parseInt(Q('#' + id).width()) + 'px';
            Q('<li id="bg_' + id + '" style="display: none;width: ' + ul_width + ';height: 28px;background: #eaeaea;"></li>').appendTo($("#" + id));
            Q("#" + id + " a,#" + id + " li>span").click(function () {
                Q("#" + id + " ul").removeClass("ul-position");
                var ul = Q(this).parent().parent().addClass("ul-position");
                Q("#bg_" + id).show().appendTo(ul);
                var li_top = Q(this).parent().position().top;
                var li_cls = Q(this).parent().attr("class");
                var li_padding_count = li_cls.replace("level", "").replace(" ", "").replace("ul-position", "").replace("li-position", "");
                // console.log(li_padding_count);
                var bg_left = li_padding_count == 0 ? "5px" : (-18 * (Math.max(0, li_padding_count - 1)));
                Q("#bg_" + id).css({
                    "position": "absolute",
                    "top": li_top,
                    "left": bg_left,
                    "z-index": 0
                });
                Q("#" + id + " li").removeClass("li-position");
                Q(this).parent().addClass("li-position");
            });
            //  -------------------------------
            Q('#' + id).click(function (e) {
                e.stopPropagation();
                Q('#' + id + ' a').each(function (i, domEle) {
                    var height = parseInt($(this).height());
                    var offset = parseInt($(this).offset().top);
                    var client = parseInt(e.clientY);
                    var diff = client - offset;
                    if (diff >= 0 && diff < height) {
                        $(this).click();
                        return false;
                    }
                    ;
                });
            });
        };
        /*
         发送ajax请求查询大纲
         查询结果添加到大纲中
         没有结果轮询
         查询失败调用fail
         */

        op.display = function (target, event) {
            var _t = this, event = Q.extend({
                done: function () {
                }, fail: function () {
                }
            }, event);
            var data = this.req.builder(this.core.extra).file(this.core.file).version(this.core.Pagination.version());
            this.req.json(R.Action.Outline, data, {
                done: function (ret) {
                    var items = [];
                    U.parseJSON(ret).forEach(function (o) {
                        items.push(_t._loop(o));
                    });
                    Manager.creatTree.call(_t.core, 'outline', target, items, "", true);
                    //event && doCall(event.done, _t, items);
                    _t.bg('outline');
                },
                fail: function (jqXHR) {
                    if (jqXHR.status === R.Common.Status.RetryWith) {
                        setTimeout(function () {
                            op.display(data, event);
                        }, R.Common.RequestDelay);
                    } else {
                        doCall(event.done, _t, jqXHR);
                    }
                }
            }, {
                context: this,
                cache: true
            });
        };


        /*
         点击大纲跳转
         跳转到大纲所在页的具体位置
         /g 全局匹配 查找所有匹配而非在找到第一个匹配后停止
         /[^0-9\\.]+/g 全局匹配0-9的小数字符  \\. 即\.匹配点字符
         / 放在开始结束表示开始和结束无意义
         */
        op.goto = function (target) {
            if (typeof target == 'undefined') {
                return;
            }

            Manager.goto(this.core, target);
        };

        return Outline;
    }();
    /*
    * 缩略图*/
    var ThumbList = function () {
        function ThumbList(reader) {
            this.core = reader;
            this.R = Q(reader);
            this.req = this.core.asker;
            this.version = reader.Pagination.version();
        }

        var tp = ThumbList.prototype, lastEvent;
        tp.listenPageChange = function (box) {
            var _t = this;
            _t.core.on(CP.Page + "index", function (_, index) {
                var thumb = Q(box).find('div[page=' + index + ']');
                if (!thumb.hasClass('active')) {
                    _t.addActive(thumb, box, true);
                }
            })
        }
        tp.display = function (box, event) {
            var v = this.core.Pagination.version();
            this.version = v;
            box.scroll(function () {
                if (lastEvent) {
                    clearTimeout(lastEvent);
                }
                lastEvent = setTimeout(function () {
                    box.children().each(function (i, d) {
                        if (!Q(d).is('[flag]')) {
                            return;
                        }
                        if (R.Util.inViewport(box, d, _t.core, true)) {
                            Q(d).trigger('onDisplay');
                        }
                    });
                }, 100);
            });

            function creatThumbDom(w, h, index) {
                var b = w / h;
                var thumb = $('<div>' +
                    '<div style="width: 170px;height: ' + parseInt(170 / b) + 'px">' +
                    '<div style="display: none;width: 270px;height: ' + parseInt(170 / b) + 'px;padding: 12px 0;background: #C3C3C3;border-radius: 2px;position: absolute;top: -12px;left: -50px;z-index: 0; "></div>' +
                    '<span style="display: none">' + (index + 1) + '</span>' +
                    '</div>' +
                    '</div>').addClass('thumb').attr('page', index).attr('flag', 'u').appendTo(box);
                setTimeout(function () {
                    _t.getImage(box, thumb);
                })
            }

            function getArea(index) {
                _t.core.area({index: index}, {
                    done: function (ret) {
                        var a = ret[0]
                        creatThumbDom(a[0], a[1], index);
                    }
                })
            }

            var _t = this;
            box.addClass('actived');
            this.listenPageChange(box);
            var info = this.core.Pagination.info();
            var count = info.count;
            for (var i = 0; i < count; i++) {
                var area = info.area[i];
                if (area) {
                    creatThumbDom(area[0], area[1], i)
                    // var width = area[0], height = area[1];
                } else {
                    getArea(i);
                }
            }

            _t.addActive(Q(box).find('div[page=' + _t.core.Pagination.current() + ']'), box, true);
            box.children().one('onDisplay', function () {//函数绑定的事件处理函数都是一次性的首次会触发
                _t.getImage(box, Q(this));
            })
        };
        tp.getImage = function (box, dom) {
            var _t = this;
            if (!R.Util.inViewport(box, dom, _t.core, true) && dom.is('[flag]') || box.is(':hidden')) {
                return;
            }
            _t.core.thumbnail(dom.attr('page'), {
                done: function () {
                    var page = Q(dom).attr('page');
                    var has_img = Q('div:first', dom).has('img').length;
                    if (!has_img) {
                        Q('div:first', dom.removeAttr('flag')).prepend(this);
                    }
                    Q('span', dom).show();
                    dom.click(function () {
                        _t.addActive(this);
                        Manager.setLastAction('thumbs', page)
                        _t.goto(page);
                    })
                },
                abort: function () {
                    Logger.log('thumbnail img abort');
                },
                fail: function () {
                    Q('div:first', dom.removeAttr('flag')).css('background', 'none');
                }
            });
        };
        tp.addActive = function (dom, box, scroll) {
            if (dom) {
                Q(dom).addClass('active').siblings().removeClass('active')
                if (box && scroll) {
                    box.scrollTo(dom);
                }
            }
        }

        tp.goto = function (index) {
            Manager.goto(this.core, {index: index});
        };

        return ThumbList;
    }();

    var CustomTag = function () {
        function CustomTag(reader) {
            this.core = reader;
            this.R = Q(reader);
            this.req = this.core.asker;
        }

        var cp = CustomTag.prototype;

        cp.bg = function (id) {
            var ul_width = parseInt(Q('#' + id).width()) + 'px';
            Q('<li id="bg_' + id + '" style="display: none;width: ' + ul_width + ';height: 28px;background: #eaeaea;"></li>').appendTo($("#" + id));
            Q("#" + id + " a,#" + id + " li>span").click(function () {
                Q("#" + id + " ul").removeClass("ul-position");
                var ul = Q(this).parent().parent().addClass("ul-position");
                Q("#bg_" + id).show().appendTo(ul);
                var li_top = Q(this).parent().position().top;
                var li_cls = Q(this).parent().attr("class");
                var li_padding_count = li_cls.replace("level", "").replace(" ", "").replace("ul-position", "").replace("li-position", "");
                // console.log(li_padding_count);
                var bg_left = li_padding_count == 0 ? "5px" : (-18 * (Math.max(0, li_padding_count - 1)));
                Q("#bg_" + id).css({
                    "position": "absolute",
                    "top": li_top,
                    "left": bg_left,
                    "z-index": 0
                });
                Q("#" + id + " li").removeClass("li-position");
                Q(this).parent().addClass("li-position");
            });
            //  -------------------------------
            Q('#' + id).click(function (e) {
                e.stopPropagation();
                Q('#' + id + ' a').each(function (i, domEle) {
                    var height = parseInt($(this).height());
                    var offset = parseInt($(this).offset().top);
                    var client = parseInt(e.clientY);
                    var diff = client - offset;
                    if (diff >= 0 && diff < height) {
                        $(this).click();
                        return false;
                    }
                    ;
                });
            });
        };
        cp.display = function (target, event) {
            var _t = this;

            var data = this.req.builder(this.core.extra).file(this.core.file).version(this.core.Pagination.version());
            this.req.json(R.Action.CustomTag, data, {
                done: function (ret) {
                    Manager.creatTree.call(_t.core, 'semantics', target, ret, "", true);
                    //doCall(event.done, _t, ret);
                    _t.bg('semantics');
                },
                fail: function (jqXHR) {
                    if (jqXHR.status === R.Common.Status.RetryWith) {
                        setTimeout(function () {
                            _t.display(target, event);
                        }, R.Common.RequestDelay);
                    } else {
                        doCall(event.done, _t, jqXHR);
                    }
                }
            }, {
                context: this,
                cache: true
            });
        };

        cp.goto = function (target) {
            var _t = this;

            if (!target) {
                return this;
            }

            var first;
            this.clear();
            Q.each(target, function (_, r) {
                Q.each(r, function (index, t) {
                    var page = findPage(_t.core, t.page),
                        w = page.width();

                    if (!first) {
                        first = t;
                    }
                    var m = addMark(page, Q.map(t.rect || t.target, function (v) {
                        return v * w;
                    }), parseInt(t.id), true);
                    Manager.listenResize(m, {
                        rect: t.rect,
                        page: page
                    }, _t.core)
                });
            });

            if (first) {
                Manager.goto(this.core, {
                    index: first.page, offset: first.rect
                });
            }

            return this;
        };

        cp.clear = function () {
            Manager.clearAll();
        };

        return CustomTag;
    }();

    var Annot = function () {
        function Annot(reader) {
            this.core = reader;
            this.R = Q(reader);
            this.req = this.core.asker;
            this.order = 'time';
            this.target = null;
        }

        var ap = Annot.prototype;
        ap.order = 'none';
        ap.sortData = function (_data, order) {
            for (var i = 0; i < _data.length; i++) {
                var _subtype = _data[i].subtype ? _data[i].subtype.toLowerCase() : '';
                var _name = _data[i].name ? _data[i].name.toLowerCase() : '';
                _data[i].type = _subtype || _name || "其他";
                _data[i]._date = _data[i].date ? _data[i].date.replace(/\D/g, "") : Infinity;
            }
            var o_data = [];
            var fnSort = function (sort) {
                //sort="creator(name对应ui)"/"type(type对应ui)"/"date(time对应ui)"
                var sort_name_obj = {};//{"Ql":[] , "Xl":[] , "undefined":[]}
                for (var i_name = 0; i_name < _data.length; i_name++) {
                    if (sort_name_obj.hasOwnProperty(_data[i_name][sort])) {
                        sort_name_obj[_data[i_name][sort]].push(_data[i_name]);
                    } else {
                        sort_name_obj[_data[i_name][sort]] = [];
                        sort_name_obj[_data[i_name][sort]].push(_data[i_name]);
                    }
                }
                var sort_name_arr = [];//["Ql" , "Xl" , "undefined"]
                for (var x_name in sort_name_obj) {
                    sort_name_arr.push(x_name);
                }
                sort_name_arr = sort_name_arr.sort();
                // console.log(sort_name_arr,'arr<=>obj',sort_name_obj);
                for (var j_name = 0; j_name < sort_name_arr.length; j_name++) {
                    // sort_name_obj[sort_name_arr[j_name]]  // sort_name_obj["Ql"]
                    for (var k_name = 0; k_name < sort_name_obj[sort_name_arr[j_name]].length; k_name++) {
                        o_data.push(sort_name_obj[sort_name_arr[j_name]][k_name]);
                    }
                }
            };
            switch (order) {
                case 'user':
                    fnSort('creator');
                    // console.log(o_data,'o_data','name');
                    break;
                case 'type':
                    fnSort('type');
                    // console.log(o_data,'o_data','type');
                    break;
                case 'time':
                    o_data = $.extend(true, [], _data);
                    o_data.sort(function (a, b) {
                        return a._date - b._date
                    });
                    // console.log(o_data,'o_data','time');
                    break;
            }
            return o_data;
        }
        ap.parseData = function (data, index) {
            var odata = Q.extend(true, [], data);
            var map = {
                'AddRevisions': {icon: 'icon24pxtianchong_zhushi_pizhu', text: '批注'},
                'DelRevisions': {icon: 'icon24pxtianchong_zhushi_shanchu', text: '删除'},
                'InsertLine': {icon: 'icon24pxtianchong_zhushi_charu', text: '插入'},
                'Replace': {icon: 'icon24pxtianchong_zhushi_tihuan', text: '替换'},
                'Movedout': {icon: 'iconic_tip_warning', text: '移出'},
                'MovedIn': {icon: 'iconic_tip_warning', text: '移入'},
                'IncreaseSpace': {icon: 'icon24pxtianchong-183', text: '加大空白'},
                'ReduceSpace': {icon: 'icon24pxtianchong_zhushi_suoxiaojianju', text: '减少空白'},
                'MoveBack': {icon: 'iconic_tip_warning', text: '后移'},
                'MoveForward': {icon: 'icon24pxtianchong_zhushi_qianyi', text: '前移'},
                'watermark': {icon: 'iconic_tip_warning', text: '水印'},
                'path': {icon: 'icon24pxtianchong_xinzeng_tuxing', text: '图形'},
                'stamp': {icon: 'icon24pxtianchong_anquan_dianziqianzhang', text: '签章'},
                'FreeText': {icon: 'icon24pxtianchong_wenbenkuang', text: '文本框'},
                'Highlight': {icon: 'icon24pxtianchong_zhushi_gaoliang', text: '高亮'},
                'Underline': {icon: 'icon24pxtianchong_zhushi_xiahuaxian', text: '下划线'},
                'Squiggly': {icon: 'icon24pxtianchong_zhushi_bolangxian', text: '波浪线'},
                'Strikeout': {icon: 'icon24pxtianchong_zhushi_shanchu', text: '删除线'},
                "RuntimeMark": {icon: 'iconic_tip_warning', text: "运行时水印"},
                'Line': {icon: 'icon24pxtianchong_zhixian-153', text: '直线工具'},
                'Arrow': {icon: 'icon24pxtianchong_dili_jiantou', text: '箭头工具'},
                'Rectangle': {icon: 'icon24pxtianchong_dili_juxing', text: '矩形工具'},
                'Ellipse': {icon: 'icon24pxtianchong_dili_tuoyuan', text: '椭圆工具'},
                'Polygon': {icon: 'icon24pxtianchong_dili_duobianxing', text: '多边形工具'},
                'PolyLine': {icon: 'icon24pxtianchong_dili_zhexian', text: '折线工具'},
                'Pencil': {icon: 'icon24pxtianchong_zhushi_shouxie', text: '签笔工具'},
                'StrokePen': {icon: 'icon24pxtianchong_zhushi_shouxie', text: '软笔工具'},
                'Tablet': {icon: 'icon24pxtianchong_zhushi_shouxie', text: '手写签批'},
                'seal': {icon: 'icon24pxtianchong_anquan_xiangpituzhang', text: '图章'},
                'default': {icon: 'iconic_tip_warning', text: '其他'}
            };
            //图标映射
            for (var i = 0, l = data.length; i < l; i++) {
                odata[i].menu = map[data[i].subtype] || map[data[i].name] || map.default
                odata[i].target = {offset: data[i]['boundary']};
                odata[i].name = data[i]['creator'] || ""
                odata[i].page = "第" + index + "页";
                odata[i].date = data[i]['date'] || ""
                odata[i].text = data[i]['remark'] || ""
            }
            return odata;
        }
        ap.createNode = function (data, parent, index) {
            if (!data) {
                data = Q(parent).data(C.DataName.Value, data);
                if (!data) {
                    return;
                }
            }
            //排序
            if (ap.order != 'none') {
                data = ap.sortData(data, ap.order);
            }
            //映射
            data = ap.parseData(data, index);
            Q.each(data, function (i, n) {
                R.Tpl.renderTo('annot_content', {data: n}, parent, R.TplFx.annot_content);
            });
        }
        ap.display = function (target, event, order) {
            /*默认初始化*/
            if (order) {
                ap.order = order;
            }
            var annot = this.core.Pagination.info().annot;

            if (!annot) {
                return new Array();
            }
            var data = new Array();
            Q.each(annot, function (_, page) {
                data.push({
                    page: '第' + (page + 1) + '页',
                    index: page,
                    isParent: true
                });
            });
            R.Tpl.renderTo('page', {data: data}, target, R.TplFx.page, {
                action: R.Action.Annot, callback: this.createNode
            });
        };

        ap.goto = function (target) {
            if (Q.isEmptyObject(target)) {
                return;
            }
            if (this.core.Pagination.current() != parseInt(target.index)) {
                this.core.jump(target.index)
            }
            this.clear();
            var page = Q('#_' + target.index),
                rect = target.offset;

            var addMark = function (page, rect, flag) {
                var group = E.qC(BC.Cover, page);
                E.qC(BC.Mark, group).remove();

                if (group.length === 0) {
                    R.Ops._Tool.Rotate(page, group);
                }

                var mark = E.qNv().addClass(BC.Mark).css({
                    left: rect[0],
                    top: rect[1],
                    width: rect[2],
                    height: rect[3],
                    background: 'none',
                    border: '1px solid #84cdfa'
                }).appendTo(group);

                if (Q.isNumeric(flag)) {
                    mark.attr(BA.MarkFlag, flag);
                }
                return mark;
            };
            var m = addMark(page, Q.map(rect, function (v) {
                return v * page.width() / R.Common.Ratio;
            }))
            Manager.listenResize(m, {
                rect: Q.map(rect, function (v) {
                    return v / R.Common.Ratio;
                }),
                page: page
            }, this.core)
            Manager.goto(this.core, m);
        };
        ap.sort = function (target, event, order) {
            ap.order = order;
            target && target.empty();
            this.display(target, event, order);
        }
        ap.clear = function () {
            Manager.clearAll();
        }

        return Annot;
    }();
    /*
    * 书签*/
    var Bookmark = function () {
        function Bookmark(reader) {
            this.core = reader;
            this.R = Q(reader);
            this.req = this.core.asker;
        }

        var bp = Bookmark.prototype;
        bp.display = function (target, event) {
            var _t = this;
            var data = this.req.builder(this.core.extra).file(this.core.file).version(this.core.Pagination.version());
            this.req.json(R.Action.Bookmark, data, {
                done: function (ret) {
                    Q.each(ret, function (_, r) {
                        r.target = {
                            page: r.page,
                            rect: r.rect
                        }
                    });
                    Manager.creatTree.call(_t.core, 'bookmark', target, ret, "", true);
                    //doCall(event.done, this, ret);
                },
                fail: function (jqXHR) {
                    if (jqXHR.status === R.Common.Status.RetryWith) {
                        setTimeout(function () {
                            _t.display(data, event);
                        }, R.Common.RequestDelay);
                    } else {
                        doCall(event.done, this, jqXHR);
                    }
                }
            }, {context: this, cache: true});
            return this;
        }
        bp.goto = function (target) {
            var page = target['page'], rect = target['rect'];
            this.core.jump(page, {
                left: rect[0],
                top: rect[1]
            });
        }
        return Bookmark;
    }();
    /*
    * 附件*/
    var Attachment = function () {
        function Attachment(reader) {
            this.core = reader;
            this.R = Q(reader);
            this.req = this.core.asker;
        }

        var ap = Attachment.prototype;
        ap.createNode = function (node, target) {
            var name = node['name'] || "", size = node['size'] || "", type = node['format'] || "",
                time = node['creation'] || "",
                loc = node['loc'] || "";
            var icon, _t = this;
            switch (type) {
                case "word":
                    icon = "alertOFDlogo.png";
                    break;
                case "excel":
                    icon = "alertOFDlogo.png";
                    break;
                case "ppt":
                    icon = "alertOFDlogo.png";
                    break;
                default:
                    icon = "alertOFDlogo.png";
                    break;
            }
            var attachmentNode = Q('<div class="Attachment-">' +
                '<div class="Attachment-up">' +
                '<div class="Attachment-left">' +
                '<div class="Attachment-left-img">' +
                '<img src="./static//image/' + icon + '" style="width: 32px;height: 32px;" />' +
                '</div>' +
                '<div class="Attachment-left-span">' +
                '<div class="Attachment-result" title="' + name + '.' + type + '">' + name + '.' + type + '</div>' +
                '</div>' +
                '</div>' +
                '<div class="Attachment-right">' +
                '<button class="openLoc"><img src="./static//image/open-download.svg" style="width: 16px;height: 16px;" title="打开附件"/></button>' +
                '<button class="odownload"><img src="./static//image/odownload.png" style="width: 16px;height: 16px;" title="下载附件"/></button>' +
                '</div>' +
                '</div>' +
                '<div class="Attachment-down">' +
                '<div>' +
                '<span>大小：</span><span class="Attachment-name">' + size + ' kb</span>' +
                '</div>' +
                '<div>' +
                '<span>创建时间：</span><span class="Attachment-time">' + time + '</span>' +
                '</div>' +
                '</div>' +
                '</div>').appendTo(target);

            /*下载点击事件*/
            function odownload() {
                _t.goto({
                    loc: loc,
                    name: name,
                    format: type
                })
            }

            function openLoc() {
                _t.open({
                    loc: loc,
                    name: name,
                    format: type
                })
            }

            attachmentNode.dblclick(odownload)
            Q('.odownload', attachmentNode).click(odownload)
            if (type == "ofd" || type == 'pdf') {
                Q('.openLoc', attachmentNode).show().click(openLoc)
            }
        };
        ap.display = function (target, event) {
            var _t = this;
            var data = this.req.builder(this.core.extra).file(this.core.file).version(this.core.Pagination.version());
            this.req.json(R.Action.Attachment, data, {
                done: function (ret) {
                    Q.each(ret, function (_, r) {
                        _t.createNode(r, target);
                        /* r.children = [
                             {name: "格式: " + (r['format'] || "")},
                             {name: "创建日期: " + (r['creation'] || "")},
                             {name: "大小: " + (r['size'] || "")},
                             {
                                 name: "点击下载", target: {
                                     loc: r.loc,
                                     name: r.name,
                                     format: r.format
                                 }
                             }
                         ];*/
                    });
                    //Manager.creatTree.call(_t.core, 'attachment', target, ret, "", true);
                    // doCall(event.done, this, ret);
                },
                fail: function (jqXHR) {
                    if (jqXHR.status === R.Common.Status.RetryWith) {
                        setTimeout(function () {
                            _t.display(data, event);
                        }, R.Common.RequestDelay);
                    } else {
                        doCall(event.done, this, jqXHR);
                    }
                }
            }, {context: this, cache: true});
            return this;
        };
        ap.goto = function (target) {
            this.core.fire('opt:core', ['downloadLoc', target.loc, target.name + "." + target.format, null, true])
        };
        ap.open = function (target) {
            this.core.fire('opt:core', ['openLoc', target.loc, target.name + "." + target.format, function (ret) {
                window.open("./reader?file=" + ret.path, "_blank")
            }])
        }
        return Attachment;
    }();
    var OESUtil = function (reader, callback) {
        var rpcUrl = Config.sealUrl, format = "xml"
        var T = this;
        this.plugins = [];
        this.pluginsInfo = {};
        this.core = reader;
        this.signSetting = null;
        this.password = null;
        this.opened = false;

        function startRPC() {
            Q(W).off('beforeunload');
            window.open("SwOESServer://" + rpcUrl + "", "_top")
            U.listenerBeforeunload();
        }

        function isSuccess(data) {
            if (Q.isArray(data)) {
                var status = data.slice(0, 2), result = data.slice(2);
                if (status[0] == 0) {
                    return result;
                } else {
                    var EM = "获取客户端签章异常, 错误码:  " + status[0] + "! 错误信息: " + status[1];
                    console.error(EM);
                    Manager.Alert(EM, 'error');
                    return false;
                }
            } else {
                Manager.Alert("获取客户端签章算法异常:数据类型错误", 'error');
            }
            return false;

        }

        function callRPC(name, setting, callback) {
            xmlRpcClient(rpcUrl, name, setting, format, function (err, data, something, otherthing) {
                if (!err) {
                    callback && callback(err, data)
                } else {
                    callback && callback(err, data)
                    if (data == "timeout") {
                        Manager.Alert("获取客户端签章超时 : " + name, 'error');
                    } else if (name != 'GetOESPlugins') {
                        console.log(err);
                        Manager.Alert("获取客户端签章异常 : " + name, 'error');
                    }
                }
            })
        }

        var T;

        //获取所有签章库名称
        function getOESPlugins(event) {
            callRPC('GetOESPlugins', "", function (errS, plugins) {
                if (!errS) {
                    T.plugins = plugins;
                    Q.each(plugins, function (k, v) {
                        T.pluginsInfo[v] = {};
                    })
                }
                event && doCall(event, this, T.pluginsInfo)
            })
        }

        //获取所有签章库信息
        function getOESInfo(event) {
            callRPC('GetOESInfo', "", function (errS, pluginsInfo) {
                if (!errS) {
                    Q.each(pluginsInfo, function (k, v) {
                        if (v['ErrCode'] != 0) {
                            console.log("Get " + v['OESName'] + "error, error code is " + v['ErrCode'])
                            console.log("ErrorMsg: " + v['ErrMsg'] + " OESPath: " + v['OESPath'])
                        }
                    })
                }
            })
        }

        //初始化openSession
        function initOpenSession(oesname, index) {
            callRPC('OpenSession', oesname, function (errS, session) {
                if (!errS) {
                    T.pluginsInfo[oesname]['session'] = session;
                    //initSeal(session, oesname)
                    //initCert(session, oesname, index);
                    if (index == T.plugins.length - 1) {
                        doCall(callback, T, T.pluginsInfo)
                    }
                }
            })
        }


        //获取印章数据
        function initSeal(session, oesname, id) {
            callRPC('GetSeal', [session, oesname, id], function (errS, seal) {
                if (!errS) {
                    T.pluginsInfo[oesname][id] = seal;
                    /*if (index == T.plugins.length - 1) {
                        doCall(callback, T, T.pluginsInfo)
                    }*/
                }
            })
        }

        function initCert(session, oesname, id) {
            callRPC('GetCert', [session, oesname, id], function (errS, cert) {
                if (!errS) {
                    T.pluginsInfo[oesname][id] = cert;
                    /* if (index == T.plugins.length - 1) {
                         doCall(callback, T, T.pluginsInfo)
                     }*/
                }
            })
        }

        var c = 0;

        function init(count) {
            if (count > 2) {
                Manager.Alert("进程启动失败", 'error')
                return;
            }
            getOESPlugins(function () {
                if (!T.plugins.length) {
                    startRPC();
                    init(c++);
                } else {
                    getOESPlugins(function () {
                        Q.each(T.plugins, function (i, v) {
                            initOpenSession(v, i);
                        })
                    });
                }
            });
        }

        this.getOESInfo = function (event) {
            return getOESInfo(event)
        }
        this.getPlugins = function () {
            return this.plugins
        }
        this.getPluginsInfo = function () {
            return this.pluginsInfo
        }
        this.getOpenSession = function (oesname) {
            return this.pluginsInfo[oesname].session;
        }
        this.getSealList = function (oesname, event) {
            var list = T.pluginsInfo[oesname]['SealList'];
            if (list) {
                event && doCall(event.done, this, list);
                return;
            }
            var event1 = {
                done: function (logout) {
                    T.getSealList(oesname, event);
                },
                fail: function (msg) {
                    Manager.messageBox(msg || "密码错误！", "请输入正确的签章密码！", {yes: getPassword});
                }
            }

            function getPassword(password, logout) {
                T.login(oesname, password, event1, logout);
            }

            var session = this.getOpenSession(oesname);
            callRPC('GetSealList', [session, oesname], function (errL, data) {
                var result = {seals: []};
                if (!errL) {
                    if (Q.isArray(data)) {
                        var status = data.slice(0, 2), sealList = data.slice(2), count = 0;
                        if (status[0] == 0) {
                            sealList.map(function (v, i) {
                                if (i % 2 == 0) {
                                    callRPC('GetSealImage', [session, 0, oesname, v, "", ""], function (errI, image) {
                                        if (!errI) {
                                            result.seals.push({
                                                id: v,
                                                name: sealList[i + 1],
                                                image: {
                                                    data: image[2],
                                                    type: image[3],
                                                    width: image[4],
                                                    height: image[5]
                                                }
                                            });
                                        }
                                        //initSeal(session, oesname, v);
                                        //initCert(session, oesname, v);
                                        count++;
                                        if (sealList.length / 2 == count) {
                                            T.pluginsInfo[oesname]['SealList'] = result;
                                            event && doCall(event.done, this, result);
                                        }
                                    })
                                }
                            })
                        } else if (status[0] == 1) {
                            Manager.messageBox("签章密码", "请输入获取签章密码!", {yes: getPassword});
                        } else {
                            var EM = "获取客户端签章异常, 错误码:  " + status[0] + "! 错误信息: " + status[1];
                            console.error(EM);
                            Manager.Alert(EM, 'error');
                            event && doCall(event.done, this, result);
                        }

                    }
                }
            })
        }
        this.getAlgorithm = function (oesname, event) {
            var session = this.getOpenSession(oesname);
            var algorithm = {
                digestMethod: "",
                signatureMethod: "",
                signatureDatetime: ""
            }
            callRPC('GetDigestMethod', [session, oesname], function (errL, data) {
                if (!errL) {
                    algorithm.digestMethod = isSuccess(data)[0] || "";
                    callRPC('GetSignMethod', [session, oesname], function (errL, data) {
                        if (!errL) {
                            algorithm.signatureMethod = isSuccess(data)[0] || "";
                            callRPC('GetSignDateTime', [session, oesname], function (errL, data) {
                                if (!errL) {
                                    algorithm.signatureDatetime = isSuccess(data)[0] || "";
                                    event && doCall(event.done, this, algorithm);
                                }
                            })
                        }
                    })
                }
            })
        }
        this.login = function (oesname, password, event, logout) {
            var session = this.getOpenSession(oesname);
            callRPC('Login', [session, oesname, password], function (errS, login) {
                if (!errS) {
                    var status = login[0], msg = login[1];
                    if (status == 0) {
                        event && doCall(event.done, T, logout)
                    } else {
                        event && doCall(event.fail, T, msg);
                    }

                }
            })
        }
        this.logout = function (oesname) {
            var session = this.getOpenSession(oesname);
            callRPC('Logout', [session, oesname], function (errS, cert) {
                if (!errS) {

                }
            })
        }
        this.getSign = function (oesname, sealId, digest, algorithm, callback, logout) {
            var session = this.getOpenSession(oesname),
                signSetting = [session, oesname, sealId, " ", digest, algorithm.signatureMethod, algorithm.signatureDatetime];
            var event = {
                done: function (logout) {
                    T.getSign(oesname, sealId, digest, algorithm, callback, logout);
                },
                fail: function (msg) {
                    Manager.messageBox(msg || "密码错误！", "请输入正确的签章密码！", {yes: getPassword});
                }
            }

            function getPassword(password, logout) {
                T.login(oesname, password, event, logout);
            }

            callRPC('Sign', signSetting, function (errS, sign) {
                if (!errS) {
                    var status = sign[0], msg = sign[1], data = sign[2];
                    if (status == 0) {
                        T.signSetting = null;
                        //logout ? T.logout(oesname) : null;
                        doCall(callback, T, data);
                    } else if (status == 1) {
                        Manager.messageBox("盖章密码", "请输入签章密码！", {yes: getPassword})
                    } else {
                        Manager.Alert("获取客户端签章异常, 错误码:  " + status + "! 错误信息: " + msg, 'error')
                    }
                }
            })

        }
        init(callback);
        return this;
    }
    /*
    * 签章*/
    var OES = function () {
        var oesp = OES.prototype, isClient = Config.sealPlace == 'client', rpcUrl = Config.sealUrl, format = "xml";

        function OES(reader) {
            this.core = reader;
            this.R = Q(reader);
            this.req = this.core.asker;
        }

        var sealUtil;
        oesp.plugins = function (setting, event) {
            if (setting && isClient) {
                if (sealUtil) {
                    event && doCall(event.done, this, sealUtil.plugins);
                } else {
                    new OESUtil(this.core, function () {
                        sealUtil = this;
                        event && doCall(event.done, this, sealUtil.plugins);
                        setTimeout(function () {
                            sealUtil.getOESInfo()
                        });
                    })
                }

            } else {
                var data = this.req.builder(this.core.extra).file(this.core.file).version(this.core.Pagination.version());
                this.req.json(R.Action.OES, data, {
                    done: function (ret) {
                        event && doCall(event.done, this, ret);
                    },
                    fail: function (ret) {
                        Manager.Alert(ret.responseText, 'error');
                    }
                })
            }

        }
        oesp.info = function (setting, event) {
            if (isClient) {
                sealUtil.getSealList(setting['name'], event)
            } else {
                var data = this.req.builder({
                    name: setting['name'] || "Suwell_SDK",
                    pwd: setting['pwd'] || "123456"
                }).version(this.core.Pagination.version()).file(this.core.file);
                this.req.json(R.Action.OES, data, {
                    done: function (ret) {
                        event && doCall(event.done, this, ret);
                    },
                    fail: function (ret) {
                        Manager.Alert(ret.responseText, 'error');
                    }
                })
            }

        }
        /*
       * 盖章数据发送到服务器*/
        oesp.post = function (data, profit, callback) {
            var _t = this;
            Manager.Loading("盖章中...");
            Q.ajax({
                dataTpye: 'json',
                type: 'post',
                url: this.req.servlet,
                data: data,
                cache: false,
                headers: xat('SIGNATURE'),
                success: function (r) {
                    var code = r.ret, msg = r.msg;
                    switch (code) {
                        case 0: //failed
                            Manager.Alert("盖章失败", 'warning');
                            break;
                        case 1: //ok
                            Manager.Alert("盖章成功", 'success');
                            callback && callback.call(_t, msg);
                            break;
                        case 2: //retry
                            setTimeout(function () {
                                oesp.post.call(_t, {tid: msg}, profit, callback);
                            }, profit)
                            break;
                    }
                },
                error: function (e) {

                }
            });
        }
        /*
        添加章*/
        oesp.add = function (setting, event) {
            var _t = this;
            var place = setting['place'], oes = setting['oes'], keyword = setting['keyword'];

            function doPost(value) {
                oesp.post.call(_t, _t.core.param(-1, {
                    '_j': JSON.stringify(value)
                }), 1000, function (v) {
                    _t.core.Pagination.version(v);
                    if (place.length > 1) {
                        window.location.reload();
                    } else {
                        _t.core.Pagination.reload(place[0]['page']);
                    }
                })
            }

            if (place && oes) {
                if (oes['image']) {
                    delete oes.image;
                }
                var s = {
                    isApply: false,
                    oes: oes,
                    place: place,
                    keyword: keyword
                }
                if (isClient) {
                    Manager.Loading("盖章中...");
                    sealUtil.getAlgorithm(oes.name, {
                        done: function (algorithm) {
                            s['algorithm'] = algorithm;
                            s['index'] = setting['index'];
                            var d = _t.core.param(-1, {
                                '_j': JSON.stringify(s)
                            })
                            _t.req.json(R.Action.Digest, d, {
                                done: function (ret) {
                                    if (ret['digest']) {
                                        sealUtil.getSign(oes.name, oes.id, ret['digest'], algorithm, function (sign) {
                                            doPost({sign: sign, digest: ret['digest']})
                                        })
                                    } else {
                                        Manager.Alert("获取摘要失败", "error")
                                    }

                                    //event && doCall(event.done, this, ret);
                                },
                                fail: function (ret) {
                                    //Manager.Alert(ret.responseText, 'error');
                                }
                            })
                        }
                    })
                } else {
                    doPost(s)
                }

            } else {
                console.log("no place")
            }
        }
        /*
        * 应用章*/
        oesp.apply = function (setting) {
            if (isClient) {
                Manager.Alert("盖章功能待开发", 'warning');
            } else {
                var data = this.core.param(-1, {
                    '_j': JSON.stringify({
                        isApply: true,
                        applyPwd: setting['pwd'] || "123456",
                    })
                });
                oesp.post.call(this, data, 1000, function () {
                    window.location.reload();
                })
            }

        }

        return OES;
    }();

    var Attribute = function () {
        function Attribute(reader) {
            this.core = reader;
            this.R = Q(reader);
            this.req = this.core.asker;
        }

        var atp = Attribute.prototype;
        /*说明*/
        atp.explain = function (event) {
            event && doCall(event.done, null, this.core.Pagination.info());
        }
        /*安全*/
        atp.safety = function (event) {
            var def = {
                Edit: 'true',
                Annot: 'true',
                Export: 'true',
                Signature: 'true',
                Watermark: 'true',
                PrintScreen: 'true',
                Printable: 'true',
                periodValidity: '',
                Copies: '无限制'
            };
            def = Q.extend(def, this.core.Pagination.info()['permission']);
            var setting = this.req.builder(this.core.extra).file(this.core.file).version(this.core.Pagination.version());
            this.req.json(R.Action.Perm, setting, {
                done: function (d) {
                    Q.each(Q.extend(def, d), function (key, value) {
                        if (value == 'true' || value == true) {
                            d[key] = '是';
                        } else if (value == 'false' || value == false) {
                            d[key] = '否';
                        } else if (value == '-1') {
                            d[key] = '无限制';
                        } else {
                            d[key] = value;
                        }
                    });

                    if (d['StartDate']) {
                        d['periodValidity'] = d['StartDate'] + ' - ' + d['EndDate'];
                    }
                    event && doCall(event.done, null, d);
                }, fail: function () {
                    event && doCall(event.done, null, {});
                }
            });
        }
        /*文档字体*/
        atp.docFont = function (event) {
            var setting = this.req.builder(this.core.extra).file(this.core.file).version(this.core.Pagination.version());
            this.req.json(R.Action.Fonts, setting, {
                done: function (d) {
                    Q.each(d, function (_, v) {
                        v['children'] = [{
                            name: "类型:trueType"
                        }]
                    })
                    event && doCall(event.done, null, d);
                }, fail: function () {
                    event && doCall(event.done, null, {});
                }
            });
        }
        /*元数据*/
        atp.metadata = function (event) {
            event && doCall(event.done, null, this.core.Pagination.info()['CustomDatas']);
        }
        /*历史版本*/
        atp.history = function (event) {
            event && doCall(event.done, null, []);
        }
        return Attribute;
    }();
    var Manager = function () {
        var mp = Manager.prototype;

        function Manager(reader) {
            this._load();
            this.reader = reader;
            this.core = Q(reader);
            this.req = this.core.asker;
            this.search = new Search(reader);
            this.outline = new Outline(reader);
            this.thumbs = new ThumbList(reader);
            this.sign = new Sign(reader);
            this.semantics = new CustomTag(reader);
            this.annotation = new Annot(reader);
            this.bookmark = new Bookmark(reader);
            this.attachment = new Attachment(reader);
            this.oes = new OES(reader);
            this.attribute = new Attribute(reader)
            this._listen();
            this.isShow = false;
            Manager.init(reader);
        }


        mp.lastAction = {
            id: null,
            target: null
        }
        mp._load = function () {
            Q.each(['./static//zTree_v3/zTreeStyle.css', './static//style/reader-ui-extend.css', './static//style/revise.css'], function (_, C) {
                E.loadCSS(C);
            });
            $.each(['./static//zTree_v3/jquery.ztree.all.js', './static//script/reader-tpl-3.2.0.js', './static//script/template-function.js', './static//rpc/utils.js', './static//rpc/xmlrpc.js'], function (_, J) {
                E.loadJS(J);
            });
        };

        mp._listen = function () {
            var _t = this;

            this.core.on(CP.Operate + 'ops', function () {
                for (var _len = arguments.length, a = new Array(_len), _key = 0; _key < _len; _key++) {
                    a[_key] = arguments[_key];
                }
                var args = a.slice(1);
                var act = args[0];
                var type = args[1];
                var setting = args[2];
                var event = args[3];
                var args = args[4];

                if (typeof _t[act] === 'object') {
                    if (Q.isFunction(_t[act][type])) {
                        _t[act][type](setting, event, args);

                        return _t[act][type];
                    }
                } else {
                    switch (act) {
                        case 'show':
                            _t.isShow = true;
                            break;
                        case 'hide':
                            _t.isShow = false;
                            Manager.setLastAction();
                            break;
                    }
                }
            }).on(CP.Action + 'annot', function () {
                var arg = arguments;
                var status = arg[1];

                if (status == 'save:fail') {
                    Manager.Alert("保存失败", 'error');
                } else if (status == 'save:before') {
                    //Manager.Loading("保存中...");
                } else if (status == 'save:success') {
                    Manager.Alert("保存成功", 'success');
                } else if (status == 'save:none') {
                    Manager.Alert("未作任何修改", 'warning');
                }
            }).on(CP.Book + 'zoom', function () {
                _t.isShow ? Manager.doLastAction.call(this) : null;
            });

            E.qC(BC.Morph, Q('.' + BC.Document)).on('mousedown', function () {
                Manager.hideCover(_t.core);
            })
        };
        Manager.init = function (core) {
            this.core = core;
        }
        Manager.goto = function (reader, target) {
            if (target instanceof Q) {
                reader.jump(target, {top: -150, left: 0});
            } else {
                var offset = target['offset'] && {left: target['offset'][0], top: target['offset'][1]};

                reader.jump(target['index'], offset)
            }
        };
        Manager.setLastAction = function (id, target) {
            if (!id) {
                Manager.clearAll();
            }
            mp.lastAction = {id: id, target: target}
        };
        Manager.doLastAction = function () {
            var id = mp.lastAction.id, target = mp.lastAction.target;
            Manager.clearAll();
            Q(this).trigger(CP.Operate + 'ops', [id, 'goto', target]);
        }
        Manager.creatTree = function (id, dom, data, setting, expandAll) {
            var _t = this;
            if (data.length <= 0) {
                //空数据
                //RE.qNv().attr('id', tree).append(RE.qNv(text)).appendTo(show);
                return;
            }

            var ul = Q('<ul class="treeparent ztree" id="' + id + '"></ul>');
            dom.append(ul);
            setting = Q.extend({
                view: {
                    dblClickExpand: true,
                    showIcon: false,
                    txtSelectedEnable: false,
                    selectedMulti: false,
                    showTitle: false,
                    showLine: false
                },
                callback: {
                    onClick: function (event, treeId, node) {
                        var target = node['target'];
                        if (id == "semantics") {
                            var treeObj = Q.fn.zTree.getZTreeObj(treeId);
                            target = Manager.getRefer(treeObj, node);
                        }
                        if (target) {
                            Q(_t).trigger(CP.Operate + 'ops', [id, 'goto', target]);
                            Manager.setLastAction(id, target);
                        }
                    }
                }
            }, setting || {});
            var ztree = Q.fn.zTree.init(ul, setting, data);
            if (expandAll) {
                ztree.expandAll(true);
            }
            return ztree;
        };
        Manager.getRefer = function (ztree, node) {
            var nodes = ztree.transformToArray(node);
            var refers = [];
            Q.each(nodes, function (_, node) {
                if (typeof node.refer != 'undefined') {
                    refers.push(node.refer);
                }
            });
            return refers;
        };
        Manager.clearAll = function () {
            E.qC(BC.Semantic, Q('.' + BC.Document)).remove();
            E.qC(BC.Mark, Q('.' + BC.Document)).filter(function (i, v) {
                return !Q(v).attr(BA.Category);
            }).remove();
        }
        Manager.fireUI = function (setting) {
            Q(this.core).trigger("ui:action", [setting]);
        }
        Manager.coverShow = false;
        Manager.showCover = function (core) {
            if (!Manager.coverShow) {
                Q('div', Q('.' + BC.Cover)).removeClass(BC.Hide);
                Manager.fireUI.call(core, ['oes:plugins', 'enable']);
                Manager.coverShow = !Manager.coverShow;
            }
        }
        Manager.hideCover = function (core) {
            if (Manager.coverShow) {
                Q('div', Q('.' + BC.Cover)).filter(function (i, v) {
                    return !Q(v).attr(BA.Category);
                }).addClass(BC.Hide);
                Manager.fireUI.call(core, ['oes:plugins', 'disabled'])
                Manager.coverShow = !Manager.coverShow;
            }
        }
        Manager.listenResize = function (mark, data, core) {
            core.on(CP.Book + 'zoom', function () {
                var rect = data.rect, page = data.page, w = page.width();
                mark.css({
                    left: rect[0] * w,
                    top: rect[1] * w,
                    width: rect[2] * w,
                    height: rect[3] * w
                })
            })
        }
        Manager.Alert = function (message, type) {
            this.core.Alert && this.core.Alert(message, type)
        }
        Manager.Loading = function (message) {
            this.core.Loading && this.core.Loading(message)
        }
        Manager.messageBox = function (title, message, event) {
            this.core.messageBox && this.core.messageBox(title, message, event)
        }
        return Manager;
    }();

    var NAME = 'ops',
        EVENT = '.' + NAME,
        //EventNamespace
        DATA = '_' + NAME; //DataName

    var MC = R.Context,
        CP = R.Common.CmdPrefix;
    var is = function (o, f) {
        return o instanceof f;
    };

    var make = function (core) {
        var R = Q(core), mgr = R.data(DATA);

        if (is(mgr, Manager)) {
            console.info('Ops manager alreay init');
        } else {
            R.data(DATA, new Manager(core));
        }
        window.SWR.TplFx && window.SWR.TplFx._init(core);
    };

    var isBind = false,
        bind = function (core) {
            if (!core) {
                console.warn('Reader is invalid');
                return;
            }
            if (isBind) {
                return;
            }
            isBind = true; //core.fire('opt:ops', [cmd, arg0, arg1, ...]);
            Q(core).on(CP.Book + 'opened' + EVENT, function () {
                make(core);
            })
        };

    Q(D).on(CP.Core + 'init' + EVENT, function (_, core) {
        bind(core);
    });
    W.SWR = R;
    G.info('Ops ready');
})(window, window.document, window.jQuery, window.SWR || {});
