# coding: utf-8

import json

import lmdb

import lglass.rpsl
import lglass.database.base

@lglass.database.base.register("lmdb")
class LMDBDatabase(lglass.database.base.Database):
	def __init__(self, env_or_path, lib=None):
		if isinstance(env_or_path, lmdb.Environment):
			self.env = env_or_path
		elif isinstance(env_or_path, str):
			if lib is None:
				lib = lmdb.LibLMDB()
			elif isinstance(lib, str):
				lib = lmdb.LibLMDB(lib)
			elif isinstance(lib, lmdb.LibLMDB):
				pass
			else:
				raise TypeError("Expected lib to be None, str or lmdb.LibLMDB, got {}".format(type(lib)))

			self.env = lmdb.Environment(lib)
			self.env.open(env_or_path)
		else:
			raise TypeError("EXpected env_or_path to be lmdb.Environment or str, got {}".format(type(env_or_path)))

		with self.env.transaction() as txn:
			with txn.primary_database as db:
				if "+directory" not in db:
					db["+directory"] = json.dumps([])
	
	def get(self, type, primary_key):
		with self.env.transaction(lmdb.MDB_RDONLY) as txn:
			obj = txn["+".join((type, primary_key))].decode()
		return lglass.rpsl.Object.from_string(obj)

	def list(self):
		with self.env.transaction(lmdb.MDB_RDONLY) as txn:
			directory = txn["+directory"].decode()
		for entry in json.loads(directory):
			yield tuple(entry)

	def find(self, primary_key, types=None):
		with self.env.transaction(lmdb.MDB_RDONLY) as txn:
			directory = txn["+directory"].decode()
		for entry in json.loads(directory):
			if types is not None and entry[0] not in types:
				continue
			if entry[1] != primary_key:
				continue
			yield self.get(*entry)

	def save(self, object):
		with self.env.transaction() as txn:
			txn["+".join(object.spec)] = object.pretty_print()
			directory = json.loads(txn["+directory"].decode())
			if list(object.spec) not in directory:
				directory.append(list(object.spec))
				txn["+directory"] = json.dumps(directory)

	def delete(self, type, primary_key):
		with self.env.transaction() as txn:
			del txn["+".join((type, primary_key))]
			directory = json.loads(txn["+directory"].decode())
			directory.remove([type, primary_key])
			txn["+directory"] = json.dumps(directory)

	def __hash__(self):
		return hash(self.env)

	@classmethod
	def from_url(cls, url):
		return cls(url.path)


@@ -682,9 +682,9 @@
 r(%22E
-X
+x
 pect
@@ -767,153 +767,8 @@
 h)))
-%0A%0A%09%09with self.env.transaction() as txn:%0A%09%09%09with txn.primary_database as db:%0A%09%09%09%09if %22+directory%22 not in db:%0A%09%09%09%09%09db%5B%22+directory%22%5D = json.dumps(%5B%5D)
 %0A%09%0A%09
@@ -861,20 +861,17 @@
 %0A%09%09%09
-obj = txn%5B%22+
+key = %22%5C0
 %22.jo
@@ -893,16 +893,33 @@
 ry_key))
+%0A%09%09%09obj = txn%5Bkey
 %5D.decode
@@ -1044,85 +1044,41 @@
 %0A%09%09%09
-directory = txn%5B%22+directory%22%5D.decode()%0A%09%09for entry in json.loads(directory
+for key, value in txn.cursor(
 ):%0A
+%09
 %09%09%09y
@@ -1088,21 +1088,40 @@
 d tuple(
-entry
+key.decode().split(%22%5C0%22)
 )%0A%0A%09def 
@@ -1217,88 +1217,84 @@
 %0A%09%09%09
-directory = txn%5B%22+directory%22%5D.decode
+for key, value in txn.cursor
 ()
+:
 %0A%09%09
-for entry in json.loads(directory):
+%09%09type, pk = key.decode().split(%22%5C0%22)
 %0A%09%09%09
+%09
 if t
@@ -1318,20 +1318,12 @@
 and 
-entry%5B0%5D not
+type
  in 
@@ -1329,24 +1329,25 @@
  types:%0A%09%09%09%09
+%09
 continue%0A%09%09%09
@@ -1347,25 +1347,14 @@
 nue%0A
+%09
 %09%09%09if
- entry%5B1%5D !=
  pri
@@ -1361,18 +1361,25 @@
 mary_key
+ != pk
 :%0A
+%09
 %09%09%09%09cont
@@ -1390,29 +1390,60 @@
 %0A%09%09%09
+%09
 yield 
-self.get(*entry
+lglass.rpsl.Object.from_string(value.decode()
 )%0A%0A%09
@@ -1507,22 +1507,25 @@
 txn:%0A%09%09%09
-txn%5B%22+
+key = %22%5C0
 %22.join(o
@@ -1535,16 +1535,27 @@
 ct.spec)
+%0A%09%09%09txn%5Bkey
 %5D = obje
@@ -1574,190 +1574,8 @@
 int(
-)%0A%09%09%09directory = json.loads(txn%5B%22+directory%22%5D.decode())%0A%09%09%09if list(object.spec) not in directory:%0A%09%09%09%09directory.append(list(object.spec))%0A%09%09%09%09txn%5B%22+directory%22%5D = json.dumps(directory
 )%0A%0A%09
@@ -1661,17 +1661,18 @@
 el txn%5B%22
-+
+%5C0
 %22.join((
@@ -1695,148 +1695,8 @@
 y))%5D
-%0A%09%09%09directory = json.loads(txn%5B%22+directory%22%5D.decode())%0A%09%09%09directory.remove(%5Btype, primary_key%5D)%0A%09%09%09txn%5B%22+directory%22%5D = json.dumps(directory)
 %0A%0A%09d

Implement new format for LMDB database