""" PieGraph represents a pie graph

    The DIRAC Graphs package is derived from the GraphTool plotting package of the
    CMS/Phedex Project by ... <to be added>
"""

from __future__ import print_function
from __future__ import absolute_import
from __future__ import division

import numpy
import math
import time
from matplotlib.patches import Wedge, Shadow
from DIRAC.Core.Utilities.Graphs.PlotBase import PlotBase
from DIRAC.Core.Utilities.Graphs.GraphData import GraphData
from DIRAC.Core.Utilities.Graphs.GraphUtilities import *

__RCSID__ = "$Id$"


class PieGraph(PlotBase):
    def __init__(self, data, ax, prefs, *args, **kw):

        PlotBase.__init__(self, data, ax, prefs, *args, **kw)
        self.pdata = data

    def pie(self, explode=None, colors=None, autopct=None, pctdistance=0.6, shadow=False):

        start = time.time()
        labels = self.pdata.getLabels()
        if labels[0][0] == "NoLabels":
            try:
                self.pdata.initialize(key_type="string")
                self.pdata.sortLabels()
                labels = self.pdata.getLabels()
                nLabels = self.pdata.getNumberOfLabels()
                explode = [0.0] * nLabels
                if nLabels > 0:
                    explode[0] = 0.1
            except Exception as x:
                print("PieGraph Error: can not interpret data for the plot")

        # labels.reverse()
        values = [l[1] for l in labels]
        x = numpy.array(values, numpy.float64)
        self.legendData = labels

        sx = float(numpy.sum(x))
        if sx > 0:
            x = numpy.divide(x, sx)

        labels = [l[0] for l in labels]
        if explode is None:
            explode = [0] * len(x)
        assert len(x) == len(labels)
        assert len(x) == len(explode)
        plot_axis_labels = self.prefs.get("plot_axis_labels", True)

        center = 0, 0
        radius = 1.1
        theta1 = 0
        i = 0
        texts = []
        slices = []
        autotexts = []

        for frac, label, expl in zip(x, labels, explode):
            x, y = center
            theta2 = theta1 + frac
            thetam = 2 * math.pi * 0.5 * (theta1 + theta2)
            x += expl * math.cos(thetam)
            y += expl * math.sin(thetam)
            color = self.palette.getColor(label)
            w = Wedge(
                (x, y),
                radius,
                360.0 * theta1,
                360.0 * theta2,
                facecolor=color,
                lw=pixelToPoint(0.5, self.dpi),
                edgecolor="#999999",
            )
            slices.append(w)
            self.ax.add_patch(w)
            w.set_label(label)

            if shadow:
                # make sure to add a shadow after the call to
                # add_patch so the figure and transform props will be
                # set
                shad = Shadow(w, -0.02, -0.02)
                shad.set_zorder(0.9 * w.get_zorder())
                self.ax.add_patch(shad)

            if plot_axis_labels:
                if frac > 0.03:
                    xt = x + 1.05 * radius * math.cos(thetam)
                    yt = y + 1.05 * radius * math.sin(thetam)

                    thetam %= 2 * math.pi

                    if 0 < thetam and thetam < math.pi:
                        valign = "bottom"
                    elif thetam == 0 or thetam == math.pi:
                        valign = "center"
                    else:
                        valign = "top"

                    if thetam > math.pi / 2.0 and thetam < 3.0 * math.pi / 2.0:
                        halign = "right"
                    elif thetam == math.pi / 2.0 or thetam == 3.0 * math.pi / 2.0:
                        halign = "center"
                    else:
                        halign = "left"

                    t = self.ax.text(
                        xt,
                        yt,
                        label,
                        size=pixelToPoint(self.prefs["subtitle_size"], self.dpi),
                        horizontalalignment=halign,
                        verticalalignment=valign,
                    )

                    t.set_fontname(self.prefs["font"])
                    t.set_fontsize(pixelToPoint(self.prefs["text_size"], self.dpi))

                    texts.append(t)

                if autopct is not None:
                    xt = x + pctdistance * radius * math.cos(thetam)
                    yt = y + pctdistance * radius * math.sin(thetam)
                    if isinstance(autopct, str):
                        s = autopct % (100.0 * frac)
                    elif callable(autopct):
                        s = autopct(100.0 * frac)
                    else:
                        raise TypeError("autopct must be callable or a format string")

                    t = self.ax.text(xt, yt, s, horizontalalignment="center", verticalalignment="center")

                    t.set_fontname(self.prefs["font"])
                    t.set_fontsize(pixelToPoint(self.prefs["text_size"], self.dpi))

                    autotexts.append(t)

            theta1 = theta2
            i += 1

        self.legendData.reverse()

        self.ax.set_xlim((-1.25, 1.25))
        self.ax.set_ylim((-1.25, 1.25))
        self.ax.set_axis_off()

        if autopct is None:
            return slices, texts
        else:
            return slices, texts, autotexts

    min_amount = 0.1

    def getLegendData(self):

        return self.legendData

    def draw(self):

        self.ylabel = ""
        self.prefs["square_axis"] = True
        PlotBase.draw(self)

        def my_display(x):
            if x > 100 * self.min_amount:
                return "%.1f" % x + "%"
            else:
                return ""

        nLabels = self.pdata.getNumberOfLabels()
        explode = [0.0] * nLabels
        if nLabels > 0:
            explode[0] = 0.1
        self.wedges, text_labels, percent = self.pie(explode=explode, autopct=my_display)
