# Copyright (C) 2024 Michael Becker  <alcexhim@gmail.com>
# 
# This file is part of Mocha.
# 
# Mocha is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# Mocha is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with Mocha.  If not, see <https://www.gnu.org/licenses/>.

import yaml.scanner
from .MochaLibraryManager import MochaLibraryManager

class MemoryLibraryManager (MochaLibraryManager):

	def __init__(self):
		MochaLibraryManager.__init__(self)
		self.filename = ""
		self.codeDefinitionFileName = ""
		self.parser = None

		self.instance_ops = [ ]
		self.attribute_ops = [ ]
		self.relationship_ops = [ ]

		self.library_reference_guids = [ ]

	def process_attribute_ops(self, ops):
		self.attribute_ops.extend(ops)
			
	def process_instance_ops(self, ops):
		self.instance_ops.extend(ops)

	def process_relationship_ops(self, ops):
		self.relationship_ops.extend(ops)

	def update_global_identifiers(self):
		pass

	def update_creation_user(self):
		pass

	def do_commit(self):
		print("writing file '" + self.filename + "'")

		from .GuidCache import GuidCache

		guid_db = GuidCache()
		strs_db = [ ]

		# *** FIRST PASS ***
		
		# first, go through and load all the instances GUIDs
		for op in self.instance_ops:
			guid_db.add(op.globalIdentifier)
			guid_db.add(op.classGlobalIdentifier)

			# print ("INST: " + str(op.globalIdentifier) + " : " + str(op.classGlobalIdentifier) + " [ " + str(op.classIndex) + "$" + str(op.instanceIndex) + " ]")

		# next, go through and ensure instances and attributes are defined
		for op in self.attribute_ops:
			guid_db.add(op.instanceId)
			if op.instanceId is None:
				print("ERR: op.instanceId is None")
				
			guid_db.add(op.attributeInstanceId)
			if op.attributeInstanceId is None:
				print("ERR: op.attributeInstanceId is None")

			if not str(op.value) in strs_db:
				strs_db.append(str(op.value))

			# print ("ATT: " + str(op.instanceId) + " . " + str(op.attributeInstanceId) + " = " + str(op.value))
		# finally, get the relationship instances 
		for op in self.relationship_ops:
			guid_db.add(op.instanceId)
			guid_db.add(op.relationshipInstanceId)
			guid_db.add(op.targetInstanceId)

			# print ("REL: " + str(op.instanceId) + " . " + str(op.relationshipInstanceId) + " = " + str(op.targetInstanceId))

		print ("processed " + str(guid_db.count()) + " instance references")

		# *** SECOND PASS ***

		# first, go through and load all the instances GUIDs
		refs_db = [ ]
		insts = [ ]
		atts = [ ]
		rels = [ ]
		rsrc_db = [ ]

		rsrc_db.append(bytes([182, 128, 64, 48]))

		for op in self.instance_ops:
			gi = guid_db.get_index(op.globalIdentifier)
			cgi = guid_db.get_index(op.classGlobalIdentifier)
			ckey = op.classIndex
			ikey = op.instanceIndex
			insts.append((gi, cgi, ckey, ikey))

			print ("INST: " + str(op.globalIdentifier) + " : " + str(op.classGlobalIdentifier) + " [ " + str(op.classIndex) + "$" + str(op.instanceIndex) + " ]")

		# next, go through and ensure instances and attributes are defined
		for op in self.attribute_ops:
			srci = guid_db.get_index(op.instanceId)
			atti = guid_db.get_index(op.attributeInstanceId)
			vali = strs_db.index(str(op.value))

			atts.append((srci, atti, vali, None))

			print ("ATT: " + str(op.instanceId) + " . " + str(op.attributeInstanceId) + " = " + str(op.value))
		# finally, get the relationship instances 
		for op in self.relationship_ops:
			srci = guid_db.get_index(op.instanceId)
			reli = guid_db.get_index(op.relationshipInstanceId)
			tgti = guid_db.get_index(op.targetInstanceId)
			rels.append((srci, reli, tgti, None))

			print ("REL: " + str(op.instanceId) + " . " + str(op.relationshipInstanceId) + " = " + str(op.targetInstanceId))

		
		guids = guid_db.to_list()
		defs_db = [ ]
		for ref in self.entityReferences:
			defs_db.append((ref, self.entityReferences[ref]))

		templates_db = dict()
		import yaml
		for key in self.parser.templates:
			templ = self.parser.templates[key]
			key2 = key
			if 'customTagName' in templ:
				key2 = templ['customTagName']

			dump = yaml.safe_dump(templ)
			# print("dump for key '" + str(key2) + "'")
			# print(dump)
			templates_db[str(key2)] = dump

		for r in self.library_reference_guids:
			refs_db.append(r)

		from .sectionfile import SectionFile, Section, GuidSection, InstancesSection, AttributesSection, RelationshipsSection, StringTableSection, ResourcesSection, DefinitionsSection, TemplatesSection
		f = SectionFile("MCX!", 2.0, 15)
		f.open(self.filename)
		
		f.sections.append(GuidSection("GUIDTable", guids))
		f.sections.append(InstancesSection("Instances", insts))
		f.sections.append(AttributesSection("Attributes", atts))
		f.sections.append(RelationshipsSection("Relationships", rels))
		f.sections.append(StringTableSection("StringTable", strs_db))
		f.sections.append(ResourcesSection("Resources", rsrc_db))
		f.sections.append(DefinitionsSection(defs_db))
		f.sections.append(TemplatesSection(templates_db))
		f.sections.append(GuidSection("LibraryRefs", refs_db))

		f.save()

		print ("processed " + str(len(self.instance_ops)) + " instances, " + str(len(self.attribute_ops)) + " attributes, and " + str(len(self.relationship_ops)) + " relationships")