# -*- coding: utf-8 -*-
# themes.py
"""This module provides a graphic theme for plotting"""

# Copyright (C) 2010-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.


class ThemeManager:
    def getthemeslist(self):
        """Return names associated with classes subclassing Theme."""
        return sorted(Theme.themes.keys())

    def gettheme(self, name):
        """Return reference to the given class name."""
        if name in Theme.themes:
            return Theme.themes[name]
        return None


class ThemeMount(type):  # from http://martyalchin.com/2008/jan/10/simple-plugin-framework/
    def __init__(cls, name, bases, attrs):
        if not hasattr(cls, 'themes'):
            # This branch only executes when processing the mount point itself.
            # So, since this is a new plugin type, not an implementation, this
            # class shouldn't be registered as a plugin. Instead, it sets up a
            # list where plugins can be registered later.
            cls.themes = {}
        else:
            # This must be a plugin implementation, which should be registered.
            # Simply appending it to the list is all that's needed to keep
            # track of it later.
            # if cls.themename in cls.themes:
                # TODO: if user can create/install themes warn if a name is
                # used by more than one theme
                # return
            cls.themes[cls.themename] = cls


class Theme(metaclass=ThemeMount):
    """Model of a theme: every theme must subclass this class."""
    themename = ""
    shear = -0.15

    @staticmethod
    def getcolor(colors, levels, grad):
        """Return gradient relative color"""
        pass

    @staticmethod
    def drawslopeinfo(devc, info, settings, startx, starty):
        """Draw slope's name and other info background"""
        pass

    @staticmethod
    def drawlegend(devc, settings, startx, starty, title):
        """Draw slope's legend"""
        pass

    @staticmethod
    def paintbackground(devc, width, height):
        """Draw background"""
        pass

    @staticmethod
    def gradback(devc, width, height, setting_f, startcol="rgb(64, 185, 255)", endcol='white'):
        """Draw a gradient background"""
        pass

    @staticmethod
    def olines(devc, slope, margins, width, height, metersize):
        """Draw altitude line"""
        pass

    @staticmethod
    def alttext(devc, slope, margins, max_y, metersize):
        """draw altitude text aside"""
        pass

    @staticmethod
    def yaxis(devc, slope, margins, max_y, metersize):
        """Draw y axis"""
        pass

    @staticmethod
    def xaxis(devc, slope, margins, max_y, d_incr, kmsize, dx, dy):
        """Draw km bar"""
        pass

    @staticmethod
    def fillhslopecontour(devc, spath_back, dx, dy, colorlist):
        """ Draw horizontal contour."""
        pass

    @staticmethod
    def fillhpoly(devc, points, color):
        """fill horizontal polygons of the 3d slope"""
        pass

    @staticmethod
    def fillfirsthpoly(devc, points, color):
        """fill first horizontal polygon of the 3d slope"""

    @staticmethod
    def fillvslopecontour(devc, path_points, pixel_0m, pixel_1000m, vpolygons, colorlist):
        """Draw a close smooth path thant contais the whole slope."""
        pass

    @staticmethod
    def fillvpoly(devc, points, color):
        """fill vertical polygons (2d and 3d) of the slope"""
        pass

    @staticmethod
    def desctext(devc, text, pos_x, pos_y, font):
        """Draw description text for every cp"""
        pass

    @staticmethod
    def gradtext(devc, text, pos_x, pos_y, font):
        """Draw gradient text for every cp"""
        pass


class ThemeClassic(Theme):
    """Classic CycloGraph theme"""
    themename = "Classic"
    shear = -0.15

    @staticmethod
    def getcolor(colors, levels, grad):
        """Return gradient relative color"""
        gradient = abs(grad)
        for i in range(len(levels)):
            if gradient < levels[i]:
                return colors[i-1]
        return colors[i]

    @staticmethod
    def drawslopeinfo(devc, info, settings, startx, starty):
        """Draw slope's name and other info background"""
        name, avp, maxp, eleg, heightg = info
        devc.setfont(settings['ftitle'])
        devc.drawtext(name, startx, starty)
        if settings['sinfo']:
            devc.setfont(settings['fdesc'])
            devc.drawtext(avp, startx+10, starty+20)
            devc.drawtext(maxp, startx+10, starty+40)
            devc.drawtext(eleg, startx+10, starty+60)
            devc.drawtext(heightg, startx+10, starty+80)

    @staticmethod
    def drawlegend(devc, settings, startx, starty, title):
        """Draw slope's legend"""
        devc.setbrush("rgb(236, 236, 236)")
        rec = (startx, starty, 310, 52)
        devc.drawrectangle(*rec)
        devc.setfont(settings['fdesc'])
        devc.setpen('black', 2)
        devc.drawtext(title, startx+130, starty+2)
        incr = 43
        devc.setpen('black', 1)
        for i in range(len(settings['colors'])):
            devc.setbrush(settings['colors'][i])
            rec = (startx+8+i*incr, starty+20, 36, 10)
            devc.drawrectangle(*rec)
            alti_t = (">%d%%" % (settings['levels'][i]))
            devc.drawtext(alti_t, startx+9+i*incr, starty+34)

    @staticmethod
    def paintbackground(devc, width, height):
        """Draw backgroundr"""
        devc.setbrush("rgb(255, 255, 255)")
        rec = (0, 0, width, height)
        devc.drawrectangle(*rec)

    @staticmethod
    def gradback(devc, width, height, setting_f, startcol="rgb(64, 185, 255)", endcol='white'):
        """Draw a gradient background"""
        area = (0, 0, width, height)
        devc.gradfill(area, startcol, endcol)
        devc.setpen('black', 1)
        devc.setfont(setting_f)

    @staticmethod
    def olines(devc, slope, margins, width, height, metersize):
        """Draw altitude line"""
        devc.setpen("rgb(150, 150, 150)", 1)
        (updownmar, leftrightmar) = margins
        (lef_mar, rig_mar) = leftrightmar
        (upp_mar, low_mar) = updownmar
        x0_alt_bar = lef_mar - 3
        x1_alt_bar = width - rig_mar - 3
        y_alt_base_bar = height - low_mar
        for i in range(int(slope.min_h / slope.h_incr),
                       int((slope.max_h / slope.h_incr) + 1)):
            yincr = int((i * slope.h_incr - slope.min_h) * metersize)
            devc.drawline(x0_alt_bar, y_alt_base_bar - yincr,
                          x1_alt_bar, y_alt_base_bar - yincr)

    @staticmethod
    def alttext(devc, slope, margins, max_y, metersize):
        """draw altitude text aside"""
        (updownmar, leftrightmar) = margins
        (lef_mar, rig_mar) = leftrightmar
        (upp_mar, low_mar) = updownmar

        devc.setpen('black', 2)
        x_alt_txt = lef_mar - 40
        y_alt_base_txt = max_y - low_mar - 8
        for i in range(int(slope.min_h/slope.h_incr), int((slope.max_h/slope.h_incr) + 1)):
            yincr = int((i * slope.h_incr - slope.min_h) * metersize)
            alti_t = ("%4d" % (i*slope.h_incr))
            devc.drawtext(alti_t, x_alt_txt, y_alt_base_txt - yincr)

    @staticmethod
    def yaxis(devc, slope, margins, max_y, metersize):
        """Draw y axis"""
        (updownmar, leftrightmar) = margins
        (lef_mar, rig_mar) = leftrightmar
        (upp_mar, low_mar) = updownmar
        linesnum = int(slope.max_h / slope.h_incr)
        devc.drawline(lef_mar,  max_y - low_mar + 4,
                      lef_mar,  max_y - low_mar - 8 \
                      - int(linesnum * slope.h_incr - slope.min_h) * metersize)

    @staticmethod
    def xaxis(devc, slope, margins, max_y, d_incr, kmsize, dx, dy):
        """Draw km bar"""
        (updownmar, leftrightmar) = margins
        (lef_mar, rig_mar) = leftrightmar
        (upp_mar, low_mar) = updownmar
        for i in range(int(int(slope.max_d) / d_incr - int(slope.min_d) / d_incr + 1)):
            if i % 2 == 0:
                devc.setbrush("rgb(0, 0, 0)")
            else:
                devc.setbrush("rgb(255, 255, 255)")
            rec = (i * d_incr * kmsize + lef_mar + dx,
                   max_y - low_mar + dy, d_incr * kmsize + 1, 5)
            devc.drawrectangle(*rec)
            d_label = ("%d" % (i * d_incr + int(slope.min_d)))
            devc.drawtext(d_label, rec[0], rec[1] + 5)

    @staticmethod
    def fillhpoly(devc, points, color):
        """fill horizontal polygons of the 3d slope"""
        devc.setbrush(color)
        devc.drawpolygon(points)

    @staticmethod
    def fillfirsthpoly(devc, points, color):
        """fill first horizontal polygon of the 3d slope"""
        devc.setbrush(color)
        devc.drawpolygon(points)

    @staticmethod
    def fillvpoly(devc, points, color):
        """fill vertical polygons (2d and 3d) of the slope"""
        devc.setbrush(color)
        devc.drawpolygon(points)

    @staticmethod
    def desctext(devc, text, pos_x, pos_y, font):
        """Draw description text for every cp"""
        devc.setfont(font)
        devc.drawrotatedtext(text, pos_x, pos_y, 90)

    @staticmethod
    def gradtext(devc, text, pos_x, pos_y, font):
        """Draw gradient text for every cp"""
        devc.setfont(font)
        devc.drawtext(text, pos_x, pos_y)


class ThemeBclassic(Theme):
    """Bezier classic CycloGraph theme"""
    themename = "Smooth classic"
    shear = -0.15

    @staticmethod
    def getcolor(colors, levels, grad):
        """Return gradient relative color"""
        gradient = abs(grad)
        for i in range(len(levels)):
            if gradient < levels[i]:
                return colors[i-1]
        return colors[i]

    @staticmethod
    def drawslopeinfo(devc, info, settings, startx, starty):
        """Draw slope's name and other info background"""
        ThemeClassic.drawslopeinfo(devc, info, settings, startx, starty)

    @staticmethod
    def drawlegend(devc, settings, startx, starty, title):
        """Draw slope's legend"""
        ThemeClassic.drawlegend(devc, settings, startx, starty, title)

    @staticmethod
    def paintbackground(devc, width, height):
        """Draw backgroundr"""
        ThemeClassic.paintbackground(devc, width, height)

    @staticmethod
    def gradback(devc, width, height, setting_f, startcol="rgb(64, 185, 255)", endcol='white'):
        """Draw a gradient background"""
        ThemeClassic.gradback(devc, width, height, setting_f, startcol, endcol)

    @staticmethod
    def olines(devc, slope, margins, width, height, metersize):
        """Draw altitude line"""
        ThemeClassic.olines(devc, slope, margins, width, height, metersize)

    @staticmethod
    def alttext(devc, slope, margins, max_y, metersize):
        """draw altitude text aside"""
        ThemeClassic.alttext(devc, slope, margins, max_y, metersize)

    @staticmethod
    def yaxis(devc, slope, margins, max_y, metersize):
        """Draw y axis"""
        ThemeClassic.yaxis(devc, slope, margins, max_y, metersize)

    @staticmethod
    def xaxis(devc, slope, margins, max_y, d_incr, kmsize, dx, dy):
        """Draw km bar"""
        ThemeClassic.xaxis(devc, slope, margins, max_y, d_incr, kmsize, dx, dy)

    @staticmethod
    def fillhslopecontour(devc, spath_back, dx, dy, colorlist):
        """ Draw horizontal contour."""
        spath_back.reverse()
        index = 0
        for pnts in spath_back:
            devc.setbrush(colorlist[index])
            index = index + 1
            path = devc.startpath(pnts[0])
            devc.drawpathcubicto(path, pnts[1:])
            point = (pnts[3][0]+dx, pnts[3][1]+dy)
            points = [(pnts[2][0]+dx, pnts[2][1]+dy),
                    (pnts[1][0]+dx, pnts[1][1]+dy),
                    (pnts[0][0]+dx, pnts[0][1]+dy)]
            devc.drawpathlineto(path, point)
            pnts = list(pnts)
            pnts.reverse()
            devc.drawpathcubicto(path, points)
            devc.endpath(path)

    @staticmethod
    def fillfirsthpoly(devc, points, color):
        """fill first horizontal polygon of the 3d slope"""
        ThemeClassic.fillfirsthpoly(devc, points, color)

    @staticmethod
    def fillvslopecontour(devc, path_points, pixel_0m, pixel_1000m, vpolygons, colorlist):
        """Draw a close smooth path thant contais the whole slope."""
        index = 0
        start_pnt = path_points.pop(0)
        point = path_points[0]
        start_pnt = point[0]
        for pnt in path_points[:-1]:
            devc.setbrush(colorlist[index])
            path = devc.startpath(start_pnt)
            devc.drawpathcubicto(path, pnt[1:])
            devc.drawpathlineto(path, vpolygons[index][1])
            devc.drawpathlineto(path, vpolygons[index][0])
            devc.drawpathlineto(path, vpolygons[index][3])
            devc.endpath(path)
            start_pnt = pnt[3]
            index = index + 1

    @staticmethod
    def desctext(devc, text, pos_x, pos_y, font):
        """Draw description text for every cp"""
        ThemeClassic.desctext(devc, text, pos_x, pos_y, font)

    @staticmethod
    def gradtext(devc, text, pos_x, pos_y, font):
        """Draw gradient text for every cp"""
        ThemeClassic.gradtext(devc, text, pos_x, pos_y, font)


class ThemeBwhite(Theme):
    """bezier white theme"""
    themename = "giro"
    shear = -0.15

    @staticmethod
    def getcolor(colors, levels, grad):
        """Return gradient relative color"""
        ThemeClassic.getcolor(colors, levels, grad)

    @staticmethod
    def drawslopeinfo(devc, info, settings, startx, starty):
        """Draw slope's name and other info background"""
        ThemeClassic.drawslopeinfo(devc, info, settings, startx, starty)

    @staticmethod
    def paintbackground(devc, width, height):
        """Draw background"""
        ThemeClassic.paintbackground(devc, width, height)

    @staticmethod
    def gradback(devc, width, height, setting_f, startcol="rgb(0, 0, 0)", endcol="rgb(70, 80, 70)"):
        """Draw a gradient background"""
        devc.setfont(setting_f)  # FIXME: move setfont in a new method

    @staticmethod
    def alttext(devc, slope, margins, max_y, metersize):
        """draw altitude text aside"""
        ThemeClassic.alttext(devc, slope, margins, max_y, metersize)

    @staticmethod
    def yaxis(devc, slope, margins, max_y, metersize):
        """Draw y axis"""
        ThemeClassic.yaxis(devc, slope, margins, max_y, metersize)

    @staticmethod
    def xaxis(devc, slope, margins, max_y, d_incr, kmsize, dx, dy):
        """Draw km bar"""
        ThemeClassic.xaxis(devc, slope, margins, max_y, d_incr, kmsize, dx, dy)

    @staticmethod
    def fillhslopecontour(devc, spath_back, dx, dy, colorlist):
        """ Draw horizontal contour."""
        devc.setbrush("rgb(207, 208, 212)")
        spath_back.reverse()
        for pnts in spath_back:
            path = devc.startpath(pnts[0])
            devc.drawpathcubicto(path, pnts[1:])
            point = (pnts[3][0]+dx, pnts[3][1]+dy)
            points = [(pnts[2][0]+dx, pnts[2][1]+dy),
                    (pnts[1][0]+dx, pnts[1][1]+dy),
                    (pnts[0][0]+dx, pnts[0][1]+dy)]
            devc.drawpathlineto(path, point)
            pnts = list(pnts)
            pnts.reverse()
            devc.drawpathcubicto(path, points)
            devc.endpath(path)

    @staticmethod
    def fillfirsthpoly(devc, points, color):
        """fill first horizontal polygon of the 3d slope"""
        devc.setbrush("rgb(207, 208, 212)")
        devc.drawpolygon(points)

    @staticmethod
    def fillvslopecontour(devc, path_points, pixel_0m, pixel_1000m, vpolygons, colorlist):
        """Draw a close smooth path thant contais the whole slope."""
        devc.setlineargradientbrush([("rgb(255, 253, 241)", 0),
                                     ("rgb(255, 253, 241)", 0.25),
                                     ("rgb(222, 234, 190)", 0.50),
                                     ("rgb(240, 236, 189)", 0.75),
                                     ("rgb(233, 198, 153)", 1)],
                                    (0, pixel_0m), (0, pixel_0m + (pixel_1000m - pixel_0m)*1.8))
        start_pnt = path_points.pop(0)
        path = devc.startpath(start_pnt)
        ctrl_pnts = path_points.pop(0)
        devc.drawpathlineto(path, ctrl_pnts[0])
        devc.drawpathcubicto(path, ctrl_pnts[1:])
        for pnt in path_points[:-1]:
            devc.drawpathcubicto(path, pnt[1:])
        devc.drawpathlineto(path, path_points[-1])
        devc.endpath(path)

    @staticmethod
    def desctext(devc, text, pos_x, pos_y, font):
        """Draw description text for every cp"""
        ThemeClassic.desctext(devc, text, pos_x, pos_y, font)


class ThemeBlue(Theme):
    """Blue theme"""
    themename = "Blue"
    shear = -0.15

    @staticmethod
    def getcolor(colors, levels, grad):
        """Return gradient relative color"""
        gradient = abs(grad)
        for i in range(len(levels)):
            if gradient < levels[i]:
                return colors[i-1]
        return colors[i]

    @staticmethod
    def drawslopeinfo(devc, info, settings, startx, starty):
        """Draw slope's name and other info background"""
        name, avp, maxp, eleg, heightg = info
        devc.setfont(settings['ftitle'])
        devc.setpen('black', 1)
        devc.drawtext(name, startx, starty)
        if settings['sinfo']:
            devc.setfont(settings['fdesc'])
            devc.drawtext(avp, startx+10, starty+20)
            devc.drawtext(maxp, startx+10, starty+40)
            devc.drawtext(eleg, startx+10, starty+60)
            devc.drawtext(heightg, startx+10, starty+80)

    @staticmethod
    def paintbackground(devc, width, height):
        """Draw background"""
        devc.setbrush("rgb(255, 255, 255)")
        rec = (0, 0, width, height)
        devc.drawrectangle(*rec)

    @staticmethod
    def gradback(devc, width, height, setting_f, startcol="rgb(255, 255, 255)", endcol="rgb(250, 250, 250)"):
        """Draw a gradient background"""
        area = (0, 0, width, height)
        devc.gradfill(area, startcol, endcol)
        devc.setpen('black', 1)
        devc.setfont(setting_f)

    @staticmethod
    def olines(devc, slope, margins, width, height, metersize):
        """Draw altitude line"""
        devc.setpen("rgb(200, 200, 250)", 1)
        (updownmar, leftrightmar) = margins
        (lef_mar, rig_mar) = leftrightmar
        (upp_mar, low_mar) = updownmar
        x0_alt_bar = lef_mar - 3
        x1_alt_bar = width - rig_mar - 3
        y_alt_base_bar = height - low_mar
        for i in range(int(slope.min_h / slope.h_incr),
                       int((slope.max_h / slope.h_incr) + 1)):
            yincr = int((i * slope.h_incr - slope.min_h) * metersize)
            devc.drawline(x0_alt_bar, y_alt_base_bar - yincr,
                          x1_alt_bar, y_alt_base_bar - yincr)

    @staticmethod
    def alttext(devc, slope, margins, max_y, metersize):
        """draw altitude text aside"""
        (updownmar, leftrightmar) = margins
        (lef_mar, rig_mar) = leftrightmar
        (upp_mar, low_mar) = updownmar

        devc.setpen('black', 2)
        x_alt_txt = lef_mar - 40
        y_alt_base_txt = max_y - low_mar - 8
        for i in range(int(slope.min_h/slope.h_incr), int((slope.max_h/slope.h_incr) + 1)):
            yincr = int((i * slope.h_incr - slope.min_h) * metersize)
            alti_t = ("%4d" % (i*slope.h_incr))
            devc.drawtext(alti_t, x_alt_txt, y_alt_base_txt - yincr)

    @staticmethod
    def yaxis(devc, slope, margins, max_y, metersize):
        """Draw y axis"""
        ThemeClassic.yaxis(devc, slope, margins, max_y, metersize)

    @staticmethod
    def xaxis(devc, slope, margins, max_y, d_incr, kmsize, dx, dy):
        """Draw km bar"""
        devc.setpen('black', 1)
        ThemeClassic.xaxis(devc, slope, margins, max_y, d_incr, kmsize, dx, dy)

    @staticmethod
    def fillhpoly(devc, points, color):
        """fill horizontal polygons of the 3d slope"""
        devc.setpen('black', 1)
        devc.setbrush("rgb(220, 220, 250)")
        devc.drawpolygon(points)

    @staticmethod
    def fillfirsthpoly(devc, points, color):
        """fill first horizontal polygon of the 3d slope"""
        devc.setpen('black', 1)
        # devc.setbrush(color)
        devc.setlineargradientbrush([("rgb(250, 250, 250)", 0),
                                     ("rgb(200, 200, 250)", 1)],
                                    (0, points[3][1]), (0, devc.size_y/2))
        devc.drawpolygon(points)

    @staticmethod
    def fillvpoly(devc, points, color):
        """fill vertical polygons (2d and 3d) of the slope"""
        devc.setpen('black', 1)
        # devc.setbrush(color)
        devc.setlineargradientbrush([("rgb(250, 250, 250)", 0),
                                     ("rgb(200, 200, 250)", 1)],
                                    (0, points[1][1]), (0, devc.size_y/2))  # max(points[3][1], points[2][1])))
        devc.drawpolygon(points)

    @staticmethod
    def desctext(devc, text, pos_x, pos_y, font):
        """Draw description text for every cp"""
        devc.setpen('black', 1)
        devc.setfont(font)
        devc.drawrotatedtext(text, pos_x, pos_y, 90)

    @staticmethod
    def gradtext(devc, text, pos_x, pos_y, font):
        """Draw gradient text for every cp"""
        devc.setpen('black', 1)
        devc.setfont(font)
        devc.drawtext(text, pos_x, pos_y)


class ThemeBlack(Theme):
    """Black theme"""
    themename = "Black"
    shear = -0.15

    @staticmethod
    def getcolor(colors, levels, grad):
        """Return gradient relative color"""
        gradient = abs(grad)
        for i in range(len(levels)):
            if gradient < levels[i]:
                return colors[i-1]
        return colors[i]

    @staticmethod
    def drawslopeinfo(devc, info, settings, startx, starty):
        """Draw slope's name and other info background"""
        name, avp, maxp, eleg, heightg = info
        devc.setfont(settings['ftitle'])
        devc.setpen('white', 1)
        devc.drawtext(name, startx, starty)
        if settings['sinfo']:
            devc.setfont(settings['fdesc'])
            devc.drawtext(avp, startx+10, starty+20)
            devc.drawtext(maxp, startx+10, starty+40)
            devc.drawtext(eleg, startx+10, starty+60)
            devc.drawtext(heightg, startx+10, starty+80)

    @staticmethod
    def drawlegend(devc, settings, startx, starty, title):
        """Draw slope's legend"""
        devc.setbrush("rgb(90, 100, 90)")
        rec = (startx, starty, 310, 52)
        devc.setpen('black', 1)
        devc.drawrectangle(*rec)
        devc.setfont(settings['fdesc'])
        devc.setpen('white', 2)
        devc.drawtext(title, startx+130, starty+2)
        incr = 43
        for i in range(len(settings['colors'])):
            devc.setbrush(settings['colors'][i])
            devc.setpen('black', 1)
            rec = (startx+8+i*incr, starty+20, 36, 10)
            devc.drawrectangle(*rec)
            devc.setpen('white', 1)
            alti_t = (">%d%%" % (settings['levels'][i]))
            devc.drawtext(alti_t, startx+9+i*incr, starty+34)

    @staticmethod
    def paintbackground(devc, width, height):
        """Draw background"""
        devc.setbrush("rgb(70, 80, 70)")
        rec = (0, 0, width, height)
        devc.drawrectangle(*rec)

    @staticmethod
    def gradback(devc, width, height, setting_f, startcol="rgb(0, 0, 0)", endcol="rgb(70, 80, 70)"):
        """Draw a gradient background"""
        area = (0, 0, width, height)
        devc.gradfill(area, startcol, endcol)
        devc.setpen('black', 1)
        devc.setfont(setting_f)

    @staticmethod
    def alttext(devc, slope, margins, max_y, metersize):
        """draw altitude text aside"""
        (updownmar, leftrightmar) = margins
        (lef_mar, rig_mar) = leftrightmar
        (upp_mar, low_mar) = updownmar

        devc.setpen('white', 2)
        x_alt_txt = lef_mar - 40
        y_alt_base_txt = max_y - low_mar - 8
        for i in range(int(slope.min_h/slope.h_incr), int((slope.max_h/slope.h_incr) + 1)):
            yincr = int((i * slope.h_incr - slope.min_h) * metersize)
            alti_t = ("%4d" % (i*slope.h_incr))
            devc.drawtext(alti_t, x_alt_txt, y_alt_base_txt - yincr)

    @staticmethod
    def yaxis(devc, slope, margins, max_y, metersize):
        """Draw y axis"""
        ThemeClassic.yaxis(devc, slope, margins, max_y, metersize)

    @staticmethod
    def xaxis(devc, slope, margins, max_y, d_incr, kmsize, dx, dy):
        """Draw km bar"""
        (updownmar, leftrightmar) = margins
        (lef_mar, rig_mar) = leftrightmar
        (upp_mar, low_mar) = updownmar
        for i in range(int(int(slope.max_d) / d_incr - int(slope.min_d) / d_incr + 1)):
            if i % 2 == 0:
                devc.setbrush("rgb(0, 0, 0)")
            else:
                devc.setbrush("rgb(255, 255, 255)")
            rec = (i * d_incr * kmsize + lef_mar + dx,
                   max_y - low_mar + dy, d_incr * kmsize + 1, 5)
            devc.setpen('black', 1)
            devc.drawrectangle(*rec)
            devc.setpen('white', 1)
            d_label = ("%d" % (i * d_incr + int(slope.min_d)))
            devc.drawtext(d_label, rec[0], rec[1] + 5)

    @staticmethod
    def fillhpoly(devc, points, color):
        """fill horizontal polygons of the 3d slope"""
        devc.setpen('black', 1)
        devc.setbrush(color)
        devc.drawpolygon(points)

    @staticmethod
    def fillfirsthpoly(devc, points, color):
        """fill first horizontal polygon of the 3d slope"""
        devc.setpen('black', 1)
        devc.setbrush(color)
        devc.setlineargradientbrush([("rgb(0, 0, 0)", 0),
                                     (color, 1)],
                                    (0, points[3][1]), (0, points[1][1]))
        devc.drawpolygon(points)

    @staticmethod
    def fillvpoly(devc, points, color):
        """fill vertical polygons (2d and 3d) of the slope"""
        devc.setpen('black', 1)
        devc.setbrush(color)
        devc.setlineargradientbrush([("rgb(0, 0, 0)", 0),
                                     (color, 1)],
                                    (0, points[1][1]), (0, min(points[3][1], points[2][1])))
        devc.drawpolygon(points)

    @staticmethod
    def desctext(devc, text, pos_x, pos_y, font):
        """Draw description text for every cp"""
        devc.setpen('white', 1)
        devc.setfont(font)
        devc.drawrotatedtext(text, pos_x, pos_y, 90)

    @staticmethod
    def gradtext(devc, text, pos_x, pos_y, font):
        """Draw gradient text for every cp"""
        devc.setpen('white', 1)
        devc.setfont(font)
        devc.drawtext(text, pos_x, pos_y)


class ThemeGray(Theme):
    """Gray theme"""
    themename = "Gray"
    shear = -0.15

    @staticmethod
    def getcolor(colors, levels, grad):
        """Return gradient relative color"""
        gradient = abs(grad)
        graycolors = ["rgb(175,175,175)", "rgb(150,150,150)",
                      "rgb(125,125,125)", "rgb(100,100,100)",
                      "rgb(75,75,75)", "rgb(50,50,50)", "rgb(25,25,25)"]
        for i in range(len(levels)):
            if gradient < levels[i]:
                return graycolors[i-1]
        return graycolors[i]

    @staticmethod
    def drawslopeinfo(devc, info, settings, startx, starty):
        """Draw slope's name and other info background"""
        ThemeClassic.drawslopeinfo(devc, info, settings, startx, starty)

    @staticmethod
    def drawlegend(devc, settings, startx, starty, title):
        """Draw slope's legend"""
        graycolors = ["rgb(175,175,175)", "rgb(150,150,150)",
                      "rgb(125,125,125)", "rgb(100,100,100)",
                      "rgb(75,75,75)", "rgb(50,50,50)", "rgb(25,25,25)"]
        devc.setbrush("rgb(236, 236, 236)")
        rec = (startx, starty, 310, 52)
        devc.drawrectangle(*rec)
        devc.setfont(settings['fdesc'])
        devc.setpen('black', 2)
        devc.drawtext(title, startx+130, starty+2)
        incr = 43
        devc.setpen('black', 1)
        for i in range(len(graycolors)):
            devc.setbrush(graycolors[i])
            rec = (startx+8+i*incr, starty+20, 36, 10)
            devc.drawrectangle(*rec)
            alti_t = (">%d%%" % (settings['levels'][i]))
            devc.drawtext(alti_t, startx+9+i*incr, starty+34)

    @staticmethod
    def paintbackground(devc, width, height):
        """Draw background"""
        devc.setbrush('white')
        rec = (0, 0, width, height)
        devc.drawrectangle(*rec)

    @staticmethod
    def gradback(devc, width, height, setting_f, startcol="rgb(0, 0, 0)", endcol="rgb(70, 80, 70)"):
        """Draw a gradient background"""
        devc.setpen('black', 1)
        devc.setfont(setting_f)

    @staticmethod
    def olines(devc, slope, margins, width, height, metersize):
        """Draw altitude line"""
        ThemeClassic.olines(devc, slope, margins, width, height, metersize)

    @staticmethod
    def alttext(devc, slope, margins, max_y, metersize):
        """draw altitude text aside"""
        (updownmar, leftrightmar) = margins
        (lef_mar, rig_mar) = leftrightmar
        (upp_mar, low_mar) = updownmar

        devc.setpen('black', 2)
        x_alt_txt = lef_mar - 40
        y_alt_base_txt = max_y - low_mar - 8
        for i in range(int(slope.min_h/slope.h_incr), int((slope.max_h/slope.h_incr) + 1)):
            yincr = int((i * slope.h_incr - slope.min_h) * metersize)
            alti_t = ("%4d" % (i*slope.h_incr))
            devc.drawtext(alti_t, x_alt_txt, y_alt_base_txt - yincr)

    @staticmethod
    def yaxis(devc, slope, margins, max_y, metersize):
        """Draw y axis"""
        ThemeClassic.yaxis(devc, slope, margins, max_y, metersize)

    @staticmethod
    def xaxis(devc, slope, margins, max_y, d_incr, kmsize, dx, dy):
        """Draw km bar"""
        devc.setpen('black', 1)
        ThemeClassic.xaxis(devc, slope, margins, max_y, d_incr, kmsize, dx, dy)

    @staticmethod
    def fillhpoly(devc, points, color):
        """fill horizontal polygons of the 3d slope"""
        devc.setpen('black', 1)
        devc.setbrush(color)
        devc.drawpolygon(points)

    @staticmethod
    def fillfirsthpoly(devc, points, color):
        """fill first horizontal polygon of the 3d slope"""
        devc.setpen('black', 1)
        devc.setbrush(color)
        devc.setlineargradientbrush([("rgb(0, 0, 0)", 0),
                                     (color, 1)],
                                    (0, points[3][1]), (0, points[1][1]))
        devc.drawpolygon(points)

    @staticmethod
    def fillvpoly(devc, points, color):
        """fill vertical polygons (2d and 3d) of the slope"""
        devc.setpen('black', 1)
        devc.setbrush("rgb(100, 100, 100)")
        devc.setbrush(color)
        devc.setlineargradientbrush([("rgb(0, 0, 0)", 0),
                                     (color, 1)],
                                    (0, points[1][1]), (0, min(points[3][1], points[2][1])))
        devc.drawpolygon(points)

    @staticmethod
    def desctext(devc, text, pos_x, pos_y, font):
        """Draw description text for every cp"""
        devc.setfont(font)
        devc.setpen('white', 1)
        devc.drawrotatedtext(text, pos_x + 1, pos_y + 1, 90)
        devc.setpen('black', 1)
        devc.drawrotatedtext(text, pos_x, pos_y, 90)

    @staticmethod
    def gradtext(devc, text, pos_x, pos_y, font):
        """Draw gradient text for every cp"""
        devc.setfont(font)
        devc.setpen('black', 1)
        devc.drawtext(text, pos_x + 1, pos_y + 1)
        devc.setpen('white', 1)
        devc.drawtext(text, pos_x, pos_y)

# vim:sw=4:softtabstop=4:expandtab
