"""
This is a demonstration file to explain how to
use a contextual generic menu item.

#. Import a dataset;
#. Create a ROI having the same shape as the dataset;
#. When selecting exactly 1 dataset and 1 ROI and doing a right-click on it,
   the contextual menu will contain the menu item named *Demo: overwrite channel with ROI*.
   If these objects have the same shape (size, spacing, direction), this menu item will be enabled.
   When clicking on that menu item, every painted pixel of the ROI will put a value of 0 in the dataset.

:author: ORS Team
:contact: http://theobjects.com
:email: info@theobjects.com
:organization: Object Research Systems (ORS), Inc.
:address: 760 St-Paul West, suite 101, Montréal, Québec, Canada, H3C 1M4
:copyright: Object Research Systems (ORS), Inc. All rights reserved 2020.
:date: Sep 28 2017 14:04
:dragonflyVersion: 3.1.0.307 (D)
:UUID: b311eb5ea47711e7b3e8448a5b5d70c0
"""

__version__ = '1.0.0'

from ORSModel import Channel, ROI
from ORSServiceClass.menuItems.contextualMenuItem import ContextualMenuItem
from ORSServiceClass.actionAndMenu.menu import Menu
from ORSServiceClass.decorators.infrastructure import interfaceMethod
from OrsHelpers.ListHelper import ListHelper


class DemoGenericMenuItemContextual_b311eb5ea47711e7b3e8448a5b5d70c0(ContextualMenuItem):

    @classmethod
    def getIsSelectionValid(cls, aCollectionOfObjects):
        """
        :param aCollectionOfObjects: a list of objects currently being selected, i.e. on which the menu item could be applied.
        :return: if True, the menu item will be displayed.
        """
        
        # The selection should be made of one Channel and one ROI,
        # no matter in what order they were selected.
        if aCollectionOfObjects is None or len(aCollectionOfObjects) != 2:
            return False

        aChannel, aROI = cls._getChannelAndROIFromSelection(aCollectionOfObjects)

        return aChannel is not None and aROI is not None

    @classmethod
    def _getChannelAndROIFromSelection(cls, aCollectionOfObjects):
        aChannel = None
        aROI = None
        for anObject in aCollectionOfObjects:
            if isinstance(anObject, Channel):
                aChannel = anObject
            elif isinstance(anObject, ROI):
                aROI = anObject
        return aChannel, aROI

    @classmethod
    def getMenuItemForSelection(cls, aCollectionOfObjects):
        """
        Returns the menu item
        :param aCollectionOfObjects: a list of objects currently being selected, i.e. on which the menu item will be applied.
        :return: Menu
        """

        # Using the "enabled" field of the Menu so that the menu item will still be visible,
        # but disabled if the dataset and the ROI don't have the same shape.
        aChannel, aROI = cls._getChannelAndROIFromSelection(aCollectionOfObjects)
        channelAndROIHaveTheSameShape = aChannel.getHasSameShape(aROI)

        collectionString = ListHelper.asPythonCollectionString(aCollectionOfObjects)
        myMenu = Menu(title='Demo: overwrite channel with ROI',
                      id_='DemoGenericMenuItemContextual_b311eb5ea47711e7b3e8448a5b5d70c0',
                      section='DemoGenericMenuItemContextual',
                      action='DemoGenericMenuItemContextual_b311eb5ea47711e7b3e8448a5b5d70c0.menuItemEntryPoint({collection})'.format(collection=str(collectionString)),
                      enabled=channelAndROIHaveTheSameShape)
        return myMenu

    @classmethod
    def menuItemEntryPoint(cls, collectionString):
        """
        Will be executed when the menu item is selected.
        :param collectionString: a list of objects representation currently being selected, i.e. on which the menu item will be applied.
        """
        
        # aCollectionOfObjects is a Python list of objects currently being selected
        aCollectionOfObjects = ListHelper.fromPythonCollection(collectionString, asPythonList=True)

        aChannel, aROI = cls._getChannelAndROIFromSelection(aCollectionOfObjects)

        # aChannel and aROI are not supposed to be None, since the current method
        # is called only when "getIsSelectionValid" returns True.
        cls.overwriteChannelWithROI(aChannel, aROI)

    # Using an interfaceMethod to log this call
    @classmethod
    @interfaceMethod
    def overwriteChannelWithROI(cls, aChannel, aROI):
        """
        Overwrites a channel using a ROI
        as a mask.

        The inputs (channel and ROI) must have the same shape.

        :param aChannel: dataset to overwrite
        :type aChannel: ORSModel.ors.Channel
        :param aROI: mask where the writing will be done
        :type aROI: ORSModel.ors.ROI
        """

        # Validation of the inputs is important to do in this method
        # because the call may come from any location (not only from this file).
        # For example, it be written in a macro file when performing a macro recording.

        if aChannel is None or aROI is None:
            return

        channelAndROIHaveTheSameShape = aChannel.getHasSameShape(aROI)
        if not channelAndROIHaveTheSameShape:
            return

        aChannel.overwriteValueWithROI(aROI, 0)
        aChannel.setDataDirty()

