# Copyright (C) 2024 Michael Becker  <alcexhim@gmail.com>
# 
# This file is part of yaml2mcl.
# 
# yaml2mcl 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.
# 
# yaml2mcl 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 yaml2mcl.  If not, see <https://www.gnu.org/licenses/>.

from editor.core import ObjectModel, DataFormat, InvalidDataFormatException, ObjectModelNotSupportedException
from editor.core.io import Reader

from io import FileIO

from ..objectmodels import McxObjectModel, McxInstance, McxAttribute, McxRelationship

class McxDataFormat (DataFormat):

	def __init__(self):
		pass

	def get_signature(self) -> str:
		return "MCX!"

	def load_internal(self, object_model : ObjectModel, stream : FileIO):

		if not isinstance(object_model, McxObjectModel):
			raise ObjectModelNotSupportedException

		r = Reader(stream)
		
		# SectionFile header
		signature = r.read_fixedstring(4)
		if signature != self.get_signature():
			raise InvalidDataFormatException
		
		version = r.read_single()
		if version != 2.0:
			raise InvalidDataFormatException
		
		flags = r.read_int32()
		section_count = r.read_int32()
		guid = r.read_guid()
		object_model.set_guid(guid)

		sections = [ ]

		for i in range(0, section_count):
			section_name = r.read_fixedstring(16).strip(' \0')
			offset = r.read_int32()
			length = r.read_int32()
			length2 = r.read_int32()
			itemcount = r.read_int32()

			print('    '+section_name)
			sections.append((section_name, offset, length, length2, itemcount))

		gids = [ ]
		insts = dict()
		strs = [ ]

		for (section_name, offset, length, length2, itemcount) in sections:
			if section_name == 'GUIDTable':
				print("mcx: reading GUID table (offset %s, length %s, count %s)" % (offset, length, itemcount))
				r.get_stream().seek(offset)
				for i in range(0, itemcount):
					gid = r.read_guid()
					gids.append(gid)
					print(gid)
				print (str(len(gids)) + " GUIDs loaded")
			elif section_name == 'StringTable':
				print("mcx: reading string table (offset %s, length %s, count %s)" % (offset, length, itemcount))
				r.get_stream().seek(offset)
				for i in range(0, itemcount):
					strs.append(r.read_terminatedstring())
			elif section_name == 'Defs':
				print("mcx: reading definitions (offset %s, length %s, count %s)" % (offset, length, itemcount))
				r.get_stream().seek(offset)
				for i in range(0, itemcount):
					key = r.read_terminatedstring()
					value = r.read_terminatedstring()
					object_model.define_entity(key, value.lower())

		for (section_name, offset, length, length2, itemcount) in sections:
			if section_name == 'Instances':
				print("mcx: reading instances at offset " + str(offset))
				r.get_stream().seek(offset)
				for i in range(0, itemcount):
					cgidi = r.read_int32()
					cgid = gids[cgidi]
					igidi = r.read_int32()

					igid = None
					if igidi >= 0 and igidi < len(gids):
						igid = gids[igidi]
					else:
						print("not found igid at index " + str(igidi))

					ckey = r.read_int32()
					ikey = r.read_int32()

					inst = McxInstance(cgid, igid, ckey, ikey)
					insts[igid] = inst
					object_model.get_instances().append(inst)

			elif section_name == 'Attributes':
				print("mcx: reading attributes")
				r.get_stream().seek(offset)
				for i in range(0, itemcount):
					srci = r.read_int32()
					src = gids[srci]

					atti = r.read_int32()
					att = gids[atti]

					vali = r.read_int32()
					val = strs[vali]

					isrc = insts[src] if src in insts else None
					iatt = insts[att] if att in insts else None

					object_model.get_attributes().append(McxAttribute(isrc, iatt, val))

			elif section_name == 'Relationships':
				print("mcx: reading relationships")
				r.get_stream().seek(offset)
				for i in range(0, itemcount):
					srci = r.read_int32()
					src = gids[srci]

					reli = r.read_int32()
					rel = gids[reli]

					tgti = r.read_int32()
					tgt = gids[tgti]

					isrc = insts[src] if src in insts else None
					irel = insts[rel] if rel in insts else None
					itgt = insts[tgt] if tgt in insts else None

					object_model.get_relationships().append(McxRelationship(isrc, irel, itgt))
		
			elif section_name == 'Templates':
				print("mcx: reading templates")
				r.get_stream().seek(offset)

				sizes = [ ]
				names = [ ]
				datas = dict()

				from editor.core.io import Endianness
				r.set_endianness(endianness=Endianness.BIG)

				for i in range(0, itemcount):
					nameLen = r.read_int32()
					dataLen = r.read_int32()
					sizes.append((nameLen, dataLen))

				for i in range(0, itemcount):
					nameLen = sizes[i][0]
					names.append(r.read_fixedstring(nameLen))
				
				for i in range(0, itemcount):
					import yaml

					dataLen = sizes[i][1]
					data = yaml.safe_load(r.read_fixedstring(dataLen))

					name = names[i]
					if "customTagName" in data:
						name = data["customTagName"]

					object_model.register_template_definition(name, data)
		pass

	def save_internal(self, object_model : ObjectModel, stream : FileIO):

		pass