#!/usr/bin/env python3
###########################################################################
#
# xasyFile implements the loading, parsing, and saving of an asy file.
#
#
# Author: Orest Shardt
# Created: June 29, 2007
#
############################################################################

import xasy2asy as xasy2asy
import io
import re


class xasyParseError(Exception):
    """A parsing error"""
    pass


class xasyFileError(Exception):
    """An i/o error or other error not related to parsing"""
    pass


def extractTransform(line):
    """Returns key and the new transform."""
    # see https://regex101.com/r/6DqkRJ/4 for info
    mapString = xasy2asy.xasyItem.mapString
    testMatch = re.match(
        r'^{0:s}\s*\(\s*\"([^\"]+)\"\s*,\s*\(([-\d, .]+)\)\s*\)'.format(mapString), line.strip())
    if testMatch is None:
        mapOnlyMatch = re.match(r'^{0:s}\s*\(\s*\"([^\"]+)\"\s*\)'.format(mapString), line.strip())
        if mapOnlyMatch is None:
            return None
        else:
            key = mapOnlyMatch.group(1)
            return key, xasy2asy.identity()
    else:
        key = testMatch.group(1)
        rawStr = testMatch.group(2)
        rawStrArray = rawStr.split(',')

        if len(rawStrArray) != 6:
            return None
        transf = [float(val.strip()) for val in rawStrArray]
        return key, xasy2asy.asyTransform(transf)


def extractTransformsFromFile(fileStr):
    transfDict = {}
    with io.StringIO() as rawCode:
        for line in fileStr.splitlines():
            test_transf = extractTransform(line.rstrip())
            if test_transf is None:
                rawCode.write(line + '\n')
            else:
                key, transf = test_transf
                if key not in transfDict.keys():
                    transfDict[key] = []
                transfDict[key].append(transf)
        final_str = rawCode.getvalue()
    return final_str, transfDict

def xasy2asyCode(xasyItems, asy2psmap):
    with io.StringIO() as asyCode:
        for item in xasyItems:
            asyCode.write(item.getTransformCode(asy2psmap))
        for item in xasyItems:
            asyCode.write(item.getObjectCode(asy2psmap))

        asyCode.write(
            'size('+str(asy2psmap*xasy2asy.yflip())+'); ' +
            xasy2asy.xasyItem.resizeComment +
            '\n'
        )
        return asyCode.getvalue()

def saveFile(file, xasyItems, asy2psmap):
    """Write a list of xasyItems to a file"""
    file.write(xasy2asyCode(xasyItems, asy2psmap))

def xasyToDict(file, xasyItems, asy2psmap):
    fileItems = []
    asyItems = []
    for item in xasyItems:
        if isinstance(item, xasy2asy.xasyScript):
            # reusing xasyFile code for objects
            # imported from asy script.
            asyItems.append({'item':item, 'type': 'xasyScript'})

        elif isinstance(item, xasy2asy.xasyText):
            # At the moment xasyText cannot be edited
            # so we treat it the same as xasyScript
            penData = {'color': item.pen.color, 'width': item.pen.width, 'options': item.pen.options}
            fileItems.append({'type': 'xasyText',
                    'align': item.label.align,
                    'location': item.label.location,
                    'fontSize': item.label.fontSize,
                    'text': item.label.text,
                    'transform': item.transfKeymap[item.transfKey][0].t,
                    'transfKey': item.transfKey,
                    'pen': penData
                    })

        elif isinstance(item, xasy2asy.xasyShape):
            penData = {'color': item.pen.color, 'width': item.pen.width, 'dashPattern': item.pen.dashPattern, 'options': item.pen.options}
            fileItems.append({'type': 'xasyShape',
                    'nodes': item.path.nodeSet,
                    'links': item.path.linkSet,
                    'fill': item.path.fill,
                    'transform': item.transfKeymap[item.transfKey][0].t,
                    'transfKey': item.transfKey,
                    'pen': penData
                    })

        elif isinstance(item, xasy2asy.asyArrow): #Will this ever even be reached?
            penData = {'color': item.pen.color, 'width': item.pen.width, 'dashPattern': item.pen.dashPattern, 'options': item.pen.options}
            fileItems.append({'type': 'asyArrow',
                    'pen': penData,
                    'arrowSettings': item.arrowSettings,
                    'transform': item.transfKeymap[item.transfKey][0].t,
                    'transfKey': item.transfKey,
                    'settings': item.arrowSettings,
                    'code': item.code
                    })

    return {'objects': fileItems, 'asy2psmap': asy2psmap.t}, asyItems
