# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018  Rickard Lindberg, Roger Lindberg
#
# This file is part of Timeline.
#
# Timeline 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.
#
# Timeline 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 Timeline.  If not, see <http://www.gnu.org/licenses/>.


import math

import wx


class FakeGC:

    def __init__(self, dc):
        self.dc = dc
        self._gradient_stops = None

    def CreatePath(self):
        return FakePath()

    def Translate(self, dx, dy):
        pass

    def SetPen(self, pen):
        self.dc.SetPen(pen)

    def SetBrush(self, brush):
        self.dc.SetBrush(brush)

    def DrawPath(self, path):
        for subpath in path.subpaths:
            self.dc.DrawPolygon(subpath)

    def CreateLinearGradientBrush(self, x, y, width, height, stops):
        self._gradient_stops = stops
        return self.dc.GetBrush()

    def DrawRectangle(self, x, y, width, height):
        # The stops has two more items than the added items. One extra in the beginning
        # and one extra in the end. So the first item added is Item(1).
        # This item contains the event colour.
        # When there is 8 stops it means that the event is fuzzy in both ends.
        # Otherwise if the alpha value of the Item(1).Colour is 0 it means that
        # the event has a fuzzy left side.
        self.dc.SetPen(wx.Pen(wx.WHITE, style=wx.PENSTYLE_TRANSPARENT))
        rect = wx.Rect(x, y, width, height)
        color = self._gradient_stops.Item(1).Colour[:3]
        transparent_colour = wx.Colour(*color, 0)
        opaque_colour = wx.Colour(*color, 255)
        alpha = self._gradient_stops.Item(1).Colour[3]
        if self._gradient_stops.Count == 8:
            self.dc.GradientFillLinear(left_half_of_rect(rect),
                                       transparent_colour, opaque_colour, wx.EAST)
            self.dc.GradientFillLinear(right_half_of_rect(rect),
                                       opaque_colour, transparent_colour, wx.EAST)
        elif alpha == 0:
            self.dc.GradientFillLinear(rect, transparent_colour, opaque_colour, wx.EAST)
        else:
            self.dc.GradientFillLinear(rect, opaque_colour, transparent_colour, wx.EAST)


class FakePath:

    def __init__(self):
        self._subpaths = []
        self._points = []

    @property
    def subpaths(self):
        return self._subpaths

    def MoveToPoint(self, x, y):
        self.CloseSubpath()
        self._points.append((x, y))

    def AddLineToPoint(self, x, y):
        self._points.append((x, y))

    def AddArc(self, x, y, radius, start_angle, end_angle, clockwise):
        divisions = 10
        if end_angle < start_angle:
            end_angle += math.radians(360)
        step = (end_angle - start_angle) / divisions
        for i in range(divisions):
            self._points.append(self._create_point(x, y, radius, start_angle + i * step))
        self._points.append(self._create_point(x, y, radius, end_angle))

    def _create_point(self, x, y, radius, angle):
        return x + radius * math.cos(angle), y + radius * math.sin(angle)

    def CloseSubpath(self):
        if self._points:
            self._subpaths.append(self._points)
        self._points = []



def create_gc(dc):
    try:
        gc = wx.GraphicsContext.Create(dc)
        if gc:
            return gc
    except TypeError:
        pass
    return FakeGC(dc)


def left_half_of_rect(rect):
    r = wx.Rect(*rect).Deflate(1, 1)
    r.SetWidth(r.GetWidth() // 2)
    return r


def right_half_of_rect(rect):
    r = wx.Rect(*rect).Deflate(1, 1)
    r.SetWidth(r.GetWidth() // 2)
    r.SetPosition(wx.Point(r.GetX() + r.GetWidth(), r.GetY()))
    return r