from fontTools.misc import sstruct
from fontTools.misc.textTools import tobytes, tostr, safeEval
from . import DefaultTable

GMAPFormat = """
		>	# big endian
		tableVersionMajor:	H
		tableVersionMinor: 	H
		flags:	H
		recordsCount:		H
		recordsOffset:		H
		fontNameLength:		H
"""
# psFontName is a byte string which follows the record above. This is zero padded
# to the beginning of the records array. The recordsOffsst is 32 bit aligned.

GMAPRecordFormat1 = """
		>	# big endian
		UV:			L
		cid:		H
		gid:		H
		ggid:		H
		name:		32s
"""


class GMAPRecord(object):
    def __init__(self, uv=0, cid=0, gid=0, ggid=0, name=""):
        self.UV = uv
        self.cid = cid
        self.gid = gid
        self.ggid = ggid
        self.name = name

    def toXML(self, writer, ttFont):
        writer.begintag("GMAPRecord")
        writer.newline()
        writer.simpletag("UV", value=self.UV)
        writer.newline()
        writer.simpletag("cid", value=self.cid)
        writer.newline()
        writer.simpletag("gid", value=self.gid)
        writer.newline()
        writer.simpletag("glyphletGid", value=self.gid)
        writer.newline()
        writer.simpletag("GlyphletName", value=self.name)
        writer.newline()
        writer.endtag("GMAPRecord")
        writer.newline()

    def fromXML(self, name, attrs, content, ttFont):
        value = attrs["value"]
        if name == "GlyphletName":
            self.name = value
        else:
            setattr(self, name, safeEval(value))

    def compile(self, ttFont):
        if self.UV is None:
            self.UV = 0
        nameLen = len(self.name)
        if nameLen < 32:
            self.name = self.name + "\0" * (32 - nameLen)
        data = sstruct.pack(GMAPRecordFormat1, self)
        return data

    def __repr__(self):
        return (
            "GMAPRecord[ UV: "
            + str(self.UV)
            + ", cid: "
            + str(self.cid)
            + ", gid: "
            + str(self.gid)
            + ", ggid: "
            + str(self.ggid)
            + ", Glyphlet Name: "
            + str(self.name)
            + " ]"
        )


class table_G_M_A_P_(DefaultTable.DefaultTable):
    dependencies = []

    def decompile(self, data, ttFont):
        dummy, newData = sstruct.unpack2(GMAPFormat, data, self)
        self.psFontName = tostr(newData[: self.fontNameLength])
        assert (
            self.recordsOffset % 4
        ) == 0, "GMAP error: recordsOffset is not 32 bit aligned."
        newData = data[self.recordsOffset :]
        self.gmapRecords = []
        for i in range(self.recordsCount):
            gmapRecord, newData = sstruct.unpack2(
                GMAPRecordFormat1, newData, GMAPRecord()
            )
            gmapRecord.name = gmapRecord.name.strip("\0")
            self.gmapRecords.append(gmapRecord)

    def compile(self, ttFont):
        self.recordsCount = len(self.gmapRecords)
        self.fontNameLength = len(self.psFontName)
        self.recordsOffset = 4 * (((self.fontNameLength + 12) + 3) // 4)
        data = sstruct.pack(GMAPFormat, self)
        data = data + tobytes(self.psFontName)
        data = data + b"\0" * (self.recordsOffset - len(data))
        for record in self.gmapRecords:
            data = data + record.compile(ttFont)
        return data

    def toXML(self, writer, ttFont):
        writer.comment("Most of this table will be recalculated by the compiler")
        writer.newline()
        formatstring, names, fixes = sstruct.getformat(GMAPFormat)
        for name in names:
            value = getattr(self, name)
            writer.simpletag(name, value=value)
            writer.newline()
        writer.simpletag("PSFontName", value=self.psFontName)
        writer.newline()
        for gmapRecord in self.gmapRecords:
            gmapRecord.toXML(writer, ttFont)

    def fromXML(self, name, attrs, content, ttFont):
        if name == "GMAPRecord":
            if not hasattr(self, "gmapRecords"):
                self.gmapRecords = []
            gmapRecord = GMAPRecord()
            self.gmapRecords.append(gmapRecord)
            for element in content:
                if isinstance(element, str):
                    continue
                name, attrs, content = element
                gmapRecord.fromXML(name, attrs, content, ttFont)
        else:
            value = attrs["value"]
            if name == "PSFontName":
                self.psFontName = value
            else:
                setattr(self, name, safeEval(value))
