"""
Class which embellishes the DataCollectionView with buttons and actions for
editing the data collection
"""
import operator

from ...external.qt.QtGui import (QWidget, QMenu,
                                  QAction, QKeySequence, QFileDialog)


from ...external.qt.QtCore import Qt, Signal, QObject

from ..ui.layertree import Ui_LayerTree

from ... import core

from ..link_editor import LinkEditor
from .. import qtutil
from ..qtutil import get_icon, nonpartial
from .custom_component_widget import CustomComponentWidget
from ..actions import act as _act
from ...core.edit_subset_mode import AndMode, OrMode, XorMode, AndNotMode
from .subset_facet import SubsetFacet


@core.decorators.singleton
class Clipboard(object):

    def __init__(self):
        self.contents = None


class LayerAction(QAction):
    _title = ''
    _icon = None
    _tooltip = None
    _enabled_on_init = False
    _shortcut = None
    _shortcut_context = Qt.WidgetShortcut

    def __init__(self, layer_tree_widget):
        self._parent = layer_tree_widget.layerTree
        super(LayerAction, self).__init__(self._title.title(), self._parent)
        self._layer_tree = layer_tree_widget
        if self._icon:
            self.setIcon(get_icon(self._icon))
        if self._tooltip:
            self.setToolTip(self._tooltip)
        self.setEnabled(self._enabled_on_init)
        if self._shortcut_context is not None:
            self.setShortcutContext(self._shortcut_context)
        if self._shortcut:
            self.setShortcut(self._shortcut)
        self._parent.addAction(self)
        self._connect()

    def _connect(self):
        self._parent.selection_changed.connect(
            self.update_enabled)
        self.triggered.connect(nonpartial(self._do_action))

    def selected_layers(self):
        return self._layer_tree.selected_layers()

    @property
    def data_collection(self):
        return self._layer_tree.data_collection

    def update_enabled(self):
        enabled = self._can_trigger()
        self.setEnabled(enabled)
        self.setVisible(enabled)

    def single_selection(self):
        return len(self.selected_layers()) == 1

    def single_selection_subset(self):
        layers = self.selected_layers()
        if len(layers) != 1:
            return False
        return isinstance(layers[0], core.Subset)

    def single_selection_subset_group(self):
        layers = self.selected_layers()
        if len(layers) != 1:
            return False
        return isinstance(layers[0], core.SubsetGroup)

    def _can_trigger(self):
        raise NotImplementedError

    def _do_action(self):
        raise NotImplementedError


class PlotAction(LayerAction):

    """Visualize the selection. Requires GlueApplication"""
    _title = "Plot Data"
    _tooltip = "Make a plot of this selection"

    def __init__(self, tree, app):
        super(PlotAction, self).__init__(tree)
        self.app = app

    def _can_trigger(self):
        return self.single_selection()

    def _do_action(self):
        assert self._can_trigger()
        data = self.selected_layers()[0].data
        self.app.choose_new_data_viewer(data)


class FacetAction(LayerAction):

    """Add a sequence of subsets which facet a ComponentID"""
    _title = "Create faceted subsets"
    _tooltip = "Create faceted subsets"

    def _can_trigger(self):
        return len(self._layer_tree.data_collection) > 0

    def _do_action(self):
        layers = self.selected_layers()
        default = layers[0].data if len(layers) > 0 else None
        SubsetFacet.facet(self._layer_tree.data_collection,
                          parent=self._layer_tree, default=default)


class NewAction(LayerAction):
    _title = "New Subset"
    _tooltip = "Create a new subset"
    _icon = "glue_subset"
    _shortcut = QKeySequence('Ctrl+Shift+N')

    def _can_trigger(self):
        return len(self.data_collection) > 0

    def _do_action(self):
        assert self._can_trigger()
        self.data_collection.new_subset_group()



class ClearAction(LayerAction):
    _title = "Clear subset"
    _tooltip = "Clear current subset"
    _shortcut = QKeySequence('Ctrl+K')

    def _can_trigger(self):
        return self.single_selection_subset_group()

    def _do_action(self):
        assert self._can_trigger()
        subset
 = self.selected_layers()[0]
        subset.subset_state = core.subset.SubsetState()


class DeleteAction(LayerAction):
    _title = "Delete Layer"
    _tooltip = "Delete the selected data and/or subset Groups"
    _shortcut = QKeySequence(Qt.Key_Backspace)

    def _can_trigger(self):
        selection = self.selected_layers()
        return all(isinstance(s, (core.Data, core.SubsetGroup))
                   for s in selection)

    def _do_action(self):
        assert self._can_trigger()
        selection = self.selected_layers()
        for s in selection:
            if isinstance(s, core.Data):
                self._layer_tree.data_collection.remove(s)
            else:
                assert isinstance(s, core.SubsetGroup)
                self._layer_tree.data_collection.remove_subset_group(s)


class LinkAction(LayerAction):
    _title = "Link Data"
    _tooltip = "Define links between data sets"
    _data_link_message = "Define links between data sets"
    _icon = "glue_link"

    def __init__(self, *args, **kwargs):
        super(LinkAction, self).__init__(*args, **kwargs)
        self._link_icon = get_icon(self._icon)
        self._unlink_icon = get_icon('glue_unlink')

    def _can_trigger(self):
        return len(self.data_collection) > 0

    def _do_action(self):
        LinkEditor.update_links(self.data_collection)


class SaveAction(LayerAction):
    _title = "Save subset"
    _tooltip = "Save the mask for this subset to a file"

    def _can_trigger(self):
        return self.single_selection_subset()

    def _do_action(self):
        assert self._can_trigger()
        subset = self.selected_layers()[0]
        save_subset(subset)


class CopyAction(LayerAction):
    _title = "Copy subset"
    _tooltip = "Copy the definition for the selected subset"
    _shortcut = QKeySequence.Copy

    def _can_trigger(self):
        return self.single_selection_subset_group()

    def _do_action(self):
        assert self._can_trigger()
        subset = self.selected_layers()[0]
        Clipboard().contents = subset.subset_state


class PasteAction(LayerAction):
    _title = "Paste subset"
    _tooltip = "Overwrite selected subset with contents from clipboard"
    _shortcut = QKeySequence.Paste

    def _can_trigger(self):
        if not self.single_selection_subset_group():
            return False
        cnt = Clipboard().contents
        if not isinstance(cnt, core.subset.SubsetState):
            return False
        return True

    def _do_action(self):
        assert self._can_trigger()
        layer = self.selected_layers()[0]
        layer.paste(Clipboard().contents)


class PasteSpecialAction(PasteAction):
    _title = "Paste Special..."
    _tooltip = "Paste with boolean logic"
    _shortcut = None

    def __init__(self, *args, **kwargs):
        super(PasteSpecialAction, self).__init__(*args, **kwargs)
        self.setMenu(self.menu())

    def menu(self):
        m = QMenu()

        a = QAction("Or", m)
        a.setIcon(get_icon('glue_or'))
        a.triggered.connect(nonpartial(self._paste, OrMode))
        m.addAction(a)

        a = QAction("And", m)
        a.setIcon(get_icon('glue_and'))
        a.triggered.connect(nonpartial(self._paste, AndMode))
        m.addAction(a)

        a = QAction("XOR", m)
        a.setIcon(get_icon('glue_xor'))
        a.triggered.connect(nonpartial(self._paste, XorMode))
        m.addAction(a)

        a = QAction("Not", m)
        a.setIcon(get_icon('glue_andnot'))
        a.triggered.connect(nonpartial(self._paste, AndNotMode))
        m.addAction(a)
        return m

    def _paste(self, mode):
        if not self._can_trigger():
            return
        assert self._can_trigger()
        layer = self.selected_layers()[0]
        mode(layer, Clipboard().contents)

    def _do_action(self):
        pass


class Inverter(LayerAct