# -*- coding: utf-8 -*-
# glal.py
"""This module provides a graphic library abstraction layer for Cyclograph"""

# Copyright (C) 2008-2015 Federico Brega, Pierluigi Villani

# 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 3
# 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.

from __future__ import print_function, unicode_literals

import sys
import glal_selected
LIBRARY = glal_selected.library
(FD_OPEN, FD_SAVE) = range(2)


def Message(*args):
    """This funcion return the class that wraps the using messaging library"""
    if LIBRARY == 'cli':
        return Message_cli(*args)


def DeviceContext(*args):
    if LIBRARY == 'cli':
        return DeviceContext_cli(*args)


def Image(*args):
    if LIBRARY == 'cli':
        return Image_cli(*args)


def addstatusbartext(maingui, text):
    """Add text to main gui status bar"""
    if LIBRARY == 'cli':
        sys.stderr.write(text)


def FileDialog(parent, title, dirname, other, file_types, rw, filename=None):
    """Return File dialog """
    return gui.FileDialog(parent, title, dirname, filename, other,
                               file_types, rw, FD_OPEN, FD_SAVE)

# Begin of cli classes ###


class Message_cli():
    """CLI interfaces doesn't need to update their view
    because they haven't got any
    """
    def send(self, *args):
        """ send method not used for cli"""
        pass

    def subscribe(self, *args):
        """ subscribe method not used for cli"""
        pass


def DeviceContext_cli(*args):
    """ Get a device contex for CLI default is an svg generator."""
    return DeviceContext_svg(*args)


class Image_cli():
    """ Image cli not used"""
    pass
# End of cli classes ###


# Begin of SVG ###
class DeviceContext_svg():
    """Device Context class to draw sgv files"""
    colors = {'white': '#ffffff',
              'black': '#000000'}

    def setcolor(self, color):
        """ Set color converting to svg compatible format."""
        if type(color) == type(str()):
            if color.startswith('#'):
                return color
            elif color.startswith('rgb'):
                tuple_ = [int(x) for x in color[4:-1].split(',')]
                return tupletocss(tuple_)
            else:
                return self.colors[color]
        else:
            sys.stderr.write("Color type unknown: "+color+" "+str(type(color))+"\n")
            return False

    def init_draw_surf(self, size, p3d):
        """ Init draw surface"""
        self.size_x = size[0]
        self.size_y = size[1]
        self.pencolor = None
        self.lineargcount = 0
        self.pensize = 0
        self.pshear = p3d
        self.svg = '''<?xml version="1.0" standalone="no"?>
<!-- Created with CycloGraph (http://cyclograph.sourceforge.net) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="%d" height="%d" version="1.1"
xmlns="http://www.w3.org/2000/svg">\n
''' % size
        if p3d:
            self.brushcolor = '#ffffff'  # white background
            self.svg += '''<rect x="0" y="0" width="%i" height="%i" fill=" %s"/>
''' % (self.size_x, self.size_y, self.brushcolor)

    def shear(self, shear):
        if shear != 0:
            self.pshear = True
            self.svg += '<g transform="skewY(%f)">' % (shear*50,)
        else:
            self.pshear = False

    def getsize(self):
        """ Return size"""
        return (self.size_x, self.size_y)

    def gradfill(self, rect, startcolor, endcolor):
        """ Fill gradient"""
        self.svg += '''
<defs>
<linearGradient id="background" x1="0%%" y1="0%%" x2="0%%" y2="100%%">
<stop offset="0%%" style="stop-color:%s;stop-opacity:1;"/>
<stop offset="80%%" style="stop-color:%s;stop-opacity:1;"/>
</linearGradient>
</defs>
<rect width="%d" height="%d" style="fill:url(#background)"/>
''' % (self.setcolor(startcolor), self.setcolor(endcolor),
        rect[2] - rect[0], rect[3] - rect[1])

    def setpen(self, color, size):
        """ Set pen's size and color"""
        self.pencolor = self.setcolor(color)
        self.pensize = str(size)

    def setfont(self, fontdict):
        """ Set font"""
        self.dim = fontdict['dim']
        self.font = "font-family:%s;font-size:%spx" % (fontdict['des'], self.dim)

    def drawtext(self, text, pos_x, pos_y):
        """ Draw text at position pos_x,pos_y """
        self.drawrotatedtext(text, pos_x, pos_y, 0)

    def gettextwidth(self, text):
        """ Return text length"""
        return self.dim*len(text)-30  # TODO: check if there is a more accurate method

    def gettextheight(self, text):
        """ Return text height"""
        return self.dim  # TODO: check if there is a more accurate method

    def drawline(self, pos_x0, pos_y0, pos_x1, pos_y1):
        """ draw line"""
        self.svg += '''<line x1="%d" y1="%d" x2="%d" y2="%d"
style="stroke:%s;stroke-width:%s"/>
''' % (pos_x0, pos_y0, pos_x1, pos_y1, self.pencolor, self.pensize)

    def setlineargradientbrush(self, colorlist, startp, endp):
        """ Get a linear gradient from startp to endp, using colors in colorlist.
        The elments of colorlist are tuple in the format (color, realtive position)."""
        self.svg += '''<defs>
<linearGradient id="linearg%s" gradientUnits="userSpaceOnUse" x1="%s" y1="%s" x2="%s" y2="%s">
''' % (self.lineargcount, startp[0], startp[1], endp[0], endp[1])
        for color in colorlist:
            self.svg += '''<stop offset="%s%%" style="stop-color:%s;stop-opacity:1;"/>
''' % (color[1]*100, self.setcolor(color[0]))
        self.svg += '''</linearGradient>
</defs>
'''
        self.brushcolor = "url(#linearg%s)" % (self.lineargcount)
        self.lineargcount = self.lineargcount + 1

    def setbrush(self, color):
        """ Set brush color"""
        self.brushcolor = self.setcolor(color)

    def drawrectangle(self, pos_x0, pos_y0, width, height):
        """ Draw rectangle"""
        self.svg += '''<rect x="%i" y="%i" width="%i" height="%i"
style="fill: %s;stroke:%s;stroke-width:%s"/>
''' % (pos_x0, pos_y0, width, height, self.brushcolor,
       self.pencolor, self.pensize)

    def drawrotatedtext(self, text, pos_x, pos_y, angle):
        """Draw the text given, rotated by the angle."""
        dy = self.dim
        self.svg += '<text x="%i" y="%i" style="%s;fill:%s"' % (pos_x, pos_y+dy, self.font, self.pencolor)
        if angle:
            self.svg += ' transform="rotate(%d,%d,%d)"' % (-angle, pos_x, pos_y)
        self.svg += '''>%s</text>
''' % (text)

    def drawpolygon(self, sequence):
        """ Draw polygon"""
        if len(sequence) < 2:
            return
        self.svg += '<polygon points="'
        for pt in sequence:
            self.svg += '%d, %d ' % (pt[0], pt[1])
        self.svg += '"\n style="fill:%s;stroke:%s;stroke-width:%s"/>\n' \
                % (self.brushcolor, self.pencolor, self.pensize)

    def startpath(self, point):
        """ Start a path in the specified point,"""
        self.svg += '''<path style="fill:%s;stroke:%s;stroke-width:%s;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M %d,%d''' % (self.brushcolor, self.pencolor, self.pensize, point[0], point[1])
        self.path = point
        return self.path

    def drawpathlineto(self, path, point):
        """ Draw a straight line from the last point to the given point."""
        self.svg += ''' L %d,%d''' % (point[0], point[1])
        self.path = point

    def drawpathcubicto(self, path, controlpoints):
        """ Draw a cubic Beziér frome the last point using the given list of
        three control points."""
        self.svg += ''' C %d,%d %d,%d %d,%d''' % (controlpoints[0][0], controlpoints[0][1],
        controlpoints[1][0], controlpoints[1][1],
        controlpoints[2][0], controlpoints[2][1])
        self.path = controlpoints[2]

    def endpath(self, path):
        """ Show the path."""
        self.svg += '"/>\n'

    def end_draw(self):
        """ end drawing"""
        if self.pshear:
            self.svg += '</g>'
        self.svg += "</svg>\n"
        print(self.svg)


class Image_svg():
    """ svg image"""
    def __init__(self, size_x,  size_y, plotfnct):
        self.size = (size_x,  size_y)
        self.plotfnct = plotfnct
        self.svg = ""

    def plot(self, settings):
        """draw svg image"""
        dcwrpp = DeviceContext_svg()
        dcwrpp.init_draw_surf(self.size, settings['3d'])
        self.plotfnct(settings, dcwrpp)
        # dcwrpp.end_draw()
        self.svg = dcwrpp.svg
        if settings['3d']:
            self.svg += "</g>\n"
        self.svg += "</svg>\n"

    def savetofile(self, path, format):
        """ Save to file"""
        if format == 'svg':
            try:
                fid = open(path, 'w')
                fid.write(self.svg)
            finally:
                fid.close()


def tupletocss(tuple_):
    """ convert tuple to css"""
    numb = tuple_[0] << 16 | tuple_[1] << 8 | tuple_[2]
    return '#' + hex(numb).split('x')[1].zfill(6)
# End of SVG ###

if LIBRARY == 'qt':
    from qt.glal import *

elif LIBRARY == 'gtk3':
    from gtk3.glal import *

elif LIBRARY == 'cli':
    pass
