from __future__ import absolute_import
# Copyright (c) 2010-2015 openpyxl

from openpyxl.styles.colors import Color, BLACK, WHITE

from openpyxl.utils.units import (
    pixels_to_EMU,
    EMU_to_pixels,
    short_color,
)

from openpyxl.compat import deprecated
from openpyxl.xml.functions import Element, SubElement, tostring
from openpyxl.xml.constants import (
    DRAWING_NS,
    SHEET_DRAWING_NS,
    CHART_NS,
    CHART_DRAWING_NS,
    PKG_REL_NS
)
from openpyxl.compat.strings import safe_string


class Shape(object):
    """ a drawing inside a chart
        coordiantes are specified by the user in the axis units
    """

    MARGIN_LEFT = 6 + 13 + 1
    MARGIN_BOTTOM = 17 + 11

    FONT_WIDTH = 7
    FONT_HEIGHT = 8

    ROUND_RECT = 'roundRect'
    RECT = 'rect'

    # other shapes to define :
    '''
    "line"
    "lineInv"
    "triangle"
    "rtTriangle"
    "diamond"
    "parallelogram"
    "trapezoid"
    "nonIsoscelesTrapezoid"
    "pentagon"
    "hexagon"
    "heptagon"
    "octagon"
    "decagon"
    "dodecagon"
    "star4"
    "star5"
    "star6"
    "star7"
    "star8"
    "star10"
    "star12"
    "star16"
    "star24"
    "star32"
    "roundRect"
    "round1Rect"
    "round2SameRect"
    "round2DiagRect"
    "snipRoundRect"
    "snip1Rect"
    "snip2SameRect"
    "snip2DiagRect"
    "plaque"
    "ellipse"
    "teardrop"
    "homePlate"
    "chevron"
    "pieWedge"
    "pie"
    "blockArc"
    "donut"
    "noSmoking"
    "rightArrow"
    "leftArrow"
    "upArrow"
    "downArrow"
    "stripedRightArrow"
    "notchedRightArrow"
    "bentUpArrow"
    "leftRightArrow"
    "upDownArrow"
    "leftUpArrow"
    "leftRightUpArrow"
    "quadArrow"
    "leftArrowCallout"
    "rightArrowCallout"
    "upArrowCallout"
    "downArrowCallout"
    "leftRightArrowCallout"
    "upDownArrowCallout"
    "quadArrowCallout"
    "bentArrow"
    "uturnArrow"
    "circularArrow"
    "leftCircularArrow"
    "leftRightCircularArrow"
    "curvedRightArrow"
    "curvedLeftArrow"
    "curvedUpArrow"
    "curvedDownArrow"
    "swooshArrow"
    "cube"
    "can"
    "lightningBolt"
    "heart"
    "sun"
    "moon"
    "smileyFace"
    "irregularSeal1"
    "irregularSeal2"
    "foldedCorner"
    "bevel"
    "frame"
    "halfFrame"
    "corner"
    "diagStripe"
    "chord"
    "arc"
    "leftBracket"
    "rightBracket"
    "leftBrace"
    "rightBrace"
    "bracketPair"
    "bracePair"
    "straightConnector1"
    "bentConnector2"
    "bentConnector3"
    "bentConnector4"
    "bentConnector5"
    "curvedConnector2"
    "curvedConnector3"
    "curvedConnector4"
    "curvedConnector5"
    "callout1"
    "callout2"
    "callout3"
    "accentCallout1"
    "accentCallout2"
    "accentCallout3"
    "borderCallout1"
    "borderCallout2"
    "borderCallout3"
    "accentBorderCallout1"
    "accentBorderCallout2"
    "accentBorderCallout3"
    "wedgeRectCallout"
    "wedgeRoundRectCallout"
    "wedgeEllipseCallout"
    "cloudCallout"
    "cloud"
    "ribbon"
    "ribbon2"
    "ellipseRibbon"
    "ellipseRibbon2"
    "leftRightRibbon"
    "verticalScroll"
    "horizontalScroll"
    "wave"
    "doubleWave"
    "plus"
    "flowChartProcess"
    "flowChartDecision"
    "flowChartInputOutput"
    "flowChartPredefinedProcess"
    "flowChartInternalStorage"
    "flowChartDocument"
    "flowChartMultidocument"
    "flowChartTerminator"
    "flowChartPreparation"
    "flowChartManualInput"
    "flowChartManualOperation"
    "flowChartConnector"
    "flowChartPunchedCard"
    "flowChartPunchedTape"
    "flowChartSummingJunction"
    "flowChartOr"
    "flowChartCollate"
    "flowChartSort"
    "flowChartExtract"
    "flowChartMerge"
    "flowChartOfflineStorage"
    "flowChartOnlineStorage"
    "flowChartMagneticTape"
    "flowChartMagneticDisk"
    "flowChartMagneticDrum"
    "flowChartDisplay"
    "flowChartDelay"
    "flowChartAlternateProcess"
    "flowChartOffpageConnector"
    "actionButtonBlank"
    "actionButtonHome"
    "actionButtonHelp"
    "actionButtonInformation"
    "actionButtonForwardNext"
    "actionButtonBackPrevious"
    "actionButtonEnd"
    "actionButtonBeginning"
    "actionButtonReturn"
    "actionButtonDocument"
    "actionButtonSound"
    "actionButtonMovie"
    "gear6"
    "gear9"
    "funnel"
    "mathPlus"
    "mathMinus"
    "mathMultiply"
    "mathDivide"
    "mathEqual"
    "mathNotEqual"
    "cornerTabs"
    "squareTabs"
    "plaqueTabs"
    "chartX"
    "chartStar"
    "chartPlus"
    '''

    @deprecated("Chart Drawings need a complete rewrite")
    def __init__(self,
                 chart,
                 coordinates=((0, 0), (1, 1)),
                 text=None,
                 scheme="accent1"):
        self.chart = chart
        self.coordinates = coordinates  # in axis units
        self.text = text
        self.scheme = scheme
        self.style = Shape.RECT
        self.border_width = 0
        self.border_color = BLACK  # "F3B3C5"
        self.color = WHITE
        self.text_color = BLACK

    @property
    def border_color(self):
        return self._border_color

    @border_color.setter
    def border_color(self, color):
        self._border_color = short_color(color)

    @property
    def color(self):
        return self._color

    @color.setter
    def color(self, color):
        self._color = short_color(color)

    @property
    def text_color(self):
        return self._text_color

    @text_color.setter
    def text_color(self, color):
        self._text_color = short_color(color)

    @property
    def border_width(self):
        return self._border_width

    @border_width.setter
    def border_width(self, w):
        self._border_width = w

    @property
    def coordinates(self):
        """Return coordindates in axis units"""
        return self._coordinates

    @coordinates.setter
    def coordinates(self, coords):
        """ set shape coordinates in percentages (left, top, right, bottom)
        """
        # this needs refactoring to reflect changes in charts
        self.axis_coordinates = coords
        (x1, y1), (x2, y2) = coords # bottom left, top right
        drawing_width = pixels_to_EMU(self.chart.drawing.width)
        drawing_height = pixels_to_EMU(self.chart.drawing.height)
        plot_width = drawing_width * self.chart.width
        plot_height = drawing_height * self.chart.height

        margin_left = self.chart._get_margin_left() * drawing_width
        xunit = plot_width / self.chart.get_x_units()

        margin_top = self.chart._get_margin_top() * drawing_height
        yunit = self.chart.get_y_units()

        x_start = (margin_left + (float(x1) * xunit)) / drawing_width
        y_start = ((margin_top
                    + plot_height
                    - (float(y1) * yunit))
                    / drawing_height)

        x_end = (margin_left + (float(x2) * xunit)) / drawing_width
        y_end = ((margin_top
                  + plot_height
                  - (float(y2) * yunit))
                  / drawing_height)

        # allow user to specify y's in whatever order
        # excel expect y_end to be lower
        if y_end < y_start:
            y_end, y_start = y_start, y_end

        self._coordinates = (
            self._norm_pct(x_start), self._norm_pct(y_start),
            self._norm_pct(x_end), self._norm_pct(y_end)
        )

    @staticmethod
    def _norm_pct(pct):
        """ force shapes to appear by truncating too large sizes """
        if pct > 1:
            return 1
        elif pct < 0:
            return 0
        return pct


class ShapeWriter(object):
    """ one file per shape """

    def __init__(self, shapes):

        self._shapes = shapes

    def write(self, shape_id):

        root = Element('{%s}userShapes' % CHART_NS)

        for shape in self._shapes:
            anchor = SubElement(root, '{%s}relSizeAnchor' % CHART_DRAWING_NS)

            xstart, ystart, xend, yend = shape.coordinates

            _from = SubElement(anchor, '{%s}from' % CHART_DRAWING_NS)
            SubElement(_from, '{%s}x' % CHART_DRAWING_NS).text = str(xstart)
            SubElement(_from, '{%s}y' % CHART_DRAWING_NS).text = str(ystart)

            _to = SubElement(anchor, '{%s}to' % CHART_DRAWING_NS)
            SubElement(_to, '{%s}x' % CHART_DRAWING_NS).text = str(xend)
            SubElement(_to, '{%s}y' % CHART_DRAWING_NS).text = str(yend)

            sp = SubElement(anchor, '{%s}sp' % CHART_DRAWING_NS, {'macro':'', 'textlink':''})
            nvspr = SubElement(sp, '{%s}nvSpPr' % CHART_DRAWING_NS)
            SubElement(nvspr, '{%s}cNvPr' % CHART_DRAWING_NS, {'id':str(shape_id), 'name':'shape %s' % shape_id})
            SubElement(nvspr, '{%s}cNvSpPr' % CHART_DRAWING_NS)

            sppr = SubElement(sp, '{%s}spPr' % CHART_DRAWING_NS)
            frm = SubElement(sppr, '{%s}xfrm' % DRAWING_NS,)
            # no transformation
            SubElement(frm, '{%s}off' % DRAWING_NS, {'x':'0', 'y':'0'})
            SubElement(frm, '{%s}ext' % DRAWING_NS, {'cx':'0', 'cy':'0'})

            prstgeom = SubElement(sppr, '{%s}prstGeom' % DRAWING_NS, {'prst':str(shape.style)})
            SubElement(prstgeom, '{%s}avLst' % DRAWING_NS)

            fill = SubElement(sppr, '{%s}solidFill' % DRAWING_NS, )
            SubElement(fill, '{%s}srgbClr' % DRAWING_NS, {'val':shape.color})

            border = SubElement(sppr, '{%s}ln' % DRAWING_NS, {'w':str(shape._border_width)})
            sf = SubElement(border, '{%s}solidFill' % DRAWING_NS)
            SubElement(sf, '{%s}srgbClr' % DRAWING_NS, {'val':shape.border_color})

            self._write_style(sp)
            self._write_text(sp, shape)

            shape_id += 1

        return tostring(root)

    def _write_text(self, node, shape):
        """ write text in the shape """

        tx_body = SubElement(node, '{%s}txBody' % CHART_DRAWING_NS)
        SubElement(tx_body, '{%s}bodyPr' % DRAWING_NS, {'vertOverflow':'clip'})
        SubElement(tx_body, '{%s}lstStyle' % DRAWING_NS)
        p = SubElement(tx_body, '{%s}p' % DRAWING_NS)
        if shape.text:
            r = SubElement(p, '{%s}r' % DRAWING_NS)
            rpr = SubElement(r, '{%s}rPr' % DRAWING_NS, {'lang':'en-US'})
            fill = SubElement(rpr, '{%s}solidFill' % DRAWING_NS)
            SubElement(fill, '{%s}srgbClr' % DRAWING_NS, {'val':shape.text_color})

            SubElement(r, '{%s}t' % DRAWING_NS).text = shape.text
        else:
            SubElement(p, '{%s}endParaRPr' % DRAWING_NS, {'lang':'en-US'})

    def _write_style(self, node):
        """ write style theme """

        style = SubElement(node, '{%s}style' % CHART_DRAWING_NS)

        ln_ref = SubElement(style, '{%s}lnRef' % DRAWING_NS, {'idx':'2'})
        scheme_clr = SubElement(ln_ref, '{%s}schemeClr' % DRAWING_NS, {'val':'accent1'})
        SubElement(scheme_clr, '{%s}shade' % DRAWING_NS, {'val':'50000'})

        fill_ref = SubElement(style, '{%s}fillRef' % DRAWING_NS, {'idx':'1'})
        SubElement(fill_ref, '{%s}schemeClr' % DRAWING_NS, {'val':'accent1'})

        effect_ref = SubElement(style, '{%s}effectRef' % DRAWING_NS, {'idx':'0'})
        SubElement(effect_ref, '{%s}schemeClr' % DRAWING_NS, {'val':'accent1'})

        font_ref = SubElement(style, '{%s}fontRef' % DRAWING_NS, {'idx':'minor'})
        SubElement(font_ref, '{%s}schemeClr' % DRAWING_NS, {'val':'lt1'})

[(228, 'openpyxl.compat.deprecated', 'deprecated', False, 'from openpyxl.compat import deprecated\n'), (250, 'openpyxl.utils.units.short_color', 'short_color', False, 'from openpyxl.utils.units import pixels_to_EMU, EMU_to_pixels, short_color\n'), (258, 'openpyxl.utils.units.short_color', 'short_color', False, 'from openpyxl.utils.units import pixels_to_EMU, EMU_to_pixels, short_color\n'), (266, 'openpyxl.utils.units.short_color', 'short_color', False, 'from openpyxl.utils.units import pixels_to_EMU, EMU_to_pixels, short_color\n'), (288, 'openpyxl.utils.units.pixels_to_EMU', 'pixels_to_EMU', False, 'from openpyxl.utils.units import pixels_to_EMU, EMU_to_pixels, short_color\n'), (289, 'openpyxl.utils.units.pixels_to_EMU', 'pixels_to_EMU', False, 'from openpyxl.utils.units import pixels_to_EMU, EMU_to_pixels, short_color\n'), (340, 'openpyxl.xml.functions.Element', 'Element', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (381, 'openpyxl.xml.functions.tostring', 'tostring', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (386, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (387, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (388, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (389, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (403, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (405, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (406, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (407, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (409, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (410, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (412, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (413, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (415, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (416, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (343, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (347, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (351, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (355, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (356, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (358, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (360, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (361, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (363, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (364, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (367, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (369, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (370, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (373, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (374, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (391, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (392, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (393, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (394, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (398, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (348, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (349, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (352, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (353, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n'), (396, 'openpyxl.xml.functions.SubElement', 'SubElement', False, 'from openpyxl.xml.functions import Element, SubElement, tostring\n')]