# ===============================================================================
# Copyright 2013 <NAME>
#
# 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 __future__ import print_function

import os

from envisage.ui.tasks.task_extension import TaskExtension
from envisage.ui.tasks.task_factory import TaskFactory
from pyface.tasks.action.schema import SMenu
from pyface.tasks.action.schema_addition import SchemaAddition
from traits.api import List, Str

from pychron.core.helpers.filetools import glob_list_directory
from pychron.core.helpers.strtools import to_bool
from pychron.envisage.initialization.initialization_parser import InitializationParser
from pychron.envisage.tasks.base_task_plugin import BaseTaskPlugin
from pychron.envisage.tasks.list_actions import PatternAction, ShowMotionConfigureAction
from pychron.lasers.laser_managers.ilaser_manager import ILaserManager
from pychron.lasers.tasks.laser_actions import OpenPowerMapAction, OpenPatternAction, NewPatternAction, \
    LaserScriptExecuteAction
# from pychron.lasers.tasks.laser_calibration_task import LaserCalibrationTask
from pychron.paths import paths


def pattern_action(name, application, manager_name, lase=False):
    def factory():
        a = PatternAction(id='pattern.action.{}'.format(name),
                          name=name.capitalize(),
                          application=application,
                          manager_name=manager_name,
                          pattern_path=os.path.join(paths.pattern_dir, name),
                          lase=lase)
        return a

    return factory


class CoreLaserPlugin(BaseTaskPlugin):
    def _task_extensions_default(self):
        actions = [SchemaAddition(factory=OpenPowerMapAction,
                           path='MenuBar/file.menu/Open'),
                   SchemaAddition(id='Open Pattern',
                                  factory=OpenPatternAction,
                                  path='MenuBar/file.menu/Open'),
                   SchemaAddition(id='New Pattern',
                                  factory=NewPatternAction,
                                  path='MenuBar/file.menu/New')]

        return [TaskExtension(actions=actions)]


class BaseLaserPlugin(BaseTaskPlugin):
    managers = List(contributes_to='pychron.hardware.managers')
    klass = None

    # name = None

    def _service_offers_default(self):
        """
        """
        if self.klass is None:
            raise NotImplementedError

        so = self.service_offer_factory(
            protocol=ILaserManager,
            factory=self._manager_factory)
        return [so]

    def _manager_factory(self):
        """
        """

        ip = InitializationParser()
        plugin = ip.get_plugin(self.klass[1].replace('Manager', ''), category='hardware')
        mode = ip.get_parameter(plugin, 'mode')

        klass = ip.get_parameter(plugin, 'klass')
        if klass is None and mode == 'client':
            klass = 'PychronLaserManager'
            pkg = 'pychron.lasers.laser_managers.pychron_laser_manager'
            factory = __import__(pkg, fromlist=[klass])
            klassfactory = getattr(factory, klass)
        else:
            factory = __import__(self.klass[0], fromlist=[self.klass[1]])
            klassfactory = getattr(factory, self.klass[1])

        params = dict(name=self.name)
        if mode == 'client':
            try:
                tag = ip.get_parameter(plugin, 'communications', element=True)
                for attr in ['host', 'port', 'kind', 'message_frame', ('use_end', to_bool)]:
                    func = None
                    if isinstance(attr, tuple):
                        attr, func = attr

                    try:
                        elem = tag.find(attr)
                        if elem is not None:
                            v = elem.text.strip()
                            if func:
                                v = func(v)

                            params[attr] = v
                        else:
                            self.debug('No communications attribute {}'.format(attr))
                    except Exception as e:
                        print('client comms fail a', attr, e)
            except Exception as e:
                print('client comms fail b', e)

        m = klassfactory(**params)
        m.mode = mode
        m.bootstrap()
        m.plugin_id = self.id
        m.bind_preferences(self.id)
        return m

    def _managers_default(self):
        """
        """
        d = []

        if self.klass is not None:
            d = [dict(name=self.name,
                      plugin_name=self.name,
                      manager=self._get_manager())]

        return d

    def _get_manager(self):
        return self.application.get_service(ILaserManager, 'name=="{}"'.format(self.name))

        # def execute_pattern(self, name):
        #     self._get_manager().execute_pattern(name)
        # def _preferences_default(self):
        #     root = paths.preferences_dir
        #     path = os.path.join(root, 'preferences.ini')
        #     if not os.path.isfile(path):
        #         with open(path, 'w'):
        #             pass
        #     return ['file://{}'.format(path)]

    def _setup_pattern_extensions(self, exts, actions=None):
        if actions is None:
            actions = []

        lactions = []
        for f in glob_list_directory(paths.pattern_dir, extension='.lp', remove_extension=True):
            actions.append(SchemaAddition(id='pattern.{}'.format(f),
                                          factory=pattern_action(f, self.application, self.name),
                                          path='MenuBar/laser.menu/patterns.menu'))
            lactions.append(SchemaAddition(id='pattern.lase.{}'.format(f),
                                           factory=pattern_action(f, self.application, self.name, lase=True),
                                           path='MenuBar/laser.menu/patterns.lase.menu'))

        if actions:

            actions.insert(0, SchemaAddition(id='patterns.menu',
                                             factory=lambda: SMenu(name='Execute Patterns', id='patterns.menu'),
                                             path='MenuBar/laser.menu'))

            lactions.insert(0, SchemaAddition(id='patterns.lase.menu',
                                              factory=lambda: SMenu(name='Execute and Lase Patterns',
                                                                    id='patterns.lase.menu'),
                                              path='MenuBar/laser.menu'))

            exts.append(TaskExtension(actions=lactions))
            exts.append(TaskExtension(actions=actions))
        else:
            self.warning('no patterns scripts located in "{}"'.format(paths.pattern_dir))

    def _create_task_extensions(self):
        def efactory():
            return SMenu(id='laser.menu', name='Laser')

        actions = [SchemaAddition(id='Laser',
                                  factory=efactory,
                                  path='MenuBar',
                                  before='tools.menu',
                                  after='view.menu')]

        exts = [TaskExtension(actions=actions)]
        return exts


class FusionsPlugin(BaseLaserPlugin):
    task_name = Str
    sources = List(contributes_to='pychron.video.sources')

    def test_communication(self):
        man = self._get_manager()
        return man.test_connection()

    def _tasks_default(self):
        return [TaskFactory(id=self.id,
                            task_group='hardware',
                            factory=self._task_factory,
                            name=self.task_name,
                            image='laser',
                            accelerator=self.accelerator),
                # TaskFactory(id='pychron.laser.calibration',
                #             task_group='hardware',
                #             factory=self._calibration_task_factory,
                #             name='Laser Calibration',
                #             accelerator='Ctrl+Shift+2')
                ]

    def _sources_default(self):
        ip = InitializationParser()
        plugin = ip.get_plugin(self.task_name.replace(' ', ''),
                               category='hardware')
        source = ip.get_parameter(plugin, 'video_source')
        rs = []
        if source:
            rs = [(source, self.task_name)]
        return rs

    def _task_extensions_default(self):
        exts = self._create_task_extensions()
        actions = [SchemaAddition(factory=ShowMotionConfigureAction,
                                  path='MenuBar/laser.menu'),
                   SchemaAddition(factory=LaserScriptExecuteAction,
                                  path='MenuBar/laser.menu')]
        self._setup_pattern_extensions(exts, actions)

        return exts

# ============= EOF =============================================

# ===============================================================================
# Copyright 2013 <NAME>
#
# 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 __future__ import print_function

import os

from envisage.ui.tasks.task_extension import TaskExtension
from envisage.ui.tasks.task_factory import TaskFactory
from pyface.tasks.action.schema import SMenu
from pyface.tasks.action.schema_addition import SchemaAddition
from traits.api import List, Str

from pychron.core.helpers.filetools import glob_list_directory
from pychron.core.helpers.strtools import to_bool
from pychron.envisage.initialization.initialization_parser import InitializationParser
from pychron.envisage.tasks.base_task_plugin import BaseTaskPlugin
from pychron.envisage.tasks.list_actions import PatternAction, ShowMotionConfigureAction
from pychron.lasers.laser_managers.ilaser_manager import ILaserManager
from pychron.lasers.tasks.laser_actions import OpenPowerMapAction, OpenPatternAction, NewPatternAction, \
    LaserScriptExecuteAction
# from pychron.lasers.tasks.laser_calibration_task import LaserCalibrationTask
from pychron.paths import paths


def pattern_action(name, application, manager_name, lase=False):
    def factory():
        a = PatternAction(id='pattern.action.{}'.format(name),
                          name=name.capitalize(),
                          application=application,
                          manager_name=manager_name,
                          pattern_path=os.path.join(paths.pattern_dir, name),
                          lase=lase)
        return a

    return factory


class CoreLaserPlugin(BaseTaskPlugin):
    def _task_extensions_default(self):
        actions = [SchemaAddition(factory=OpenPowerMapAction,
                           path='MenuBar/file.menu/Open'),
                   SchemaAddition(id='Open Pattern',
                                  factory=OpenPatternAction,
                                  path='MenuBar/file.menu/Open'),
                   SchemaAddition(id='New Pattern',
                                  factory=NewPatternAction,
                                  path='MenuBar/file.menu/New')]

        return [TaskExtension(actions=actions)]


class BaseLaserPlugin(BaseTaskPlugin):
    managers = List(contributes_to='pychron.hardware.managers')
    klass = None

    # name = None

    def _service_offers_default(self):
        """
        """
        if self.klass is None:
            raise NotImplementedError

        so = self.service_offer_factory(
            protocol=ILaserManager,
            factory=self._manager_factory)
        return [so]

    def _manager_factory(self):
        """
        """

        ip = InitializationParser()
        plugin = ip.get_plugin(self.klass[1].replace('Manager', ''), category='hardware')
        mode = ip.get_parameter(plugin, 'mode')

        klass = ip.get_parameter(plugin, 'klass')
        if klass is None and mode == 'client':
            klass = 'PychronLaserManager'
            pkg = 'pychron.lasers.laser_managers.pychron_laser_manager'
            factory = __import__(pkg, fromlist=[klass])
            klassfactory = getattr(factory, klass)
        else:
            factory = __import__(self.klass[0], fromlist=[self.klass[1]])
            klassfactory = getattr(factory, self.klass[1])

        params = dict(name=self.name)
        if mode == 'client':
            try:
                tag = ip.get_parameter(plugin, 'communications', element=True)
                for attr in ['host', 'port', 'kind', 'message_frame', ('use_end', to_bool)]:
                    func = None
                    if isinstance(attr, tuple):
                        attr, func = attr

                    try:
                        elem = tag.find(attr)
                        if elem is not None:
                            v = elem.text.strip()
                            if func:
                                v = func(v)

                            params[attr] = v
                        else:
                            self.debug('No communications attribute {}'.format(attr))
                    except Exception as e:
                        print('client comms fail a', attr, e)
            except Exception as e:
                print('client comms fail b', e)

        m = klassfactory(**params)
        m.mode = mode
        m.bootstrap()
        m.plugin_id = self.id
        m.bind_preferences(self.id)
        return m

    def _managers_default(self):
        """
        """
        d = []

        if self.klass is not None:
            d = [dict(name=self.name,
                      plugin_name=self.name,
                      manager=self._get_manager())]

        return d

    def _get_manager(self):
        return self.application.get_service(ILaserManager, 'name=="{}"'.format(self.name))

        # def execute_pattern(self, name):
        #     self._get_manager().execute_pattern(name)
        # def _preferences_default(self):
        #     root = paths.preferences_dir
        #     path = os.path.join(root, 'preferences.ini')
        #     if not os.path.isfile(path):
        #         with open(path, 'w'):
        #             pass
        #     return ['file://{}'.format(path)]

    def _setup_pattern_extensions(self, exts, actions=None):
        if actions is None:
            actions = []

        lactions = []
        for f in glob_list_directory(paths.pattern_dir, extension='.lp', remove_extension=True):
            actions.append(SchemaAddition(id='pattern.{}'.format(f),
                                          factory=pattern_action(f, self.application, self.name),
                                          path='MenuBar/laser.menu/patterns.menu'))
            lactions.append(SchemaAddition(id='pattern.lase.{}'.format(f),
                                           factory=pattern_action(f, self.application, self.name, lase=True),
                                           path='MenuBar/laser.menu/patterns.lase.menu'))

        if actions:

            actions.insert(0, SchemaAddition(id='patterns.menu',
                                             factory=lambda: SMenu(name='Execute Patterns', id='patterns.menu'),
                                             path='MenuBar/laser.menu'))

            lactions.insert(0, SchemaAddition(id='patterns.lase.menu',
                                              factory=lambda: SMenu(name='Execute and Lase Patterns',
                                                                    id='patterns.lase.menu'),
                                              path='MenuBar/laser.menu'))

            exts.append(TaskExtension(actions=lactions))
            exts.append(TaskExtension(actions=actions))
        else:
            self.warning('no patterns scripts located in "{}"'.format(paths.pattern_dir))

    def _create_task_extensions(self):
        def efactory():
            return SMenu(id='laser.menu', name='Laser')

        actions = [SchemaAddition(id='Laser',
                                  factory=efactory,
                                  path='MenuBar',
                                  before='tools.menu',
                                  after='view.menu')]

        exts = [TaskExtension(actions=actions)]
        return exts


class FusionsPlugin(BaseLaserPlugin):
    task_name = Str
    sources = List(contributes_to='pychron.video.sources')

    def test_communication(self):
        man = self._get_manager()
        return man.test_connection()

    def _tasks_default(self):
        return [TaskFactory(id=self.id,
                            task_group='hardware',
                            factory=self._task_factory,
                            name=self.task_name,
                            image='laser',
                            accelerator=self.accelerator),
                # TaskFactory(id='pychron.laser.calibration',
                #             task_group='hardware',
                #             factory=self._calibration_task_factory,
                #             name='Laser Calibration',
                #             accelerator='Ctrl+Shift+2')
                ]

    def _sources_default(self):
        ip = InitializationParser()
        plugin = ip.get_plugin(self.task_name.replace(' ', ''),
                               category='hardware')
        source = ip.get_parameter(plugin, 'video_source')
        rs = []
        if source:
            rs = [(source, self.task_name)]
        return rs

    def _task_extensions_default(self):
        exts = self._create_task_extensions()
        actions = [SchemaAddition(factory=ShowMotionConfigureAction,
                                  path='MenuBar/laser.menu'),
                   SchemaAddition(factory=LaserScriptExecuteAction,
                                  path='MenuBar/laser.menu')]
        self._setup_pattern_extensions(exts, actions)

        return exts

# ============= EOF =============================================

# =============================================================================== # Copyright 2013 <NAME> # # 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 pychron.lasers.tasks.laser_calibration_task import LaserCalibrationTask # name = None # def execute_pattern(self, name): #     self._get_manager().execute_pattern(name) # def _preferences_default(self): #     root = paths.preferences_dir #     path = os.path.join(root, 'preferences.ini') #     if not os.path.isfile(path): #         with open(path, 'w'): #             pass #     return ['file://{}'.format(path)] # TaskFactory(id='pychron.laser.calibration', #             task_group='hardware', #             factory=self._calibration_task_factory, #             name='Laser Calibration', #             accelerator='Ctrl+Shift+2') # ============= EOF =============================================