import copy
from .output import basic_gds_output

from time import localtime
import sys

from . import key_records 
from ..geometry.shapes.basic import shape_rect

__all__ = ["gds_output_key"]

class gds_output_key(basic_gds_output):
	#----------------------------------------------------------------------------
	#Layout-level output functions
	#----------------------------------------------------------------------------

	def __list_library_header__(self, library):
		self.init_library_header(library)
		return ([key_records.Header,
				   " 5;\n",
				   key_records.BgnLib,
				   ";\n",
				   key_records.LastMod,
				   " ",
				   __str_date__(self.library.modified),
				   ";\n",
				   key_records.LastAcc,
				   " ",
				   __str_date__(self.library.accessed),
				   ";\n",
				   key_records.LibName,
				   " ",
				   self.library.name,
				   ";\n",
				   key_records.Units,
				   ";\n",
				   key_records.UserUnits,
				   " ",
				   str(self.library.grid/self.library.unit),
				   ";\n",
				   key_records.PhysUnits,
				   " ",
				   str(self.library.grid),
				   ";\n"])

	def __list_library_footer__(self):
		self.fini_library_footer()
		return key_records.EndLib + ";\n"

	def __list_structure_header__(self, item):
		sname = self.scramble_structure_name(item.name)
		return ([__str_comment__("Structure: " + item.name),
						__str_comment__(item.comment),
						key_records.BgnStr,
						";\n",
						key_records.Creation,
						" ",
						__str_date__(item.created),
						";\n",
						key_records.LastMod,
						" ",
						__str_date__(item.modified),
						";\n",
						key_records.StrName,
						" ",
						sname,
						";\n"
						])

	#generate the footer for any structure
	def __list_structure_footer__(self, item):
		sname = self.scramble_structure_name(item.name)
		return key_records.EndStr + " " + sname + ";\n\n"

	#----------------------------------------------------------------------------
	#Element level output functions
	#----------------------------------------------------------------------------

	#text
	def list_label_element (self, item, additional_transform = None):
		T = item.transformation + additional_transform # make a copy because there is also the height
		coordinates = [T.__translate__(item.coordinate)]
		T.magnification *= item.height
		return [
			key_records.Text,
			"; ",
			self.__str_layer__(item.layer),
			"\n",
			key_records.TextType,
			" 0;\n",
			key_records.Presentation,
			" ",
			str(item.h_alignment),
			",",
			str(item.v_alignment),
			",",
			str(item.font),
			";\n",
			key_records.PathType,
			" 1;\n",
			__str_transformation__(T),
			self.__str_coordinatelist__(coordinates),
			key_records.String,
			" \"",
			item.text,
			"\";\n",
			key_records.EndEl,
			";\n"
			]

	#references
	def list_sref_element (self, item, additional_transform = None):
		T = item.transformation + gds_translation(item.position) + additional_transform
		coordinates = T.apply([(0.0, 0.0)])
		sname = self.scramble_structure_name(item.reference.name)
		return (
			[key_records.SRef,
			";\n",
			key_records.SName,
			 " ",
			 sname,
			 ";\n",
			 __str_transformation__(T),
			 self.__str_coordinatelist__(coordinates),
			 key_records.EndEl,
			 ";\n"
			 ])

	def list_aref_element (self, item, additional_transform = None):
		T = item.transformation + gds_translation(item.origin) + additional_transform
		sname = self.scramble_structure_name(item.reference.name)
		coordinates = T.apply([(0.0, 0.0), (item.n_o_periods[0] * item.period[0], 0.0),(0.0, item.n_o_periods[1] * item.period[1])])
		return ([
			key_records.ARef,
			";\n",
			key_records.SName,
			" ",
			sname,
			";\n",
			key_records.ColRow,
			" { ",
			str(int(item.n_o_periods[0])),
			" , ",
			str(int(item.n_o_periods[1])),
			" };\n",
			__str_transformation__(T),
			self.__str_coordinatelist__(coordinates),
			key_records.EndEl,
			";\n"
			])

	def list_box_element (self, item, additional_transform = None):
		T = item.transformation + additional_transform
		coordinates = T(shape_rect(item.center, item.box_size)).tolist()
		return ([
			key_records.Box,
			"; ",
			self.__str_layer__(item.layer),
			key_records.BoxType,
			" 0;\n",
			self.__str_coordinatelist__(coordinates),
			key_records.EndEl,
			";\n"
			])

	def list_path_element (self, layer, coordinates, line_width, path_type):
		return ([
			key_records.Path,
			"; ",
			self.__str_layer__(layer),
			key_records.DataType,
			" 0; ",
			key_records.PathType,
			" ",
			str(path_type),
			"; ",
			key_records.Width,
			" ",
			str(self.library.snap_value(self.__scale_value__(line_width))),
			";\n",
			self.__str_coordinatelist__(coordinates),
			key_records.EndEl,
			";\n"
			])

	def list_boundary_element (self, layer, coordinates):
		return ([
			key_records.Boundary,
			"; ",
			self.__str_layer__(layer),
			key_records.DataType,
			" 0; \n",
			self.__str_coordinatelist__(coordinates),
			key_records.EndEl,
			";\n"
			])

	#generate coordinate strings from a list of coordinates
	def __str_coordinatelist__ (self, coordinates):
		ret_data = ["   ",
				   key_records.XY,
				   " ",
				   str(len(coordinates)),
				   ";\n"
				   ]
		#rounded_coordinates = self.round_coordinates(coordinates)
		for coord in coordinates:
			ret_data.extend([" ",
							 key_records.X,
							 " ",
							 str(self.__scale_value__(coord[0])),
							 ";   ",
							key_records.Y,
							 " " ,
							str(self.__scale_value__(coord[1])),
							 ";\n"
							 ])
		return "".join(ret_data)


	def __str_layer__(self, layer):
		return "".join([ key_records.Layer,
						" ",
						str(layer.number),
						"; "])

	#----------------------------------------------------------------------------
	# Low-level output
	#----------------------------------------------------------------------------

#Create the date strings
def __str_date__(T = None):
	if T == None: T = time()
	t = localtime(T)
	return "{" + strftime("%y-%m-%d  %H:%M:%S", t) + "}"

#Generate comment in the Key file
def __str_comment__(text):
	return "# " + text + "\n"


def __str_transformation__(transform):
	flip = transform.flip
	rotation = transform.rotation

	if flip:
		flipstr = "1"
	else:
		flipstr = "0"

	if transform.absolute_rotation:
		arotstr = "1"
	else:
		arotstr = "0"

	if transform.absolute_magnification:
		amagstr = "1"
	else:
		amagstr = "0"
		
	return "".join(["   ",
				key_records.STrans,
				" ",
				flipstr,
				",",
				amagstr ,
				",",
				arotstr,
				" ; ",
				key_records.Mag,
				" ",
				str(transform.magnification),
				" ; ",
				key_records.Angle,
				" ",
				str(rotation),
				" ; \n"
				])
