/*
 * @京东APP日历组件库
 * @Author: yuhongliang
 * @Date:   2017-04-24 16:54:34
 * @Last Modified by:   余鸿亮
 * @Last Modified time: 2017-07-10 11:08:23
 */

//umd
;
(function(root, factory) {
    if (typeof exports === 'object' && exports) {
        module.exports = factory(root);
    } else if (typeof define === 'function' && define.amd) {
        define(factory);
    } else root.jdReminder = factory(root);
}(typeof window !== 'undefined' ? window : this, function(window) {

    /**
     * 唯一标识
     */
    var uniqueId = (function() {
        var idCounter = 0;
        return function(prefix) {
            var id = ++idCounter + '';
            return prefix ? prefix + id : id;
        };
    })();

    /**
     * jdreminder异常类
     * @param {[type]} message [description]
     */
    function JdReminderException(message) {
        this.message = message;
        this.name = 'JdReminderException';
        this.toString = function() {
            console.error(this.name + ': ' + this.message);
        }
    }
    JdReminderException.prototype = Object.create(Error.prototype);
    JdReminderException.prototype.constructor = JdReminderException;

    //单例模式变量
    var INSTANCE;

    //shortcut
    var toString = Object.prototype.toString;

    //判断是否为Object
    var isObject = function(options) {
        return toString.call(options) === '[object Object]';
    };
    //判断参数是否为undefined
    var isUndefined = function(param) {
        return typeof param === 'undefined';
    };
    //判断是否为函数
    var isFunction = function(func) {
        return func && (typeof func === 'function');
    };
    //判断是否为数组
    var isArray = function(param) {
        // body...
        return toString.call(param) === '[object Array]';
    };
    //判断是否为字符串
    var isString = function(param) {
            return typeof param === 'string';
        }
        //判断是否为空字符串
    var isEmptyString = function(param) {
        return param === '';
    }

    //入参为undefined时，返回undefined
    //否则返回param值
    var returnDefaultUndefined = function(param) {
        return (typeof param != 'undefined') ? param : undefined;
    };

    //环境变量及简单方法
    var ua = window.navigator.userAgent.toLowerCase();
    var uaArr = ua.split(';');
    var isWKWebview = /supportJDSHWK\/1/i.test(ua); //iosapp,webview内核是否为wk
    var isJd = ua.indexOf('jdapp') != -1;
    var isIphone = uaArr[1] === 'iphone';
    var isAndroid = uaArr[1] === 'android';
    var jdApp = ua.indexOf('jdapp') != -1;
    var uaArr = ua.split(';');
    var jdAppVersion = (function() {
        if (jdApp) {
            return uaArr[2] ? uaArr[2].replace(/\./g, '') : '';
        } else {
            return '';
        }
    })();

    //6.1版本分割线
    var isUsingNewInterface = (function() {
        return jdApp && jdAppVersion >= 610;
    })();

    //扩展对象
    function extendObject(target, source) {
        if (isUndefined(target) || isUndefined(source)) throw new JdReminderException('target, source参数必须提供');
        if (!isObject(target) || !isObject(source)) throw new JdReminderException('target, source参数必须为Object类型');
        for (var prop in source) {
            if (source.hasOwnProperty(prop)) {
                //所有字段转成字符串类型
                target[prop] = source[prop];
            }
        }
        return target;
    }

    /**
     * 解析日历注册回调函数返回参数
     * 旧版中：IOS返回一个参数字符串，形式为'0/1,callbackId'；Android返回两个参数，true/false,callbackId
     * 新版中：IOS，Android均返回两个参数，第一个参数为0/1，第二个参数为callbackId
     *
     * 其中：0/1,true/false表示是否已预约；callbackId为透传值
     * @param  {[type]} ret        [description]
     * @param  {[type]} callBackId [description]
     * @return {[type]}            [description]
     */
    function parseCallbackData(ret, callBackId) {
        var args = arguments;
        var ret, callBackId;
        if (!isUsingNewInterface) {
            //如果第二个参数为undefined
            if (isUndefined(args[1])) {
                var arg = args[0].split(',');
                ret = (arg[0] == 1)
                callBackId = arg[1];
            } else {
                ret = args[0] == 'true';
                callBackId = args[1];
            }
            return { appointed: ret, id: callBackId };
        } else {
            //强行转换为字符串类型
            //以区分'','0','1'
            ret += '';

            //结果标识为预约状态
            if (ret == '1' || ret == '0') return { appointed: ret == '1', id: callBackId };

            //批量查询，第一参数返回数组
            //当没有查到时，IOS返回的是空数组，Android返回的是空字符串
            //android
            if (isEmptyString(ret)) return { status: [], id: callBackId };

            //try...catch保护
            try {
                var allStatus = JSON.parse(ret);
            } catch (e) {
                return { status: [], id: callBackId };
            }

            //ios
            if (isArray(allStatus)) {
                return { status: allStatus, id: callBackId }
            }
        }
    }


    /**
     * JdReminder类构造函数
     * @param {[type]} options [description]
     */
    function JdReminder() {
        if (!(this instanceof JdReminder)) return new JdReminder();
    }

    /**
     * 封装常用函数
     * @return {[type]} [description]
     */
    JdReminder.prototype.util = {
        isNeedChangeStatus: isUsingNewInterface,
        isHighVersion: isUsingNewInterface,
        isJd: isJd,
        isIphone: isIphone,
        isAndroid: isAndroid,
        isObject: isObject,
        isFunction: isFunction,
        isArray: isArray,
        isUndefined: isUndefined,
        isEmptyString: isEmptyString,
        returnDefaultUndefined: returnDefaultUndefined,
        extendObject: extendObject,
        parseCallbackData: parseCallbackData
    }

    //初始化
    JdReminder.prototype.init = function(options) {
        //提醒
        console.warn('init方法不是必须执行的，如果需要设定全局的type值，可以执行该函数进行统一设置；如不需要，可以在添加、取消、查询提醒操作时针对每一条提醒传入相应的type值');

        //定义属性变量
        this.setting = {};

        //拷贝配置数据
        if (options) {
            if (!isObject(options)) throw new JdReminderException('入参必须为Object对象类型');
            else {
                for (var prop in options) {
                    if (options.hasOwnProperty(prop)) {
                        options[prop] = returnDefaultUndefined(options[prop]);
                    }
                }
                extendObject(this.setting, options);
            }
        } else {}
    }

    /**
     * ios6.0版本下url使用的是字符串，6.1及以上版本使用的是json串
     * 为抹平两种之间的差异，方便第三方调用，这里做兼容处理；第三方使用
     * 方式仍为传入url字符串
     * @param  {[type]} url [description]
     * @return {[type]}     [description]
     */
    JdReminder.prototype.transformURLToJSON = function(obj) {
        //6.1及以上版本，使用json串
        //
        if (isUsingNewInterface) obj['url'] = JSON.stringify({
            des: 'm',
            params: {
                url: obj['url']
            }
        });
    }

    /**
     * 将对象中的属性值强制转换成字符串类型
     * @param  {[type]} obj [description]
     * @return {[type]}     [description]
     */
    JdReminder.prototype.transformKeyToString = function(obj) {
        for (var prop in obj) {
            if (obj.hasOwnProperty(prop)) {

                //新版中全部转换成字符串
                if (isUsingNewInterface) {
                    obj[prop] = obj[prop] + '';
                } else {
                    //旧版中android,ios需要针对处理
                    //
                    //
                    //ios该字段需要转换成字符串类型，
                    //android不需要
                    if (prop == 'id') {
                        if (isIphone) obj[prop] = obj[prop] + '';
                    }
                }
            }
        }
        return obj;
    }

    /**
     * 过滤入口参数，如果没有传入相应字段属性，默认设置为空值
     * 另外抹平ios和android间的参数差异
     * @param  {[type]} options [description]
     * @return {[type]}         [description]
     */
    JdReminder.prototype.filterParamOptions = function(options) {
        if (!isObject(options)) { throw new JdReminderException('入参必须为Object对象类型'); return; }

        //拷贝原始数据
        //原因是ios端，add/del时使用的dataType为数字（提供的枚举值）
        //查询预约状态时使用的是字符串。
        //当添加预约后，在执行查询，最后执行删除（整个过程不退出页面）
        //这时删除时会把dataType修改成字符串值，导致删除命令失败
        //
        //因此需要隔离原始对象
        //
        var copiedOptions = {};
        extendObject(copiedOptions, options)

        //释放options数据
        options = null;

        //ios中，开始时间以秒为单位的数字字符串(旧版中)，新版中使用时间戳
        //android中，以毫秒为单位，long类型，时间戳
        //时间戳为13位
        if (isIphone && !isUsingNewInterface) copiedOptions['time'] = (copiedOptions['time'] / 1000) + '';
        console.log("========ios====1111111111", isIphone)
        console.log("==========and=============11111111111", isAndroid)
        console.log("==========ua=============1111111", ua)
            //构造函数里面是否传入了type值，如果有值的话，直接使用构造函数里面的值
            //否则使用传入的type值
        if (isUndefined(this.setting)) {
            if (isUndefined(copiedOptions.type)) throw new JdReminderException('type字段缺失，请在options对象参数中指定');
        } else {
            if (isUndefined(copiedOptions.type)) {
                if (isUndefined(this.setting.type)) throw new JdReminderException('type字段缺失，请在构造函数或options对象参数中指定');
                else {
                    if (isUsingNewInterface) {
                        copiedOptions['type'] = this.setting.type + '';
                    } else {
                        copiedOptions['type'] = this.setting.type;
                    }
                }
            }
        }
        //ios6.0版本下url使用的是字符串，6.1及以上版本使用的是json串
        //为抹平两种之间的差异，方便第三方调用，这里做兼容处理；第三方使用
        //方式仍为传入url字符串
        //
        this.transformURLToJSON(copiedOptions);

        //将传入值全部转成字符串类型
        //
        this.transformKeyToString(copiedOptions);

        //返回options
        return copiedOptions;
    }

    /**
     * ios 6.10版本以下，使用协议形式
     * @param  {[type]} action  [description]
     * @param  {[type]} options [description]
     * @return {[type]}         [description]
     */
    JdReminder.prototype.createIOSSchemaForLowVersion = function(action, options) {
        options = this.filterParamOptions(options);
        options.type = 6;
        return 'openApp.jdMobile://virtual?params={' +
            '"category":"jump",' +
            '"des":"saveToCalender",' +
            '"sourceValue":"sourceValue_saveToCalender",' +
            '"sourceType":"sourceType_saveToCalender",' +
            '"SourceParam":"sourceParam",' +
            '"actionType":"' + action + '",' +
            '"dataType":"' + options.type + '",' +
            '"calendarTitle":"' + options.title + '",' +
            '"beginTime":"' + options.time + '",' +
            '"dataId":"' + options.id + '",' +
            '"jumpUrl":"' + encodeURIComponent(options.url) + '"}';
    }

    /**
     * 安卓 6.10版本以下
     * @param  {[type]} argument [description]
     * @return {[type]}          [description]
     */
    JdReminder.prototype.createAndroidSchemaForLowVersion = function(action, options) {
        options = this.filterParamOptions(options);
        options.type = 'HUODONG';
        if (window.JdAndroid) {
            if (action == 'add') {
                if (isFunction(window.JdAndroid.setJDReminder)) {
                    window.JdAndroid.setJDReminder(options.type, options.id, options.title, options.time, options.url);
                } else throw new JdReminderException('android->setJDReminder不是一个函数，注意该函数应该只在APP内才会有');
            } else if (action == 'del') {
                if (isFunction(window.JdAndroid.cancelJDReminder)) {
                    window.JdAndroid.cancelJDReminder(options.type, options.id, options.time);
                } else throw new JdReminderException('android->cancelJDReminder不是一个函数，注意该函数应该只在APP内才会有');
            }
        } else throw new JdReminderException('android->window.JDAndroid对象不存在，注意该对象应该只在APP内才会有');
    }

    /**
     * 生成addReminder,removeReminder参数
     * @param  {[type]} options [description]
     * @return {[type]}         [description]
     */
    JdReminder.prototype.createReminderOptionsJsonString = function(action, options) {
        console.log('createReminderOptionsJsonString-- - action', action)
        console.log('createReminderOptionsJsonString-- - options', options)
        if (action == 'add') return JSON.stringify({
            businessType: options.type,
            showTag: options.tag || '',
            remindTitle: options.title || '',
            beginTime: options.time,
            uniqueId: options.id,
            jumpStr: options.url || '',
            imgUrl: options.imgUrl || '',
            notifyTime: options.nTime || (options.time - 180000),
            extraStr1: options.extra1 || '',
            extraStr2: options.extra2 || '',
            callBackName: options.addCallback,
            callBackId: options.id,
        });
        if (action == 'del') return JSON.stringify({
            businessType: options.type,
            beginTime: options.time,
            uniqueId: options.id,
            callBackName: options.deleteCallback,
            callBackId: options.id
        });
    }

    /**
     * ios和android在6.1版本上，均对齐，函数签名均一致
     * 因此不需要做平台检测
     * @param  {[type]} action  [description]
     * @param  {[type]} options [description]
     * @return {[type]}         [description]
     */
    JdReminder.prototype.createAllSameSchemaUsingJsBridge = function(action, options) {
        console.log('createAllSameSchemaUsingJsBridge--action', action)
        console.log('createAllSameSchemaUsingJsBridge--options', options)
        options = this.filterParamOptions(options);
        var jsonStringParams = this.createReminderOptionsJsonString(action, options);
        if (window.JDAppUnite) {
            if (action == 'add') {
                console.log('createAllSameSchemaUsingJsBridge--add', isFunction(window.JDAppUnite.addReminder))
                if (isFunction(window.JDAppUnite.addReminder)) {
                    console.log('createAllSameSchemaUsingJsBridge--add', jsonStringParams)
                    window.JDAppUnite.addReminder(jsonStringParams);
                } else throw new JdReminderException('addReminder不是一个函数，注意该函数应该只在APP内才会有');
            } else if (action == 'del') {
                if (isFunction(window.JDAppUnite.removeReminder)) {
                    window.JDAppUnite.removeReminder(jsonStringParams);
                } else throw new JdReminderException('removeReminder不是一个函数，注意该函数应该只在APP内才会有');
            }
        } else throw new JdReminderException('window.JDAppUnite对象不存在，注意该函数应该只在APP内才会有');
    }

    /**
     * 京东客户端6.2版本开始IOS渲染内核改为WK，js和原生的交互方式发生变化，需要单独处理
     * @param  {[type]} action  [description]
     * @param  {[type]} options [description]
     * @return {[type]}         [description]
     */
    JdReminder.prototype.createIOSSchemaForWKWebview = function(action, options) {
        options = this.filterParamOptions(options);
        //wk方式调用
        this.executeIOSSchemaInWKWebviewCircumstance({
            method: ((action == 'add') ? 'addReminder' : 'removeReminder'),
            params: this.createReminderOptionsJsonString(action, options)
        });
    }

    /**
     * WK环境下，执行提醒相关协议
     * @param  {[type]} options [description]
     * @return {[type]}         [description]
     */
    JdReminder.prototype.executeIOSSchemaInWKWebviewCircumstance = function(options) {
        var WKJsonString = extendObject({ callBackName: null, callBackId: null }, options);
        console.log('WKJsonString', WKJsonString)
        try {
            window.webkit.messageHandlers.JDAppUnite.postMessage(WKJsonString);
        } catch (e) {
            throw new JdReminderException('window.webkit.messageHandlers.JDAppUnite.postMessage方法执行错误');
        }
    }

    /**
     * 生成IOS日历schema
     * 三种情况:
     * (1)是否为WK内核
     * (2)>=6.1版本
     * (3)<6.1版本
     * 优先考虑是否支持WK
     * @param  {[type]} action  [description]
     * @param  {[type]} options [description]
     * @return {[type]}         [description]
     */
    JdReminder.prototype.createJdReminderIOSSchema = function(action, options) {
        console.log('createJdReminderIOSSchema---isWKWebview', isWKWebview)
        console.log('createJdReminderIOSSchema---isUsingNewInterface', isUsingNewInterface)
            // body...
        if (isWKWebview) return this.createIOSSchemaForWKWebview(action, options);
        if (!isUsingNewInterface) return this.createIOSSchemaForLowVersion(action, options);
        // ios和android在6.1版本上，均对齐，函数名称和传入的参数类型均一致
        // 因此不需要做平台检测
        else return this.createAllSameSchemaUsingJsBridge(action, options);
    }

    /**
     * 生成Android日历schema
     * @param  {[type]} action  [description]
     * @param  {[type]} options [description]
     * @return {[type]}         [description]
     */
    JdReminder.prototype.createJdReminderAndroidSchema = function(action, options) {
        // body...
        if (!isUsingNewInterface) return this.createAndroidSchemaForLowVersion(action, options);
        // ios和android在6.1版本上，均对齐，函数名称和传入的参数类型均一致
        // 因此不需要做平台检测
        else return this.createAllSameSchemaUsingJsBridge(action, options);
    }

    /**
     * 生成最终的日历schema
     * 分两种环境ios和android
     * @param  {[type]} options [description]
     * @return {[type]}         [description]
     */
    JdReminder.prototype.createJdReminderSchema = function(action, options) {
        if (!isObject(options)) {
            throw new JdReminderException('入口参数必须为Object对象类型');
            return;
        }
        console.log("========ios====", isIphone)
        console.log("==========and=============", isAndroid)
        console.log("==========action=============", action)
        console.log("==========options=============", options)
        if (isIphone) return this.createJdReminderIOSSchema(action, options);
        else if (isAndroid) return this.createJdReminderAndroidSchema(action, options);
    }

    /**
     * 添加提醒
     * @param {[type]} options [description]
     */
    JdReminder.prototype.add = function(options) {
        console.log('添加提醒')
        var self = this;
        return new Promise(function(resolve, reject) {
            //添加提醒时，动态生成全局回调函数
            //为保证回调函数唯一性，可以使用options中的id参数来生成
            //
            var addCallback = function(ret, callBackId) {
                var data = parseCallbackData(ret, callBackId);

                //释放内存
                window[addReminderCallBackName] = null;
                resolve(data);
            }

            //定义函数名称
            var addReminderCallBackName = 'addJdReminderCallback' + options.id;

            //注册全局回调
            window[addReminderCallBackName] = addCallback;

            //将函数名挂载至options对象中
            //
            options.addCallback = addReminderCallBackName;

            //低版本下，IOS返回字符串Schema，android返回undefined
            //高版本下，IOS,Android均通过添加相应的回调来监听操作结果
            var ret = self.createJdReminderSchema('add', options);
            console.log('ret', ret)
            if (isString(ret)) { resolve({ appointed: true, id: options.id }); }
        });
    }

    /**
     * 取消提醒
     * @param  {[type]} options [description]
     * @return {[type]}         [description]
     */
    JdReminder.prototype.delete = function(options, cb) {

        //取消提醒时，动态生成全局回调函数
        //为保证回调函数唯一性，可以使用options中的id参数来生成
        //
        var self = this;
        return new Promise(function(resolve, reject) {
            //定义全局回调函数名称
            var deleteReminderCallbackName = 'deleteJdReminderCallback' + options.id;

            //添加提醒时，动态生成全局回调函数
            //为保证回调函数唯一性，可以使用options中的id参数来生成
            //
            var deleteCallback = function(ret, callBackId) {
                var data = parseCallbackData(ret, callBackId);

                //释放内存
                window[deleteReminderCallbackName] = null;
                resolve(data);
            }

            //注册全局回调函数
            window[deleteReminderCallbackName] = deleteCallback;

            //挂载
            options.deleteCallback = deleteReminderCallbackName;

            //低版本下，IOS返回字符串Schema，android返回undefined
            //高版本下，IOS,Android均通过添加相应的回调来监听操作结果
            var ret = self.createJdReminderSchema('del', options);
            if (isString(ret)) { resolve({ appointed: true, id: options.id }) }
        });
    }


    /**
     * 检测预约状态
     * 单个检测
     * ios,android端均通过回调方式返回预约状态信息
     * @param  {[type]} options [description]
     * @return {[type]}         [description]
     */
    JdReminder.prototype.checkStatus = function(options) {
        var self = this;
        return new Promise(function(resolve, reject) {
            //过滤参数
            options = self.filterParamOptions(options);
            var params;

            //检测预约状态回调函数
            var statusCallback = function(ret, callBackId) {
                var data = parseCallbackData(ret, callBackId);

                //释放内存
                window['checkReminderCallback'] = null;
                resolve(data);
            };

            //挂载全局回调函数
            window['checkReminderCallback'] = statusCallback;

            //iphone
            if (isIphone) {
                //支持WK
                if (isWKWebview) {
                    return self.executeIOSSchemaInWKWebviewCircumstance({
                        method: 'checkReminder',
                        params: JSON.stringify({
                            businessType: options.type,
                            beginTime: options.time,
                            uniqueId: options.id,
                            callBackName: 'checkReminderCallback',
                            callBackId: options.id
                        })
                    });
                }
                //不支持WK
                if (!isUsingNewInterface) {
                    options.type = 'HUODONG';
                    params = JSON.stringify({
                        dataType: options.type,
                        beginTime: options.time,
                        jumpUrl: options.url,
                        callBackName: 'checkReminderCallback',
                        callBackId: options.id
                    });
                } else {
                    params = JSON.stringify({
                        businessType: options.type,
                        beginTime: options.time,
                        uniqueId: options.id,
                        callBackName: 'checkReminderCallback',
                        callBackId: options.id
                    });
                }
                if (!isUsingNewInterface) window.MobileNavi && window.MobileNavi.checkReminder(params);
                else window.JDAppUnite && window.JDAppUnite.checkReminder(params);
            } else if (isAndroid) {
                //android
                if (!isUsingNewInterface) {
                    if (window.JdAndroid) {
                        if (isFunction(window.JdAndroid.checkReminder)) {
                            window.JdAndroid.checkReminder(options.type, options.id, options.time, options.id);
                        } else throw new JdReminderException('window.JdAndroid.checkReminder 不是一个函数');
                    } else throw new JdReminderException('window.JdAndroid不存在，注意该对象只在APP内才会有')
                } else {
                    if (window.JDAppUnite) {
                        if (isFunction(window.JDAppUnite.checkReminder)) {
                            window.JDAppUnite.checkReminder(JSON.stringify({
                                businessType: options.type,
                                beginTime: options.time,
                                uniqueId: options.id,
                                callBackName: 'checkReminderCallback',
                                callBackId: options.id
                            }));
                        } else throw new JdReminderException('window.JDAppUnite.checkReminder 不是一个函数');
                    } else throw new JdReminderException('window.JDAppUnite不存在，注意该对象只在APP内才会有');
                }
            } else {}
        });
    }


    /**
     * 查询某一时间段内的所有预约
     * 该函数在6.1版本开始提供，ios,android端命名空间和函数签名均对齐
     * 这里不做平台区分处理
     * @param  {[type]} options [description]
     * @return {[type]}         [description]
     */
    JdReminder.prototype.returnAllRemindedStatusInTimeSpan = function(options) {
        var uId = uniqueId();
        var self = this;
        //map数据, 输出格式为 { id: appointed, ... }
        function dataMap(ids) {
            var data = {};
            ids.forEach(function(id) {
                //查出来的数据，全是被设置提醒过的
                data[id] = true;
            });
            return data;
        }

        //return promise
        return new Promise(function(resolve, reject) {
            //注入全局回调函数
            var callBackName = 'checkAllJdRemindedStatusCallback' + uId;
            var jsonStringParams = JSON.stringify({
                businessType: options.type,
                fromTime: options.fromTime + '' || '',
                toTime: options.toTime + '' || '',
                callBackName: callBackName,
                callBackId: uId
            });
            window[callBackName] = function(ret, callBackId) {
                    //返回的是已添加提醒id数组
                    var ids = parseCallbackData(ret, callBackId);
                    //释放内存
                    window[callBackName] = null;
                    resolve(dataMap(ids.status));
                }
                //支持WK
            if (isWKWebview) {
                self.executeIOSSchemaInWKWebviewCircumstance({
                    method: 'getAllRemindersWithTimeSpanAndBusinessType',
                    params: jsonStringParams
                });
            } else {
                if (window.JDAppUnite) {
                    //过滤非函数
                    if (!isFunction(window.JDAppUnite.getAllRemindersWithTimeSpanAndBusinessType)) {
                        throw new JdReminderException('window.JDAppUnite.getAllRemindersWithTimeSpanAndBusinessType不是函数');
                        return;
                    }
                    //执行批量查询
                    window.JDAppUnite.getAllRemindersWithTimeSpanAndBusinessType(jsonStringParams);
                } else {
                    throw new JdReminderException('window.JDAppUnite不存在，注意该对象只在APP内才会有');
                }
            }
        });
    }

    /**
     * 批量查询，传入options数组
     * 不过该方法对性能损耗较大，原因是频繁连接数据库
     * 在app新版下，使用app提供的批量查询接口，一次性查出预约
     * 过的信息，此种情况下只需连接一次数据库
     * @param  {[type]} optArray [description]
     * @return {[type]}          [description]
     */
    JdReminder.prototype.returnAllRemindedStatusUsingOptions = function(optionsArr) {
        // body...
        //
        if (!isArray(optionsArr)) { throw new JdReminderException('optionsArr参数必须为数组'); return; }

        //定义变量
        var checkedCount = 0;
        var currentIndex = 0;
        var allCount = optionsArr.length;
        var invalideCount = 0;
        var retArray = [];
        var self = this;

        //map数据，输出格式为 { id: appointed, ... }
        function dataMap(retArray) {
            var data = {};
            retArray.forEach(function(ret) {
                data[ret.id] = ret.appointed || false;
            });
            return data;
        }

        //return promise
        return new Promise(function(resolve) {
            // body...
            //
            var check = function() {
                if (currentIndex <= allCount - 1) {
                    var option = optionsArr[currentIndex];
                    if (!isObject(option)) {
                        throw new JdReminderException('optionsArr数组内部子项不是Object类型数据');
                        invalideCount++;
                    } else {
                        self.checkStatus(option).then(function(data) {

                            //放入数据
                            retArray.push(data);

                            //记数加一
                            currentIndex++;
                            checkedCount++;
                            if (checkedCount == allCount - invalideCount) resolve(dataMap(retArray));
                            else check();
                        });
                    }
                } else {
                    if (checkedCount == allCount - invalideCount) resolve(dataMap(retArray));
                }
            }
            check();
        });
    }


    /**
     * 返回所有预约信息
     * 兼容新版提供的批量查询和旧版的循环遍历查询
     * @param  {[type]} param [description]
     * @return {[type]}       [description]
     */
    JdReminder.prototype.returnAllRemindedStatus = function(param) {}

    //构建单例模式
    if (!INSTANCE) INSTANCE = JdReminder();

    //返回对象
    return INSTANCE;

}));