// indexedDB.js，浏览器本地数据库操作

// 数据库：IDBDatabase 对象
// 对象仓库：IDBObjectStore 对象
// 索引： IDBIndex 对象
// 事务： IDBTransaction 对象
// 操作请求：IDBRequest 对象
// 指针： IDBCursor 对象
// 主键集合：IDBKeyRange 对象

// IndexedDB 数据库有版本的概念。同一个时刻，只能有一个版本的数据库存在。
// 如果要修改数据库结构（新增或删除表、索引或者主键），只能通过升级数据库版本完成。

const indexDB = {
    // indexedDB兼容
    indexedDB: window.indexedDB || window.webkitindexedDB || window.msIndexedDB || mozIndexedDB,

    // IDBDatabase
    dbs: {}, // {databaseName:db}
    /**
     * 打开数据库
     *     databaseName : 数据库名称
     *     version      : 数据库版本，如果不存在则打开已有同名数据库或新建版本为1的数据库
     *                               如果存在则打开指定版本的数据库，如果不存在则创建该版本的数据库
     *     newStore     : 新追加的存储对象或列表，当新建或更新数据库时使用。
     *                  {
     *                     tableName:"tableName", // 表名。
     *                     key:"key" // 主键，默认建立索引的属性。如果主键存在则指定主键，如果主键不存在则使用自增主键
     *                  }
     *     index        : 索引对象或列表，当新建或更新数据库时使用。
     *                  {
     *                      indexName:"indexName", // 索引名
     *                      unique:false, // 不允许重复的值
     *                  }
     */
    open: function (databaseName, version, newStore, index) {
        return new Promise((resolve, reject) => {
            let request; // IDBRequest 对象

            // 这个方法接受两个参数，第一个参数是字符串，表示数据库的名字。如果指定的数据库不存在，就会新建数据库。
            // 第二个参数是整数，表示数据库的版本。如果省略，打开已有数据库时，默认为当前版本；新建数据库时，默认为1。
            if (version) {
                request = this.indexedDB.open(databaseName, version);
            } else {
                request = this.indexedDB.open(databaseName);
            }

            // 数据库打开异常
            request.onerror = () => {
                console.log('IndexedDB数据库打开错误');
                reject();
            };

            // 数据库打开成功
            request.onsuccess = (event) => {
                console.log('IndexedDB数据库打开成功');
                this.dbs[databaseName] = event.target.result;
                resolve(this.dbs[databaseName]);
            };

            // onupgradeneeded，调用创建新的储存空间
            request.onupgradeneeded = (event) => {
                this.dbs[databaseName] = event.target.result;
                if (newStore) {
                    let stores = Array.isArray(newStore) ? newStore : [newStore];
                    stores.forEach(store => {
                        if (!this.dbs[databaseName].objectStoreNames.contains(store.tableName)) {
                            // 如果主键存在则指定主键，如果主键不存在则使用自增主键
                            let optional = store.key ? {keyPath: store.key} : {autoIncrement: true};
                            let objectStore = this.dbs[databaseName].createObjectStore(store.tableName, optional);
                            // 创建索引
                            let indexs = Array.isArray(index) ? index : [index];
                            indexs.forEach(index => {
                                objectStore.createIndex(index.indexName, index.indexName, {unique: index.unique});
                            })
                        }
                    })
                }
                console.log('IndexedDB数据库已经更新');
            };
        });
    },

    /**
     * 删除数据库，删除之前需要先关闭数据库 {closeDB}
     *     databaseName : 数据库名称
     */
    deleteDB: function (databaseName) {
        return new Promise((resolve, reject) => {
            let request = this.indexedDB.deleteDatabase(databaseName);
            request.onerror = () => {
                console.log('删除数据库出错');
                reject();
            };
            request.onsuccess = () => {
                resolve();
            }
        });
    },

    /**
     * 关闭数据库
     *     databaseName : 数据库名称
     */
    closeDB: function (databaseName) {
        this.dbs[databaseName].close();
        console.log('数据库已关闭');
    },

    /**
     * 插入数据
     *     databaseName : 数据库名称
     *     tableName    : 表名称
     *     data         : 要插入数据库的数据
     *
     */
    insert: function (databaseName, tableName, data) {
        return new Promise((resolve, reject) => {
            let transaction = this.dbs[databaseName].transaction([tableName], 'readwrite');
            let objectStore = transaction.objectStore(tableName)
            if (Array.isArray(data)) {
                data.forEach(item => {
                    objectStore.add(item);
                })
                // TODO 批量插入，操作事件监听
            } else {
                let request = objectStore.add(data);
                request.onsuccess = () => {
                    console.log('数据写入成功');
                    resolve();
                };

                request.onerror = () => {
                    console.log('数据写入失败');
                    reject();
                }
            }
        });
    },

    /**
     * 通过主键查找数据
     *     databaseName : 数据库名称
     *     tableName    : 表名称
     *     option       : 要查询条件
     *                    indexName:索引名称，当索引名称为空时，通过主键查询
     *                    value:查询条件 (IDBKeyRange)
     */
    select: function (databaseName, tableName, option) {
        return new Promise((resolve, reject) => {
            let transaction = this.dbs[databaseName].transaction([tableName], 'readonly');
            let objectStore = transaction.objectStore(tableName);
            let request;
            if (option.indexName) {
                request = objectStore.index(option.indexName).get(option.value);
            } else {
                request = objectStore.get(option.value);
            }

            request.onsuccess = () => {
                console.log('数据查询成功');
                resolve(request.result);
            };

            request.onerror = () => {
                console.log('数据查询失败');
                reject();
            };
        });
    },

    /**
     * 查找数据
     *     databaseName : 数据库名称
     *     tableName    : 表名称
     *     keyRange     : 查找数据的主键范围
     */
    selectListByCursor: function (databaseName, tableName, keyRange) {
        return new Promise((resolve, reject) => {
            let transaction = this.dbs[databaseName].transaction([tableName], 'readonly');
            let objectStore = transaction.objectStore(tableName)
            let request = objectStore.openCursor(keyRange);
            let resultList = [];
            request.onsuccess = (event) => {
                console.log(request);
                let cursor = event.target.result;
                if (cursor) {
                    resultList.push(cursor.value)
                    cursor.continue();
                } else {
                    console.log('数据查询成功');
                    resolve(resultList);
                }
            };

            request.onerror = () => {
                console.log('数据查询失败');
                reject();
            };
        });
    },

    /**
     * 查找数据
     *     databaseName : 数据库名称
     *     tableName    : 表名称
     *     keyRange     : 查找数据的主键范围
     */
    selectList: function (databaseName, tableName, keyRange) {
        return new Promise((resolve, reject) => {
            let transaction = this.dbs[databaseName].transaction([tableName], 'readonly');
            let objectStore = transaction.objectStore(tableName)
            let request = objectStore.getAll(keyRange);
            request.onsuccess = () => {
                console.log('数据查询成功');
                console.log(request);
                resolve(request.result);
            };

            request.onerror = () => {
                console.log('数据查询失败');
                reject();
            };
        });
    },

    /**
     * 通过主键更新数据，当主键不存在时会插入该数据
     *     databaseName : 数据库名称
     *     tableName    : 表名称
     *     object       : 要更新的对象，其中包含主键
     */
    updateByPrimaryKey: function (databaseName, tableName, object) {
        return new Promise((resolve, reject) => {
            let transaction = this.dbs[databaseName].transaction([tableName], 'readwrite');
            let objectStore = transaction.objectStore(tableName)
            let request = objectStore.put(object);
            request.onsuccess = () => {
                console.log('数据更新成功');
                resolve(request.result);
            };

            request.onerror = () => {
                console.log('数据更新失败');
                reject();
            };
        });
    },

    /**
     * 通过主键删除数据
     *     databaseName : 数据库名称
     *     tableName    : 表名称
     *     keyRange     : 要删除的主键范围
     */
    deleteByPrimaryKey: function (databaseName, tableName, keyRange) {
        return new Promise((resolve, reject) => {
            let transaction = this.dbs[databaseName].transaction([tableName], 'readwrite');
            let objectStore = transaction.objectStore(tableName)
            let request = objectStore.delete(keyRange);
            request.onsuccess = () => {
                console.log('数据删除成功');
                resolve(request.result);
            };

            request.onerror = () => {
                console.log('数据删除失败');
                reject();
            };
        });
    },

    /**
     * 清空数据表
     *     databaseName : 数据库名称
     *     tableName    : 表名称
     */
    clear: function (databaseName, tableName) {
        return new Promise((resolve, reject) => {
            let transaction = this.dbs[databaseName].transaction([tableName], 'readwrite');
            let objectStore = transaction.objectStore(tableName)
            let request = objectStore.clear();
            request.onsuccess = () => {
                console.log('数据表清除成功');
                resolve(request.result);
            };

            request.onerror = () => {
                console.log('数据表清除失败');
                reject();
            };
        });
    },

    /**
     * 统计数据表中数据数
     *     databaseName : 数据库名称
     *     tableName    : 表名称
     *     keyRange     : 统计数量的主键范围
     */
    count: function (databaseName, tableName, keyRange) {
        return new Promise((resolve, reject) => {
            let transaction = this.dbs[databaseName].transaction([tableName], 'readwrite');
            let objectStore = transaction.objectStore(tableName)
            let request = objectStore.count(keyRange);
            request.onsuccess = () => {
                resolve(request.result);
            };

            request.onerror = () => {
                reject();
            };
        });
    },

    test: function () {
        this.open("myDB", 2, {tableName: "user", key: "id"}, {indexName: "name"}).then(db => {
            // 插入
            // this.insert("myDB", "user", {id: 1, name: "jason", email: "1067741001@qq.com"})

            // 关闭
            // this.closeDB("myDB");

            // 删除
            // this.deleteDB("myDB").then(() => {
            //     console.log("删除成功");
            // }).catch(() => {
            //     console.log("删除失败");
            // })

            // 主键查找
            // this.select("myDB", "user", {value: 1}).then(data => {
            //     console.log(data);
            // });

            // 索引查找
            // this.select("myDB", "user", {indexName: "name", value: "jason3"}).then(data => {
            //     console.log(data);
            // });

            // 条件查找
            // this.selectListByCursor("myDB", "user", IDBKeyRange.lowerBound(0)).then(data => {
            //     console.log(data);
            // });

            // 主键更新
            // this.updateByPrimaryKey("myDB", "user", {id: 1, name: "jason3", email: "21067741001@qq.com"});

            // 主键删除
            // this.deleteByPrimaryKey("myDB", "user", 2);

            // 清除数据表
            // this.clear("myDB", "user");

            // 统计数据量
            // this.count("myDB", "user", IDBKeyRange.lowerBound(2)).then(count => {
            //     console.log("数据量 : " + count);
            // });

        })
    },

    install: function (Vue) {
        Vue.prototype.$indexDB = this;
    }
}

export default indexDB;

// import IndexDB from '@/utils/indexedDB'
//
// Vue.use(IndexDB);
