# -*- coding: utf-8 -*-
# This file is part of CairoSVG
# Copyright © 2010-2012 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, 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")

    # Set "standard" values that may be used by gradients
    node["width"], node["height"] = str(r * 2), str(r * 2)
    node["x"], node["y"] = str(cx - r), str(cy - r)

    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")

    # Set "standard" values that may be used by gradients
    node["width"], node["height"] = str(rx * 2), str(ry * 2)
    node["x"], node["y"] = str(cx - rx), str(cy - ry)

    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)


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)
        while points:
            x, y, points = point(surface, points)
            surface.context.line_to(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()
