# ===============================================================================
# Copyright 2012 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.
# ===============================================================================

# ============= enthought library imports =======================
from __future__ import absolute_import
from traits.api import HasTraits, Instance, DelegatesTo, Button, List, Any, Float
from traitsui.api import View, Item, VGroup, HGroup, Group, spring, TabularEditor

# ============= standard library imports ========================
import pickle
import os
from numpy import polyval

# ============= local library imports  ==========================
from pychron.managers.manager import Manager
from pychron.database.selectors.power_calibration_selector import (
    PowerCalibrationSelector,
)
from pychron.database.adapters.power_calibration_adapter import PowerCalibrationAdapter
from pychron.paths import paths
from pychron.graph.graph import Graph
from pychron.hardware.meter_calibration import MeterCalibration

"""
use a dbselector to select data
"""


class BoundsSelector(HasTraits):
    graph = Instance(Graph)

    def traits_view(self):
        v = View(
            Item("graph", show_label=False, style="custom"),
            buttons=["OK", "Cancel"],
            kind="livemodal",
        )
        return v


class CompositeCalibrationManager(Manager):
    db = Instance(PowerCalibrationAdapter)
    selector = Instance(PowerCalibrationSelector)

    append = Button
    replace = Button
    load_graph = Button
    save = Button

    selected_calibrations = List
    selected = Any

    results = DelegatesTo("selector")

    graph = Instance(Graph)

    dclicked = Any

    parent_name = "FusionsDiode"

    power = Float
    input = Float

    def _power_changed(self):
        pc = self._load_calibration()
        pc
        if pc is not None:
            self.input, _ = pc.get_input(self.power)

    def _load_calibration(self):
        try:
            p = self._get_calibration_path()
            with open(p, "rb") as f:
                pc = pickle.load(f)
        except:
            return

        return pc

    def _dclicked_changed(self):
        s = self.selected
        if s is not None:
            s.bounds = None
            s.load_graph()
            s.graph.add_range_selector()

            bc = BoundsSelector(graph=s.graph)

            info = bc.edit_traits()
            if info.result:
                bounds = s.graph.plots[0].default_index.metadata["selections"]
                s.bounds = bounds
                s.calibration_bounds = (
                    polyval(s.coefficients, bounds[0]),
                    polyval(s.coefficients, bounds[1]),
                )

    def _append_fired(self):
        s = self.selector.selected
        if s is not None:
            for si in s:
                trs = list(si.traits().keys()).remove("graph")
                self.selected_calibrations.append(si.clone_traits(traits=trs))

    def _replace_fired(self):
        s = self.selector.selected
        trs = list(s.traits().keys()).remove("graph")
        self.selected_calibrations = s.clone_traits(traits=trs)

    def _save_fired(self):
        self._dump_calibration()

    def _dump_calibration(self):
        pc = MeterCalibration()
        coeffs = []
        bounds = []
        for s in self.selected_calibrations:
            coeffs.append(s.coefficients)
            bounds.append(s.calibration_bounds)
        pc.coefficients = coeffs
        pc.bounds = bounds

        p = self._get_calibration_path()
        self.info("saving calibration to {}".format(p))
        with open(p, "wb") as f:
            pickle.dump(pc, f)

    def _get_calibration_path(self):
        p = os.path.join(
            paths.hidden_dir, "{}_power_calibration".format(self.parent_name)
        )
        return p

    def _load_graph_fired(self):

        g = self.graph
        g.clear()
        #        g.new_plot(zoom=True, pan=True,
        #                   padding=[40, 10, 10, 40]
        #                   )
        has_bounds = False
        for i, s in enumerate(self.selected_calibrations):
            if s.bounds:
                has_bounds = True
            elif has_bounds:
                g.clear()
                self._plot_factory(g)
                self.warning_dialog("{} does not have its bounds set".format(s.rid))
                break

            s.load_graph(graph=g, new_plot=i == 0)

        g.redraw()

    def traits_view(self):
        selector_grp = Group(Item("selector", style="custom", show_label=False))
        transfer_grp = VGroup(
            spring,
            VGroup(Item("append", show_label=False), Item("replace", show_label=False)),
            spring,
        )
        editor = TabularEditor(
            adapter=self.selector.tabular_adapter(),
            editable=False,
            dclicked="object.dclicked",
            selected="object.selected",
        )
        selected_grp = Item("selected_calibrations", editor=editor, show_label=False)
        data_tab = Group(
            HGroup(selector_grp, transfer_grp, selected_grp),
            show_border=True,
            label="Data",
        )

        process_tab = Group(
            HGroup(
                Item("power"),
                Item("input", format_str="    %0.3f   ", style="readonly"),
                spring,
                Item("save", show_label=False),
                Item("load_graph", show_label=False),
            ),
            Item("graph", style="custom", show_label=False),
            show_border=True,
            label="Process",
        )

        v = View(
            VGroup(data_tab, process_tab),
            resizable=True,
            title="Composite {} Power Calibration".format(self.parent_name),
        )
        return v

    def _graph_default(self):
        g = Graph(
            container_dict={
                #                                  'fill_padding':True,
                #                                  'bgcolor':'red',
                "padding": 5
            }
        )
        self._plot_factory(g)
        return g

    def _plot_factory(self, graph):
        graph.new_plot(
            zoom=True,
            pan=True,
            padding=[50, 10, 10, 40],
            xtitle="Setpoint (%)",
            ytitle="Measured Power (W)",
        )

    def _db_default(self):

        if self.parent_name == "FusionsDiode":
            name = paths.diodelaser_db
        else:
            name = paths.co2laser_db
        db = PowerCalibrationAdapter(name=name, kind="sqlite")
        db.connect()
        return db

    def _selector_default(self):
        return self.db._selector_factory()


if __name__ == "__main__":
    ccm = CompositeCalibrationManager()
    ccm.configure_traits()
# ============= EOF =============================================

[(43, 'traits.api.Instance', 'Instance', (['Graph'], {}), False, 'from traits.api import HasTraits, Instance, DelegatesTo, Button, List, Any, Float\n'), (55, 'traits.api.Instance', 'Instance', (['PowerCalibrationAdapter'], {}), False, 'from traits.api import HasTraits, Instance, DelegatesTo, Button, List, Any, Float\n'), (56, 'traits.api.Instance', 'Instance', (['PowerCalibrationSelector'], {}), False, 'from traits.api import HasTraits, Instance, DelegatesTo, Button, List, Any, Float\n'), (66, 'traits.api.DelegatesTo', 'DelegatesTo', (['"""selector"""'], {}), False, 'from traits.api import HasTraits, Instance, DelegatesTo, Button, List, Any, Float\n'), (68, 'traits.api.Instance', 'Instance', (['Graph'], {}), False, 'from traits.api import HasTraits, Instance, DelegatesTo, Button, List, Any, Float\n'), (127, 'pychron.hardware.meter_calibration.MeterCalibration', 'MeterCalibration', ([], {}), False, 'from pychron.hardware.meter_calibration import MeterCalibration\n'), (181, 'traitsui.api.Item', 'Item', (['"""selected_calibrations"""'], {'editor': 'editor', 'show_label': '(False)'}), False, 'from traitsui.api import View, Item, VGroup, HGroup, Group, spring, TabularEditor\n'), (209, 'pychron.graph.graph.Graph', 'Graph', ([], {'container_dict': "{'padding': 5}"}), False, 'from pychron.graph.graph import Graph\n'), (234, 'pychron.database.adapters.power_calibration_adapter.PowerCalibrationAdapter', 'PowerCalibrationAdapter', ([], {'name': 'name', 'kind': '"""sqlite"""'}), False, 'from pychron.database.adapters.power_calibration_adapter import PowerCalibrationAdapter\n'), (47, 'traitsui.api.Item', 'Item', (['"""graph"""'], {'show_label': '(False)', 'style': '"""custom"""'}), False, 'from traitsui.api import View, Item, VGroup, HGroup, Group, spring, TabularEditor\n'), (139, 'pickle.dump', 'pickle.dump', (['pc', 'f'], {}), False, 'import pickle\n'), (169, 'traitsui.api.Item', 'Item', (['"""selector"""'], {'style': '"""custom"""', 'show_label': '(False)'}), False, 'from traitsui.api import View, Item, VGroup, HGroup, Group, spring, TabularEditor\n'), (183, 'traitsui.api.HGroup', 'HGroup', (['selector_grp', 'transfer_grp', 'selected_grp'], {}), False, 'from traitsui.api import View, Item, VGroup, HGroup, Group, spring, TabularEditor\n'), (196, 'traitsui.api.Item', 'Item', (['"""graph"""'], {'style': '"""custom"""', 'show_label': '(False)'}), False, 'from traitsui.api import View, Item, VGroup, HGroup, Group, spring, TabularEditor\n'), (202, 'traitsui.api.VGroup', 'VGroup', (['data_tab', 'process_tab'], {}), False, 'from traitsui.api import View, Item, VGroup, HGroup, Group, spring, TabularEditor\n'), (87, 'pickle.load', 'pickle.load', (['f'], {}), False, 'import pickle\n'), (172, 'traitsui.api.Item', 'Item', (['"""append"""'], {'show_label': '(False)'}), False, 'from traitsui.api import View, Item, VGroup, HGroup, Group, spring, TabularEditor\n'), (172, 'traitsui.api.Item', 'Item', (['"""replace"""'], {'show_label': '(False)'}), False, 'from traitsui.api import View, Item, VGroup, HGroup, Group, spring, TabularEditor\n'), (190, 'traitsui.api.Item', 'Item', (['"""power"""'], {}), False, 'from traitsui.api import View, Item, VGroup, HGroup, Group, spring, TabularEditor\n'), (191, 'traitsui.api.Item', 'Item', (['"""input"""'], {'format_str': '"""    %0.3f   """', 'style': '"""readonly"""'}), False, 'from traitsui.api import View, Item, VGroup, HGroup, Group, spring, TabularEditor\n'), (193, 'traitsui.api.Item', 'Item', (['"""save"""'], {'show_label': '(False)'}), False, 'from traitsui.api import View, Item, VGroup, HGroup, Group, spring, TabularEditor\n'), (194, 'traitsui.api.Item', 'Item', (['"""load_graph"""'], {'show_label': '(False)'}), False, 'from traitsui.api import View, Item, VGroup, HGroup, Group, spring, TabularEditor\n'), (107, 'numpy.polyval', 'polyval', (['s.coefficients', 'bounds[0]'], {}), False, 'from numpy import polyval\n'), (108, 'numpy.polyval', 'polyval', (['s.coefficients', 'bounds[1]'], {}), False, 'from numpy import polyval\n')]