# 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 wx

from timelinelib.canvas.drawing.utils import darken_color
from timelinelib.canvas.drawing.utils import lighten_color
from timelinelib.canvas.eventboxdrawers.defaulteventboxdrawer import DefaultEventBoxDrawer
from timelinelib.canvas.gc import create_gc
import timelinelib.meta.overrides as mark


GRADIENT_STYLE_LEFT = 1
GRADIENT_STYLE_RIGHT = 2
GRADIENT_STYLE_BOTH = 3


class OtherGradientEventBoxDrawer(DefaultEventBoxDrawer):
    """
    This is a special event box drawer that overrides the background drawing and fuzzy
    edges drawing of the DefaultEventBoxDrawer.
    """
    def __init__(self, fuzzy_edges=False):
        """
        :param fuzzy_edges: If True, fuzzy edges are drawn instead of using an icon.
        """
        self._fuzzy_edges = fuzzy_edges
        self._event = None
        self._rect = None
        self._light_color = None
        self._dark_color = None

    @mark.overrides
    def _draw_background(self, dc, rect, event):
        """
        :param dc: The device context to draw on
        :param rect: The bounding rectangle where the event shall be drawn.
        :param event: The event to draw
        """
        self._event = event
        self._rect = rect
        self._light_color = lighten_color(self._event.get_color())
        self._dark_color = darken_color(self._event.get_color(), factor=0.8)
        dc.SetPen(self._get_pen(dc, event))
        if self._fuzzy_edges:
            if event.fuzzy_start or event.fuzzy_end:
                dc.DrawLine(self._rect.GetTopLeft(), self._rect.GetTopRight())
                dc.DrawLine(self._rect.GetBottomLeft(), self._rect.GetBottomRight())
            if event.fuzzy_start and event.fuzzy_end:
                self._draw_fuzzy_background(dc, GRADIENT_STYLE_BOTH)
            elif event.fuzzy_start:
                self._draw_fuzzy_background(dc, GRADIENT_STYLE_LEFT)
            elif event.fuzzy_end:
                self._draw_fuzzy_background(dc, GRADIENT_STYLE_RIGHT)
            else:
                self._draw_background_no_fuzzy_edges(dc)
        else:
            self._draw_background_no_fuzzy_edges(dc)

    @mark.overrides
    def _draw_fuzzy_edges(self, dc, rect, event):
        """
        :param dc: The device context to draw on
        :param rect: The bounding rectangle where the event shall be drawn.
        :param event: The event to draw
        The purpose of this function is to NOT draw the fuzzy edges icon, since this
        drawer has no left and right edges if self._fuzzy_edges, otherwise we delegate
        all drawing to the DefaultEventBoxDrawer.
        """
        if not self._fuzzy_edges:
            super(OtherGradientEventBoxDrawer, self)._draw_fuzzy_edges(dc, rect, event)

    def _draw_background_no_fuzzy_edges(self, dc):
        dc.DrawRectangle(self._rect)
        dc.GradientFillLinear(deflate_rect(self._rect), self._light_color, self._dark_color, wx.WEST)

    def _draw_fuzzy_background(self, dc, style):
        gc = create_gc(dc)
        brush = self._create_gradient_brush(gc, style)
        gc.SetBrush(brush)
        gc.DrawRectangle(*self._rect)

    def _create_gradient_brush(self, gc, style):
        c1 = wx.Colour(*self._event.get_color(), 0)
        c2 = wx.Colour(*self._event.get_color(), 50)
        c3 = wx.Colour(*self._event.get_color(), 255)
        stops = wx.GraphicsGradientStops()
        if style == GRADIENT_STYLE_LEFT:
            stops.Add(c1, 0)
            stops.Add(c2, 0.1)
            stops.Add(c3, 0.3)
            stops.Add(c3, 1)
        elif style == GRADIENT_STYLE_RIGHT:
            stops.Add(c1, 1)
            stops.Add(c2, 0.9)
            stops.Add(c3, 0.7)
            stops.Add(c3, 0)
        elif style == GRADIENT_STYLE_BOTH:
            stops.Add(c1, 0)
            stops.Add(c2, 0.1)
            stops.Add(c3, 0.3)
            stops.Add(c3, 0.7)
            stops.Add(c2, 0.9)
            stops.Add(c1, 1)
        return gc.CreateLinearGradientBrush(self._rect.x, self._rect.y, self._rect.x + self._rect.width,
                                            self._rect.y + self._rect.height, stops)


def deflate_rect(rect, dx=1, dy=1):
    return wx.Rect(*rect).Deflate(dx, dy)
