# ===============================================================================
# Copyright 2013 Jake Ross
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ===============================================================================
from __future__ import absolute_import
from __future__ import print_function

from chaco.label import Label
from six.moves import map

from pychron.core.ui import set_qt

set_qt()

# ============= enthought library imports =======================
from chaco.abstract_overlay import AbstractOverlay
from kiva.fonttools import str_to_font
from traits.api import HasTraits, Instance, Float, File, Property, Str, List
from traitsui.api import View, Controller, UItem
from chaco.api import OverlayPlotContainer
from enable.component_editor import ComponentEditor
from pyface.api import FileDialog, OK

# ============= standard library imports ========================
from lxml.etree import ElementTree, Element
from chaco.plot import Plot
from chaco.array_plot_data import ArrayPlotData
from numpy import linspace, cos, sin, pi
import os
import csv
from chaco.data_label import DataLabel
from pychron.paths import paths
from chaco.plot_graphics_context import PlotGraphicsContext
from traitsui.menu import Action
import math
from pychron.core.helpers.strtools import to_bool


# ============= local library imports  ==========================
class myDataLabel(DataLabel):
    show_label_coords = False
    marker_visible = False
    label_position = "center"
    border_visible = False


class LabelsOverlay(AbstractOverlay):
    labels = List

    def overlay(self, other_component, gc, view_bounds=None, mode="normal"):
        with gc:
            gc.set_font(str_to_font(None, None, "7"))

            for x, y, l in self.labels:
                ll = Label(x=x, y=y, text=l, font="modern 7")
                w, h = ll.get_bounding_box(gc)
                x, y = other_component.map_screen([(x, y)])[0]
                gc.set_text_position(x - w / 2.0, y + 5)
                gc.show_text(l)


class RotatingContainer(OverlayPlotContainer):
    rotation = Float(0)

    def _draw(self, gc, *args, **kw):
        with gc:
            w2 = self.width / 2
            h2 = self.height / 2
            # gc.translate_ctm(w2, h2)
            # gc.rotate_ctm(math.radians(self.rotation))
            # gc.translate_ctm(-w2, -h2)
            super(RotatingContainer, self)._draw(gc, *args, **kw)


class GraphicGeneratorController(Controller):
    def save(self, info):
        self.model.save()

    def traits_view(self):
        w, h = 750, 750
        v = View(
            UItem("srcpath"),
            # Item('rotation'),
            UItem("container", editor=ComponentEditor(), style="custom"),
            width=w + 2,
            height=h + 56,
            resizable=True,
            buttons=[Action(name="Save", action="save"), "OK", "Cancel"],
        )
        return v


class GraphicModel(HasTraits):
    srcpath = File
    xmlpath = File
    container = Instance(OverlayPlotContainer)
    name = Property
    _name = Str
    rotation = Float(enter_set=True, auto_set=False)
    initialized = False

    def _get_name(self):
        return os.path.splitext(
            self._name if self._name else os.path.basename(self.srcpath)
        )[0]

    def save(self, path=None):
        #        print self.container.bounds

        if path is None:
            dlg = FileDialog(action="save as", default_directory=paths.data_dir or "")
            if dlg.open() == OK:
                path = dlg.path

        if path is not None:
            _, tail = os.path.splitext(path)
            c = self.container
            if tail == ".pdf":
                from chaco.pdf_graphics_context import PdfPlotGraphicsContext

                gc = PdfPlotGraphicsContext(filename=path, pagesize="letter")

            else:
                if not tail in (".png", ".jpg", ".tiff"):
                    path = "{}.png".format(path)

                gc = PlotGraphicsContext((int(c.outer_width), int(c.outer_height)))
                #            c.use_backbuffer = False

            # for ci in c.components:
            #     try:
            #         ci.x_axis.visible = False
            #         ci.y_axis.visible = False
            #     except Exception:
            #         pass

            # c.use_backbuffer = False
            from reportlab.lib.pagesizes import LETTER

            c.do_layout(size=(LETTER[1], LETTER[1]), force=True)
            gc.render_component(c)
            #            c.use_backbuffer = True
            gc.save(path)
            self._name = os.path.basename(path)

    def load(self, path):
        parser = ElementTree(file=open(path, "r"))
        circles = parser.find("circles")
        outline = parser.find("outline")

        bb = outline.find("bounding_box")
        bs = bb.find("width"), bb.find("height")
        w, h = [float(b.text) for b in bs]

        use_label = parser.find("use_label")
        if use_label is not None:
            use_label = to_bool(use_label.text.strip())
        else:
            use_label = True

        data = ArrayPlotData()
        p = Plot(data=data, padding=10)
        p.x_grid.visible = False
        p.y_grid.visible = False

        p.x_axis.visible = False
        p.y_axis.visible = False

        p.x_axis.title = "X cm"
        p.y_axis.title = "Y cm"

        p.index_range.low_setting = -w / 2
        p.index_range.high_setting = w / 2

        p.value_range.low_setting = -h / 2
        p.value_range.high_setting = h / 2

        thetas = linspace(0, 2 * pi)

        radius = circles.find("radius").text
        radius = float(radius)

        face_color = circles.find("face_color")
        if face_color is not None:
            face_color = face_color.text
        else:
            face_color = "white"
        labels = []
        for i, pp in enumerate(circles.findall("point")):
            x, y, l = pp.find("x").text, pp.find("y").text, pp.find("label").text

            #             print i, pp, x, y
            # load hole specific attrs
            r = pp.find("radius")
            if r is None:
                r = radius
            else:
                r = float(r.text)

            fc = pp.find("face_color")
            if fc is None:
   
             fc = face_color
            else:
                fc = fc.text

            x, y = list(map(float, (x, y)))
            xs = x + r * sin(thetas)
            ys = y + r * cos(thetas)

            xn, yn = "px{:03d}".format(i), "py{:03d}".format(i)
            data.set_data(xn, xs)
            data.set_data(yn, ys)

            plot = p.plot(
(xn, yn), face_color=fc, type="polygon")[0]
            labels.append((x, y, l))
            # if use_label:
            #     label = myDataLabel(component=plot,
            #                         data_point=(x, y),
            #                         label_text=l,
            #                         bgcolor='transparent')
            #     plot.overlays.append(label)
        if use_label:
            p.overlays.append(LabelsOverlay(component=plot, labels=labels))

        self.container.add(p)
        self.container.invalidate_and_redraw()

    def _srcpath_changed(self):

        # default_radius=radius,
        # default_bounds=bounds,
        # convert_mm=convert_mm,
        # use_label=use_label,
        # make=make,
        # rotate=rotate)
        self._reload()

    def _rotation_changed(self):
        self._reload()

    def _reload(self):
        if self.initialized:
            self.container = self._container_factory()
            print(os.path.isfile(self.srcpath), self.srcpath)
            i