from gk_input import *
from time import *
from key_records import *
from gk_global import *
from gk_transforms import *
from string import *
from sys import *

class key_record(object):
    def __init__(self,rtype, data):
        self.rtype = rtype
        self.data= data

class gds_input_key(basic_gds_input):
    def __init__(self, input_stream = sys.stdin):
        basic_gds_input.__init__(self, input_stream )
        self.__current_structure__ = None

    def __parse_library__ (self):
        uu = False
        pu = False

        while 1:
            r = self.__parse_record__()
            t = r.rtype #type
            d = r.data #data
            if t == KeyRecordTypeBgnStr:
                self.__parse_structure__()
            elif t == KeyRecordTypeHeader:
                #header is not parsed in an import
                continue
            elif t == KeyRecordTypeBgnLib:
                #header is not parsed in an import
                continue
            elif t == KeyRecordTypeLastMod:
                self.library.modified = self.__parse_time__(d)
                continue
            elif t == KeyRecordTypeLastAcc:
                self.library.accessed = self.__parse_time__(d)
                continue
            elif t == KeyRecordTypeUnits:
                #This is only an announcement
                continue
            elif t == KeyRecordTypeUserUnits:
                import_key_Unit = self.__parse_float__(d)
                uu = True
                if uu and pu:
                    self.library.set_unit(import_key_Grid / import_key_Unit)
            elif t == KeyRecordTypePhysUnits:
                import_key_Grid = self.__parse_float__(d)
                self.library.set_grid (import_key_Grid)
                pu = True
                if uu and pu:
                    self.library.set_unit(import_key_Grid / import_key_Unit)

            elif t == KeyRecordTypeLibName:
                self.library.name = self.__parse_string__(d)
                continue
            elif t == KeyRecordTypeEndLib:
                break
            elif t == KeyRecordTypeRefLibs:
                print >> stderr, "Warning: REFLIBS is not supported. This will be ignored."
            elif t == KeyRecordTypeFonts:
                print >> stderr, "Warning: FONTS is not supported. This will be ignored."
            elif t == KeyRecordTypeAttrTable:
                print >> stderr, "Warning: ATTRTABLE is not supported. This will be ignored."
            elif t == KeyRecordTypeGenerations:
                print >> stderr, "Warning: GENERATIONS is not supported. This will be ignored."
            else:
                print >> stderr, "Error: Unsupported record type in File:", t
                raise SystemExit
        return self.library

    def __parse_structure__(self):

        while 1:
            r = self.__parse_record__()
            t = r.rtype #type
            d = r.data #data
            if t == KeyRecordTypeBoundary:
                S.add_el(self.__parse_boundary_element__())
            elif t == KeyRecordTypePath:
                S.add_el(self.__parse_path_element__())
            elif t == KeyRecordTypeSRef:
                S.add_el(self.__parse_sref_element__())
            elif t == KeyRecordTypeARef:
                S.add_el(self.__parse_aref_element__())
            elif t == KeyRecordTypeBox:
                S.add_el(self.__parse_box_element__())
            elif t == KeyRecordTypeText:
                S.add_el(self.__parse_label_element__())
            elif t == KeyRecordTypeStrName:
                name = self.make_structure_name(self.__parse_string__(d))
                S = gds_structure(name, [], self.library)
                S.created = created
                S.modified = modified
                S.grid = self.library.grid
                S.unit = self.library.unit
                self.__current_structure__= S
            elif t == KeyRecordTypeCreation:
                created = self.__parse_time__(d)
            elif t == KeyRecordTypeLastMod:
                modified = self.__parse_time__(d)
            elif t == KeyRecordTypeEndStr:
                break
            elif t == KeyRecordTypeStrClass:
                print >> stderr, "Warning: STRCLASS is not supported. This will be ignored"
            else:
                print >> stderr, "Error: Unsupported element type in Structure:", t
                raise SystemExit
        return S


    def __parse_length__(self, s):
        return float(s) * self.scaling

    def __parse_coordinate__(self):
        x = self.__parse_record__()
        if not x.rtype == KeyRecordTypeX:
            print >> stderr, "Error: Invalid x-coordinate Record", x.rtype , "in Key Import"
            raise SystemExit
        y = self.__parse_record__()
        if not y.rtype == KeyRecordTypeY:
            print >> stderr, "Error: Invalid y-coordinate Record", x.rtype , "in Key Import"
            raise SystemExit
        return (self.__parse_length__(x.data), self.__parse_length__(y.data))

    def __parse_record__(self):
        quotes = False
        comment = False
        rec = []
        try:
            s = self.i_stream.read(1)
            while (not s == ";") or (quotes) or (comment):
                if s == "\"":
                    quotes = not quotes
                if s == "#":
                    comment = True
                if s == "\n":
                    comment = False
                if not comment:
                    rec.append(s)
                s = self.i_stream.read(1)
        except:
            print >> stderr, "Error: Could not read KEY record"
            raise SystemExit

        rec = split("".join(rec))
        type = rec[0]
        data = join(rec[1:len(rec)])

        return key_record(type, data)

    def __parse_shape__(self,n_o_points):
        return gds_shape([self.__parse_coordinate__() for i in range(n_o_points)])
    
    def __parse_boundary_element__(self):
        # read parameters
        layer = 0
        datatype = 0
        coords = []
        while 1:
            r = self.__parse_record__()
            t = r.rtype #type
            d = r.data #datalength
            if t == KeyRecordTypeLayer:
                layer = self.map_layer(self.__parse_int__(d))
            elif t == KeyRecordTypeDataType:
                datatype = self.__parse_int__(d)
            elif t == KeyRecordTypeXY:
                nxy = self.__parse_int__(d)
                coords = self.__parse_shape__(nxy)
                if not coords.closed:
                    print >> stderr, "Warning: BOUNDARY Coordinate list not closed in structure " + self.__current_structure__.name 
                coords.close()
            elif t == KeyRecordTypeEndEl:
                break
            elif t == KeyRecordTypeElFlags:
                print >> stderr, "Warning: ELFLAGS in BOUNDARY is not supported. This will be ignored"
            elif t == KeyRecordTypePlex:
                print >> stderr, "Warning: PLEX in BOUNDARY is not supported. This will be ignored"
            else:
                print >> stderr, "Error: Unsupported type in BOUNDARY:", t
                raise SystemExit
        return el_boundary(layer, coords)


    def __parse_path_element__ (self):
        # read parameters
        layer = 0
        datatype = 0
        pathtype = PATH_TYPE_NORMAL
        width = 0
        coords = []
        while 1:
            r = self.__parse_record__()
            t = r.rtype #type
            d = r.data #datalength
            if t == KeyRecordTypeLayer:
                layer = self.map_layer(self.__parse_int__(d))
            elif t == KeyRecordTypeDataType:
                datatype = self.__parse_int__(d)
            elif t == KeyRecordTypePathType:
                pathtype = self.__parse_int__(d)
            elif t == KeyRecordTypeWidth:
                width = self.__parse_length__(d)
            elif t == KeyRecordTypeXY:
                nxy = self.__parse_int__(d)
                coords = self.__parse_shape__(nxy)
            elif t == KeyRecordTypeEndEl:
                break
            elif t == KeyRecordTypeElFlags:
                print >> stderr, "Warning: ELFLAGS in PATH is not supported. This will be ignored."
            elif t == KeyRecordTypePlex:
                print >> stderr, "Warning: PLEX in PATH is not supported. This will be ignored."
            else:
                print >> stderr, "Error: Unsupported type in PATH:", t
                raise SystemExit
        return el_path(layer, coords, width, pathtype)


    def __parse_sref_element__(self):
        name = ""
        coord = (0.0, 0.0)
        transform = gds_no_distort_transform()
        while 1:
            r = self.__parse_record__()
            t = r.rtype #type
            d = r.data #datalength
            if t == KeyRecordTypeSName:
                name = self.__parse_string__(d)
            elif t == KeyRecordTypeXY:
                nxy = self.__parse_int__(d)
                if not nxy == 1:
                    print >> stderr, "Error: SREF only supports a single coordinate."
                    raise SystemExit
                coord = self.__parse_coordinate__()
            elif t == KeyRecordTypeEndEl:
                break
            elif t == KeyRecordTypeElFlags:
                print >> stderr, "Warning: ELFLAGS in SREF is not supported. This will be ignored."
            elif t == KeyRecordTypePlex:
                print >> stderr, "Warning: PLEX in SREF is not supported. This will be ignored."
            elif t == KeyRecordTypeSTrans:
                self.__parse_transformation__(transform, d)

            elif t == KeyRecordTypeMag:
                self.__parse_magnification__(transform, d)
            elif t == KeyRecordTypeAngle:
                self.__parse_rotation__(transform, d)
            else:
                print >> stderr, "Error: Unsupported type in SREF:", t
                raise SystemExit

        if name =="":
            print >> stderr, "Error: SREF: name of structure is empty"
            raise SystemExit
        else:
            name = self.make_structure_name(name)

        if self.library.structure_exists(name):
            S = self.library[name]
        else:
            # add dummy structure (which will be overwritten later)
            S = gds_structure(name, [], self.library)
        V = gds_sref_element(S, coord, transform)
        return V

    def __parse_aref_element__(self):
        name = ""
        coord_zero = (0.0, 0.0)
        coord_x = (0.0, 0.0)
        coord_y = (0.0, 0.0)
        col = 1
        row = 1
        transform = gds_no_distort_transform()
        while 1:
            r = self.__parse_record__(f)
            t = r.rtype #type
            d = r.data #datalength
            if t == KeyRecordTypeColRow:
                col = self.__parse_int__(d)
                row = self.__parse_int__(d)
                if col <= 0 or row <=0:
                    print >> stderr, "Error: Invalid COLROW in AREF"
                    raise SystemExit
            elif t == KeyRecordTypeSName:
                name = self.__parse_string__(d)
            elif t == KeyRecordTypeXY:
                nxy = self.__parse_int__(d)
                if not nxy == 3:
                    print >> stderr, "Error: AREF supports exactly three coordinates."
                    raise SystemExit
                coord_zero = self.__parse_coordinate__()
                coord_x = self.__parse_coordinate__()
                coord_y = self.__parse_coordinate__()
    ##            if not ((coord_x[1]-coord_zero[1])==0 and (coord_y[0]-coord_zero[0])==0) :
    ##                print >> stderr, "Warning: AREF with rotated coordinates is not supported. Structure will not be rotated"
    ##            if (coord_x[0]-coord_zero[0])<0:
    ##                sign_x = -1
    ##            else:
    ##                sign_x = +1
    ##            if (coord_y[1]-coord_zero[1])<0:
    ##                sign_y = -1
    ##            else:
    ##                sign_y = +1
    ##
    ##            x = sign_x * distance(coord_x, coord_zero)/col
    ##            y = sign_y * distance(coord_y, coord_zero)/row
            elif t == KeyRecordTypeEndEl:
                break
            elif t == KeyRecordTypeElFlags:
                print >> stderr, "Warning: ELFLAGS in AREF is not supported. This will be ignored."
            elif t == KeyRecordTypePlex:
                print >> stderr, "Warning: PLEX in AREF is not supported. This will be ignored."
            elif t == KeyRecordTypeSTrans:
                self.__parse_transformation__(transform, d)
            elif t == KeyRecordTypeMag:
                self.__parse_magnification__(transform, d)
            elif t == KeyRecordTypeAngle:
                self.__parse_rotation__(transform, d)
            else:
                print >> stderr, "Error: Unsupported type in AREF:", t
                raise SystemExit

        coordinates = [coord_zero, coord_x, coord_y]
        cc= self.library.snap_shape(transform.reverse(shape_translate (coordinates, (-coord_zero[0], -coord_zero[1]))))
        if (not cc[1][1] == 0.0) or (not cc[2][0] == 0.0):
            print >> stderr, "Error: Coordinates in AREF do not match Transformation STRANS, MAG, ANGLE in structure " + self.__current_structure__

        if name =="":
            print >> stderr, "Error: AREF: name of structure is empty"
            raise SystemExit
        else:
            name = self.make_structure_name(name)

        if self.library.structure_exists(name):
            S = self.library[name]
        else:
            # add dummy structure (which will be overwritten later)
            S = gds_structure(name, [], self.library)
        # try to fix arefs with negative period
        czx = coord_zero[0]
        px = cc[1][0]
        py = cc[2][1]
        if px < 0:
            px *= -1
            czx -= px
        czy = coord_zero[1]
        if py < 0:
            py *= -1
            czy -= py
        coord_zero = (czx, czy)
        period = (px/col, py/row)
            
        V = gds_aref_element(S, origin, period, (col, row), transform)
        return V

    def __parse_box_element__(self):
        # read parameters
        layer = 0
        boxtype = 0
        coords = []
        while 1:
            r = self.__parse_record__(f)
            t = r.rtype #type
            d = r.data #datalength

            if t == KeyRecordTypeLayer:
                layer = self.map_layer(self.__parse_int__(d))
            elif t == KeyRecordTypeBoxType:
                boxtype = self.__parse_int__(d)
            elif t == KeyRecordTypeXY:
                nxy = self.__parse_int__(d)
                coords = self.__parse_shape__( nxy)
            elif t == KeyRecordTypeEndEl:
                break
            elif t == KeyRecordTypeElFlags:
                print >> stderr, "Warning: ELFLAGS in BOX is not supported. This will be ignored"
            elif t == KeyRecordTypePlex:
                print >> stderr, "Warning: PLEX in BOX is not supported. This will be ignored"
            else:
                print >> stderr, "Error: Unsupported type in BOX:", t
                raise SystemExit
        c = coords[0]
        xmin = c[0]
        ymin = c[1]
        xmax = c[0]
        ymax = c[1]
        for c in coords:
            xmin = min(xmin, c[0])
            ymin = min(ymin, c[1])
            xmax = max(xmax, c[0])
            ymax = max(ymax, c[1])
        return gds_box_element(layer, (0.5*(xmin+xmax), 0.5*(ymin+ymax)), (xmax-xmin, ymax-ymin))

    def __parse_label_element__(self):
        # read parameters
        transform = gds_no_distort_transform()
        layer = 0
        texttype = 0
        font = TEXT_FONT_DEFAULT
        ver_alignment = TEXT_ALIGN_TOP
        hor_alignment = TEXT_ALIGN_LEFT
        text = ""
        width = 1.0
        coords = []
        while 1:
            r = self.__parse_record__(f)
            t = r.rtype #type
            d = d.data #datalength
            if t == KeyRecordTypeLayer:
                layer = self.map_layer(self.__parse_int__(d))
            elif t == KeyRecordTypeTextType:
                datatype = self.__parse_int__(d)
            elif t == KeyRecordTypePathType:
                pathtype = self.__parse_int__(d)
            elif t == KeyRecordTypePresentation:
                presentation = split(d, ",")
                hor_alignment = self.__parse_int__(presentation[0])
                ver_alignment = self.__parse_int__(presentation[1])
                font = import_key_make_int(self.__parse_int__(presentation[2]))
            elif t == KeyRecordTypeWidth:
                width = self.__parse_length__(d)
            elif t == KeyRecordTypeXY:
                nxy = self.__parse_int__(d)
                if not nxy == 1:
                    print >> stderr, "Error: TEXT (Label) only supports a single coordinate. "
                    raise SystemExit
                coord = self.__parse_coordinate__()
            elif t == KeyRecordTypeString:
                text = self.__parse_string__(d)
            elif t == KeyRecordTypeEndEl:
                break
            elif t == KeyRecordTypeElFlags:
                print >> stderr, "Warning: ELFLAGS in TEXT (Label) is not supported. This will be ignored."
            elif t == KeyRecordTypePlex:
                print >> stderr, "Warning: PLEX in TEXT (Label) is not supported. This will be ignored."
            elif t == KeyRecordTypeSTrans:
                self.__parse_transformation__(transform, d)
            elif t == KeyRecordTypeMag:
                self.__parse_magnification__(transform, d)
            elif t == KeyRecordTypeAngle:
                self.__parse_rotation__(transform, d)
            else:
                print >> stderr, "Error: Unsupported type in TEXT (label):", t
                raise SystemExit
        return gds_label_element (layer, text, coord, (hor_alignment, ver_alignment) , font, 1.0, transform)

    def __parse_magnification__(self, T, data):
        m = self.__parse_float__(data)
        T.magnification = m

    def __parse_rotation__ (self, T, data):
        T.rotation = self.__parse_float__(data)
        
    def __parse_transformation__(self, T, data):
        d = split(data, ",")
        T.v_mirror = self.__parse_int__(d[0]) == 1
        T.absolute_magnification = (self.parse_int__(d[1]) == 1)
        T.absolute_rotation = (self.__parse_int__(d[2]) == 1)
        return 

    def __parse_int__(self, data):
        try:
            return int(data)
        except:
            print >> stderr, "Error: Could not read INT"
            raise SystemError

    def __parse_float__(self, data):
        try:
            return float(data)
        except:
            print >> stderr, "Error: Could not read FLOAT"
            raise SystemError

    def __parse_string__(self, data):
        return strip(data,"\"")

    def __parse_time__(self, data):
        data = data.strip("{}")
        data = data.replace(":", " ")
        data = data.replace("-", " ")
        dt = split(data)
        year = self.__parse_int__(dt[0])
        month= self.__parse_int__(dt[1])
        day= self.__parse_int__(dt[2])
        hour= self.__parse_int__(dt[3])
        minute= self.__parse_int__(dt[4])
        second= self.__parse_int__(dt[5])
        return mktime((year, month, day, hour, minute, second, 0, 0, -1))
