# This file is part of CairoSVG
# Copyright © 2010-2015 Kozea
#
# This library is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# This library 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 Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with CairoSVG.  If not, see <http://www.gnu.org/licenses/>.

"""
Shapes drawers.

"""

from math import pi

from .helpers import normalize, point, point_angle, size


def circle(surface, node):
    """Draw a circle ``node`` on ``surface``."""
    r = size(surface, node.get('r'))
    if not r:
        return
    cx = size(surface, node.get('cx'), 'x')
    cy = size(surface, node.get('cy'), 'y')

    surface.context.new_sub_path()
    surface.context.arc(cx, cy, r, 0, 2 * pi)


def ellipse(surface, node):
    """Draw an ellipse ``node`` on ``surface``."""
    rx = size(surface, node.get('rx'), 'x')
    ry = size(surface, node.get('ry'), 'y')
    if not rx or not ry:
        return
    cx = size(surface, node.get('cx'), 'x')
    cy = size(surface, node.get('cy'), 'y')

    ratio = ry / rx
    surface.context.new_sub_path()
    surface.context.save()
    surface.context.scale(1, ratio)
    surface.context.arc(cx, cy / ratio, rx, 0, 2 * pi)
    surface.context.restore()


def line(surface, node):
    """Draw a line ``node``."""
    x1, y1, x2, y2 = tuple(
        size(surface, node.get(position), position[0])
        for position in ('x1', 'y1', 'x2', 'y2'))
    surface.context.move_to(x1, y1)
    surface.context.line_to(x2, y2)
    angle = point_angle(x1, y1, x2, y2)
    node.vertices = [(x1, y1), (pi - angle, angle), (x2, y2)]


def polygon(surface, node):
    """Draw a polygon ``node`` on ``surface``."""
    polyline(surface, node)
    surface.context.close_path()


def polyline(surface, node):
    """Draw a polyline ``node``."""
    points = normalize(node.get('points', ''))
    if points:
        x, y, points = point(surface, points)
        surface.context.move_to(x, y)
        node.vertices = [(x, y)]
        while points:
            x_old, y_old = x, y
            x, y, points = point(surface, points)
            angle = point_angle(x_old, y_old, x, y)
            node.vertices.append((pi - angle, angle))
            surface.context.line_to(x, y)
            node.vertices.append((x, y))


def rect(surface, node):
    """Draw a rect ``node`` on ``surface``."""
    x, y = size(surface, node.get('x'), 'x'), size(surface, node.get('y'), 'y')
    width = size(surface, node.get('width'), 'x')
    height = size(surface, node.get('height'), 'y')
    rx = node.get('rx')
    ry = node.get('ry')
    if rx and ry is None:
        ry = rx
    elif ry and rx is None:
        rx = ry
    rx = size(surface, rx, 'x')
    ry = size(surface, ry, 'y')

    if rx == 0 or ry == 0:
        surface.context.rectangle(x, y, width, height)
    else:
        if rx > width / 2:
            rx = width / 2
        if ry > height / 2:
            ry = height / 2

        # Inspired by Cairo Cookbook
        # http://cairographics.org/cookbook/roundedrectangles/
        ARC_TO_BEZIER = 4 * (2 ** .5 - 1) / 3
        c1 = ARC_TO_BEZIER * rx
        c2 = ARC_TO_BEZIER * ry

        surface.context.new_path()
        surface.context.move_to(x + rx, y)
        surface.context.rel_line_to(width - 2 * rx, 0)
        surface.context.rel_curve_to(c1, 0, rx, c2, rx, ry)
        surface.context.rel_line_to(0, height - 2 * ry)
        surface.context.rel_curve_to(0, c2, c1 - rx, ry, -rx, ry)
        surface.context.rel_line_to(-width + 2 * rx, 0)
        surface.context.rel_curve_to(-c1, 0, -rx, -c2, -rx, -ry)
        surface.context.rel_line_to(0, -height + 2 * ry)
        surface.context.rel_curve_to(0, -c2, rx - c1, -ry, rx, -ry)
        surface.context.close_path()
