// 浏览器数据库 IndexedDB 
// [https://wangdoc.com/javascript/bom/indexeddb]
// [https://www.ruanyifeng.com/blog/2018/07/indexeddb.html]

var db = null
export default {
	/**
	 * 打开数据库
	 * @param {string} dbName 数据库的名字
	 * @param {int} version 数据库的版本
	 * @return {object} 该函数会返回一个数据库实例
	 */
	async openDB(dbName = 'Asistent', version = 1) {
		return new Promise((resolve, reject) => {
			//  兼容浏览器
			var indexedDB =
				window.indexedDB ||
				window.mozIndexedDB ||
				window.webkitIndexedDB ||
				window.msIndexedDB;
			
			// 打开数据库，若没有则会创建
			const request = indexedDB.open(dbName, version);
			
			// 数据库打开成功回调
			request.onsuccess = function(event) {
				db = event.target.result; // 数据库对象
				console.log(`数据库打开成功 name: ${db.name} version: ${db.version}`);
				resolve(db);
			};
			
			// 数据库打开失败的回调
			request.onerror = function(err) {
				db = null
				console.log(`数据库打开报错 name: ${db.name} version: ${db.version}`, err);
				reject(err)
			};
			
			// 数据库意外关闭的回调
			request.onclose = function(event) {
				db = null
				console.log(`数据库意外关闭 name: ${db.name} version: ${db.version}`, event);
			};
			
			// 数据库有更新时候的回调
			request.onupgradeneeded = function(event) {
				// 数据库创建或升级的时候会触发
				console.log("数据库有更新");
				db = event.target.result; // 数据库对象
				var objectStore;

				if (dbName == 'Asistent') {
					if (!db.objectStoreNames.contains('mapInfo')) {
						// 创建存储库
						objectStore = db.createObjectStore("mapInfo", {
							keyPath: "shopId", // 这是主键
							// autoIncrement: false // 实现自增
						});

						// 创建索引，在后面查询数据的时候可以根据索引查
						objectStore.createIndex("mapName", "mapName", {
							unique: false
						});
					}
				}
			};
		});
	},

	/**
	 * 新增数据
	 * @param {string} storeName 仓库名称
	 * @param {string} data 数据
	 */
	insertData(storeName, data) {
		if (db == null) {
			console.warn('[insertData] IndexedDB 数据库尚未连接')
			return
		}
		
		var request = db
			.transaction([storeName], "readwrite") // 事务对象 指定表格名称和操作模式（"只读"或"读写"）
			.objectStore(storeName) // 仓库对象
			.add(data);

		request.onsuccess = function(event) {
			console.log("数据写入成功");
		};

		request.onerror = function(err) {
			console.log("数据写入失败", err);
		};
	},

	/**
	 * 更新数据
	 * @param {string} storeName 仓库名称
	 * @param {object} data 数据
	 */
	updateData(storeName, data) {
		if (db == null) {
			console.warn('[updateData] IndexedDB 数据库尚未连接')
			return
		}
		
		var request = db
			.transaction([storeName], "readwrite") // 事务对象
			.objectStore(storeName) // 仓库对象
			.put(data);	//put方法有两个参数，第一个参数是要更新的value，第二个参数是要更新的key，如果忽略第二个参数，默认会使用创建存储对象时指定的 keyPath

		request.onsuccess = function() {
			console.log("数据更新成功");
		};

		request.onerror = function(err) {
			console.log("数据更新失败", err);
		};
	},

	/**
	 * 通过主键删除数据
	 * @param {string} storeName 仓库名称
	 * @param {object} key 主键值
	 */
	deleteDataByKey(storeName, key) {
		if (db == null) {
			console.warn('[deleteDataByKey] IndexedDB 数据库尚未连接')
			return
		}
		
		var request = db
			.transaction([storeName], "readwrite")
			.objectStore(storeName)
			.delete(key);

		request.onsuccess = function() {
			console.log("数据删除成功");
		};

		request.onerror = function(err) {
			console.log("数据删除失败", err);
		};
	},

	/**
	 * 通过索引和游标删除指定的多条数据
	 * @param {string} storeName 仓库名称
	 * @param {string} indexName 索引名
	 * @param {object} indexValue 索引值
	 */
	deleteDataByIndex(storeName, indexName, indexValue) {
		if (db == null) {
			console.warn('[deleteDataByIndex] IndexedDB 数据库尚未连接')
			return
		}
		
		var store = db.transaction(storeName, "readwrite").objectStore(storeName);
		var request = store
			.index(indexName) // 索引对象
			.openCursor(IDBKeyRange.only(indexValue)); // 指针对象
			
		request.onsuccess = function(e) {
			var cursor = e.target.result;
			var deleteRequest;
			if (cursor) {
				deleteRequest = cursor.delete(); // 请求删除当前项
				deleteRequest.onsuccess = function() {
					console.log("游标删除该记录成功");
				};
				deleteRequest.onerror = function(err) {
					console.log("游标删除该记录失败", err);
				};
				cursor.continue();
			}
		};
		
		request.onerror = function(err) {
			console.log("索引游标查询失败", err);
		};
	},

	/**
	 * 通过主键读取数据
	 * @param {string} storeName 仓库名称
	 * @param {string} key 主键值
	 */
	getDataByKey(storeName, key) {
		if (db == null) {
			console.warn('[getDataByKey] IndexedDB 数据库尚未连接')
			return
		}
		
		return new Promise((resolve, reject) => {
			var transaction = db.transaction([storeName]); // 事务
			var objectStore = transaction.objectStore(storeName); // 仓库对象
			var request = objectStore.get(key); // 通过主键获取数据

			request.onsuccess = function(event) {
				console.log("主键查询结果: ", request.result);
				resolve(request.result);
			};
			
			request.onerror = function(err) {
				console.log("主键查询失败", err);
				reject(err)
			};
		});
	},

	/**
	 * 通过游标读取数据
	 * @param {string} storeName 仓库名称
	 */
	cursorGetAllData(storeName) {
		if (db == null) {
			console.warn('[cursorGetAllData] IndexedDB 数据库尚未连接')
			return
		}
		
		return new Promise((resolve, reject) => {
			let list = [];
			var store = db
				.transaction(storeName, "readwrite") // 事务
				.objectStore(storeName); // 仓库对象
			var request = store.openCursor(); // 指针对象
			
			// 游标开启成功，逐行读数据
			request.onsuccess = function(e) {
				var cursor = e.target.result;
				if (cursor) {
					// 必须要检查
					list.push(cursor.value);
					cursor.continue(); // 遍历了存储对象中的所有内容
				} else {
					console.log("游标读取的数据：", list);
					resolve(list);
				}
			};
			
			request.onerror = function(err) {
				console.log("游标读取数据失败", err);
			};
		});
	},

	/**
	 * 通过索引读取数据
	 * @param {string} storeName 仓库名称
	 * @param {string} indexName 索引名称
	 * @param {string} indexValue 索引值
	 */
	getDataByIndex(storeName, indexName, indexValue) {
		if (db == null) {
			console.warn('[getDataByIndex] IndexedDB 数据库尚未连接')
			return
		}
		
		var store = db.transaction(storeName, "readwrite").objectStore(storeName);
		var request = store.index(indexName).get(indexValue);

		request.onsuccess = function(e) {
			var result = e.target.result;
			console.log("索引查询结果：", result);
		};
		
		request.onerror = function(err) {
			console.log("索引查询失败", err);
		};
	},

	/**
	 * 通过索引和游标查询多条记录
	 * @param {string} storeName 仓库名称
	 * @param {string} indexName 索引名称
	 * @param {string} indexValue 索引值
	 */
	cursorGetDataByIndex(storeName, indexName, indexValue) {
		if (db == null) {
			console.warn('[cursorGetDataByIndex] IndexedDB 数据库尚未连接')
			return
		}
		
		return new Promise((resolve, reject) => {
			let list = [];
			var store = db.transaction(storeName, "readwrite").objectStore(storeName); // 仓库对象
			var request = store
				.index(indexName) // 索引对象
				.openCursor(IDBKeyRange.only(indexValue)); // 指针对象
				
			request.onsuccess = function(e) {
				var cursor = e.target.result;
				if (cursor) {
					// 必须要检查
					list.push(cursor.value);
					cursor.continue(); // 遍历了存储对象中的所有内容
				} else {
					console.log("游标索引查询结果：", list);
					resolve(list);
				}
			};
			
			request.onerror = function(err) {
				console.log("游标索引查询失败", err);
			};
		});
	},

	/**
	 * 通过索引和游标分页查询记录
	 * @param {string} storeName 仓库名称
	 * @param {string} indexName 索引名称
	 * @param {string} indexValue 索引值
	 * @param {number} page 页码
	 * @param {number} pageSize 查询条数
	 */
	cursorGetDataByIndexAndPage(
		storeName,
		indexName,
		indexValue,
		page,
		pageSize
	) {
		if (db == null) {
			console.warn('[cursorGetDataByIndexAndPage] IndexedDB 数据库尚未连接')
			return
		}
		
		let list = [];
		let counter = 0; // 计数器
		let advanced = true; // 是否跳过多少条查询
		var store = db.transaction(storeName, "readwrite").objectStore(storeName); // 仓库对象
		var request = store
			.index(indexName) // 索引对象
			.openCursor(IDBKeyRange.only(indexValue)); // 指针对象
			
		request.onsuccess = function(e) {
			var cursor = e.target.result;
			if (page > 1 && advanced) {
				advanced = false;
				cursor.advance((page - 1) * pageSize); // 跳过多少条
				return;
			}
			if (cursor) {
				// 必须要检查
				list.push(cursor.value);
				counter++;
				if (counter < pageSize) {
					cursor.continue(); // 遍历了存储对象中的所有内容
				} else {
					cursor = null;
					console.log("分页查询结果", list);
				}
			} else {
				console.log("分页查询结果", list);
			}
		};
		
		request.onerror = function(err) {
			console.log("分页查询失败", err);
		};
	},

	/**
	 * 关闭数据库
	 * @param {object} db 数据库实例
	 */
	closeDB() {
		if (db == null) {
			console.warn('[closeDB] IndexedDB 数据库尚未连接')
			return
		}
		
		db.close();
		db = null
		console.log("关闭数据库");
	},

	/**
	 * 删除数据库
	 * @param {object} dbName 数据库名称
	 */
	deleteDBAll(dbName) {
		console.log(dbName);
		let deleteRequest = window.indexedDB.deleteDatabase(dbName);

		deleteRequest.onsuccess = function(event) {
			console.log("删除成功");
		};
		deleteRequest.onerror = function(err) {
			console.log("删除失败", err);
		};
	}
}