#!/usr/bin/env python2
# coding=utf-8
'''
Copyright (C) 2013 Sebastian Wüst, sebi@timewaster.de

This program 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 2 of the License, or
(at your option) any later version.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
'''

# standard libraries
import math
from StringIO import StringIO
# local library
import inkex


class hpglDecoder:

    def __init__(self, hpglString, options):
        ''' options:
                "resolutionX":float
                "resolutionY":float
                "showMovements":bool
                "docWidth":float
                "docHeight":float
        '''
        self.hpglString = hpglString
        self.options = options
        self.scaleX = options.resolutionX / 25.4 # dots/inch to dots/mm
        self.scaleY = options.resolutionY / 25.4 # dots/inch to dots/mm
        self.warning = ''
        self.textMovements = _("Movements")
        self.textPenNumber = _("Pen #")

    def getSvg(self):
        # prepare document
        self.doc = inkex.etree.parse(StringIO('<svg xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="%smm" height="%smm" viewBox="0 0 %s %s"></svg>' %
            (self.options.docWidth, self.options.docHeight, self.options.docWidth, self.options.docHeight)))
        inkex.etree.SubElement(self.doc.getroot(), inkex.addNS('namedview', 'sodipodi'), {inkex.addNS('document-units', 'inkscape'): 'mm'})
        actualLayer = 0
        self.layers = {}
        if self.options.showMovements:
            self.layers[0] = inkex.etree.SubElement(self.doc.getroot(), 'g', {inkex.addNS('groupmode', 'inkscape'): 'layer', inkex.addNS('label', 'inkscape'): self.textMovements, 'id': self.textMovements})
        # parse paths
        hpglData = self.hpglString.split(';')
        if len(hpglData) < 3:
            raise Exception('NO_HPGL_DATA')
        oldCoordinates = (0.0, self.options.docHeight)
        path = ''
        for i, command in enumerate(hpglData):
            if command.strip() != '':
                if command[:2] == 'IN' or command[:2] == 'FS' or command[:2] == 'VS':
                    # if Initialize, force or speed command, ignore
                    pass
                elif command[:2] == 'SP':
                    # if Select Pen command
                    actualLayer = command[2:]
                    self.createLayer(actualLayer)
                elif command[:2] == 'PU':
                    # if Pen Up command
                    if ' L ' in path:
                        self.addPathToLayer(path, actualLayer)
                    if self.options.showMovements and oldCoordinates != self.getParameters(command[2:]):
                        path = 'M %f,%f' % oldCoordinates
                        path += ' L %f,%f' % self.getParameters(command[2:])
                        self.addPathToLayer(path, 0)
                    path = 'M %f,%f' % self.getParameters(command[2:])
                    oldCoordinates = self.getParameters(command[2:])
                elif command[:2] == 'PD':
                    # if Pen Down command
                    parameterString = command[2:]
                    if parameterString.strip() != '':
                        parameterString = parameterString.replace(';', '').strip()
                        parameter = parameterString.split(',')
                        for i, param in enumerate(parameter):
                            if i % 2 == 0:
                                parameter[i] = str(float(param) / self.scaleX)
                            else:
                                parameter[i] = str(self.options.docHeight - (float(param) / self.scaleY))
                        parameterString = ','.join(parameter)
                        path += ' L %s' % parameterString
                        oldCoordinates = (float(parameter[-2]), float(parameter[-1]))
                else:
                    self.warning = 'UNKNOWN_COMMANDS'
        if ' L ' in path:
            self.addPathToLayer(path, actualLayer)
        return (self.doc, self.warning)

    def createLayer(self, layerNumber):
        try:
            self.layers[layerNumber]
        except KeyError:
            self.layers[layerNumber] = inkex.etree.SubElement(self.doc.getroot(), 'g',
                {inkex.addNS('groupmode', 'inkscape'): 'layer', inkex.addNS('label', 'inkscape'): self.textPenNumber + layerNumber, 'id': self.textPenNumber + layerNumber})

    def addPathToLayer(self, path, layerNumber):
        lineColor = '000000'
        if layerNumber == 0:
            lineColor = 'ff0000'
        inkex.etree.SubElement(self.layers[layerNumber], 'path', {'d': path, 'style': 'stroke:#' + lineColor + '; stroke-width:0.4; fill:none;'})

    def getParameters(self, parameterString):
        # process coordinates
        if parameterString.strip() == '':
            parameterString = '0,0;'
        # remove command delimiter
        parameterString = parameterString.replace(';', '').strip()
        # split parameter
        parameter = parameterString.split(',')
        # convert to svg coordinate system and return
        return (float(parameter[0]) / self.scaleX, self.options.docHeight - (float(parameter[1]) / self.scaleY))

# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99