from reportlab.graphics.charts.barcharts import VerticalBarChart, HorizontalBarChart
from reportlab.graphics.charts.doughnut import Doughnut
from reportlab.graphics.charts.linecharts import HorizontalLineChart
from reportlab.graphics.charts.piecharts import Pie, LegendedPie
from reportlab.graphics.widgets.markers import makeMarker

from .util import getColor


def set_properties(obj, data, prop_map):

    for key, fnc in prop_map:
        if key in data:
            try:
                value = fnc(data[key])

                if value is not None:
                    obj.__setattr__(key, value)
            except:
                continue


class Props:

    def __init__(self, instance):
        self.prop_map = [("x", int), ("y", int), ("width", int), ("height", int), ("data", lambda x: x),
                         ("labels", lambda x: instance.assign_labels(x))]
        self.prop_map_title = [("x", int), ("y", int), ("_text", str)]
        self.prop_map_legend = [("x", int), ("y", int), ("deltax", int), ("alignment", str), ("boxAnchor", str),
                                ("fontSize", int), ("strokeWidth", int), ("dy", int), ("dx", int), ("dxTextSpace", int),
                                ("deltay", int), ("columnMaximum", int), ("variColumn", int), ("deltax", int),
                                ("fontName", str), ("colorNamePairs", list)]
        self.prop_map_legend1 = [("x", int), ("y", int)]
        self.prop_map_bars = [("strokeWidth", int)]
        self.prop_map_barLabels = [("nudge", int), ("fontSize", int), ("fontName", str)]
        self.prop_map_categoryAxis = [("visibleTicks", int), ("strokeWidth", int), ("tickShift", int),
                                      ("labelAxisMode", str)]
        self.prop_map_categoryAxis_labels = [("angle", int), ("dy", int), ("fontSize", int),
                                             ("boxAnchor", str), ("fontName", str), ("textAnchor", str)]
        self.prop_map_slices = [("strokeWidth", int), ("labelRadius", float), ("poput", int), ("fontName", str),
                                ("fontSize", int), ("strokeDashArray", str)]

    def add_prop(self, prop_map, data):
        prop_map += data


class BaseChart:

    def set_legend(self, data, legend, props=None):
        if props is None:
            props = Props(self)
        set_properties(legend, data, props.prop_map_legend)
        return legend

    def load_data_legend(self, data, legend):
        legend.colorNamePairs = []
        color = self.get_colors()

        for x, obj in enumerate(data['data']):
            if isinstance(obj, list):
                for y, value in enumerate(obj):
                    if color:
                        if data['type'] == "doughnut":
                            legend.colorNamePairs.append((color[x], (data['labels'][y], " ", str(value))))
                        else:
                            legend.colorNamePairs.append((color[y], (data['labels'][y], " ", str(value))))
            elif color:
                    legend.colorNamePairs.append((color[x], (data['labels'][x], " ", str(obj))))

    def set_title_properties(self, data, title, props=None):
        if props is None:
            props = Props(self)
        set_properties(title, data, props.prop_map_title)
        return title

    def set_properties(self, data, props=None):
        if props is None:
            props = Props(self)
        set_properties(self, data, props.prop_map)

    def get_colors(self):
        colors = []
        return colors


class BaseBarChart(BaseChart):

    def __init__(self):
        super().__init__()

    def set_properties(self, data, props=None):
        props = Props(self)
        props.add_prop(props.prop_map, [("barWidth", str)])
        props.add_prop(props.prop_map, [("barSpacing", str)])
        props.add_prop(props.prop_map, [("barLabelFormat", str)])
        props.add_prop(props.prop_map, [("strokeColor", getColor)])
        props.add_prop(props.prop_map, [("groupSpacing", int)])
        super().set_properties(data, props=props)

        if "bars" in data:
            self.set_bars(data["bars"], props=props)

        if "barLabels" in data:
            self.set_barLabels(data["barLabels"], props=props)

        if "categoryAxis" in data:
            self.set_categoryAxis(data["categoryAxis"], props=props)

            if "labels" in data['categoryAxis']:
                self.set_categoryAxis_labels(data["categoryAxis"]["labels"], props=props)

    def assign_labels(self, labels):
        self.categoryAxis.categoryNames = labels

    def set_bars(self, data, props=None):
        if props is None:
            props = Props(self)
        props.add_prop(props.prop_map_bars, [("strokeColor", getColor)])
        set_properties(self.bars, data, props.prop_map_bars)


    def set_barLabels(self, data, props=None):
        if props is None:
            props = Props(self)
        set_properties(self.barLabels, data, props.prop_map_barLabels)

    def set_categoryAxis(self, data, props=None):
        if props is None:
            props = Props(self)
        props.add_prop(props.prop_map_categoryAxis, [("strokeColor", getColor)])
        set_properties(self.categoryAxis, data, props.prop_map_categoryAxis)

    def set_categoryAxis_labels(self, data, props=None):
        if props is None:
            props = Props(self)
        props.add_prop(props.prop_map_categoryAxis_labels, [("fillColor", getColor)])
        set_properties(self.categoryAxis.labels, data, props.prop_map_categoryAxis_labels)


class HorizontalBar(HorizontalBarChart, BaseBarChart):
    pass


class VerticalBar(VerticalBarChart, BaseBarChart):
    pass


class HorizontalLine(HorizontalLineChart, BaseChart):

    def __init__(self):
        super().__init__()

    def assign_labels(self, labels):
        self.categoryAxis.categoryNames = labels

    def set_properties(self, data, props=None):
        props = Props(self)
        props.add_prop(props.prop_map, [("fillColor", getColor)])
        props.add_prop(props.prop_map, [("lineLabelFormat", str)])
        props.add_prop(props.prop_map, [("strokeColor", int)])
        props.add_prop(props.prop_map, [("joinedLines", int)])
        props.add_prop(props.prop_map, [("marker", self.fill_marker)])
        super().set_properties(data, props=props)

    def fill_marker(self, fill_type):

        for x in range(len(self.data)):
            self.lines[x].symbol = makeMarker(fill_type)

    def get_colors(self):
        colors = []
        return colors


class PieChart(Pie, BaseChart):

    def __init__(self):
        super().__init__()

    def set_properties(self, data, props=None):
        props = Props(self)
        props.add_prop(props.prop_map, [("sideLabels", int)])
        props.add_prop(props.prop_map, [("simpleLabels", int)])
        props.add_prop(props.prop_map, [("sideLabelsOffset", int)])
        props.add_prop(props.prop_map, [("startAngle", int)])
        props.add_prop(props.prop_map, [("orderMode", str)])
        props.add_prop(props.prop_map, [("direction", str)])
        super().set_properties(data, props=props)

        if "slices" in data:
            self.set_slices(data['slices'], props=props)

    def assign_labels(self, labels):
        self.labels = labels

    def set_slices(self, data, props=None):
        if props is None:
            props = Props(self)
        props.add_prop(props.prop_map_slices, [("strokeColor", getColor)])
        props.add_prop(props.prop_map_slices, [("fillColor", getColor)])
        set_properties(self.slices, data, props.prop_map_slices)

    def get_colors(self):
        colors_list = []
        for x, obj in enumerate(self.data):
            colors_list.append(self.slices[x].fillColor)
        return colors_list


class LegendedPieChart(LegendedPie, BaseChart):

    def __init__(self):
        super().__init__()
        self.legend1.x = 350
        self.legend1.y = 150

    def set_properties(self, data, props=None):
        props = Props(self)
        props.add_prop(props.prop_map, [("legend_data", list)])
        super().set_properties(data, props=props)

        if "legend1" in data:
            self.set_legend1(self.legend1, data['legend1'], props=props)

    def set_legend1(self, obj, data, props=None):
        if props is None:
            props = Props(self)
        set_properties(obj, data, props.prop_map_legend1)

    def assign_labels(self, labels):
        self.legend_names = labels


class DoughnutChart(Doughnut, BaseChart):

    def __init__(self):
        super().__init__()

    def assign_labels(self, labels):
        self.labels = labels

    def get_colors(self):
        colors = []
        for x, obj in enumerate(self.data):
            colors.append(self.slices[x].fillColor)
        return colors
