import wx

from outwiker.gui.preferences.baseprefpanel import BasePrefPanel
from outwiker.gui.controls.hotkeyctrl import HotkeyCtrl, EVT_HOTKEY_EDIT
from outwiker.core.commands import MessageBox

class HotKeysPanel(BasePrefPanel):
    """
    Панель с настройками, связанными с редактором
    """

    def __init__(self, parent, application):
        super().__init__(parent)

        self._application = application
        self.__hotkeys = {}

        self.__createGui()
        self.LoadState()

        self.__filterText.Bind(wx.EVT_TEXT, self.__onFilterEdit)
        self.__actionsList.Bind(wx.EVT_LISTBOX, self.__onActionSelect)
        self.__hotkeyCtrl.Bind(EVT_HOTKEY_EDIT, self.__onHotkeyEdit)
        self.SetupScrolling()

    def __onHotkeyEdit(self, event):
        newActionStrId = self.__getSelectedStrid()
        if newActionStrId is None:
            return

        newhotkey = event.hotkey
        oldActionStrId = self.__findConflict(
            newhotkey,
            self._application.actionController.getArea(newActionStrId))

        if oldActionStrId is not None:
            newAction = self._application.actionController.getTitle(
                newActionStrId)
            oldAction = self._application.actionController.getTitle(
                oldActionStrId)

            text = _('{hotkey} hotkey assigned for "{old}".\nAssign this hotkey for "{new}"?').format(
                hotkey=newhotkey,
                old=oldAction,
                new=newAction)

            if (MessageBox(text,
                           _('Hotkeys conflict'),
                           wx.ICON_QUESTION | wx.YES | wx.NO) == wx.YES):
                self.__hotkeys[oldActionStrId] = None
            else:
                self.__hotkeyCtrl.SetValue(self.__hotkeys[newActionStrId])
                return

        self.__hotkeys[newActionStrId] = newhotkey

    def __getSelectedStrid(self):
        """
        Возвращает strid выбранного действия или None,
        если в списке ничего не выбрано
        """
        index = self.__actionsList.GetSelection()
        if index == wx.NOT_FOUND:
            return None

        return self.__actionsList.GetClientData(index)

    def __createGui(self):
        mainSizer = wx.FlexGridSizer(cols=1)
        mainSizer.AddGrowableRow(1)
        mainSizer.AddGrowableCol(0)

        self.__actionsList = wx.ListBox(self)
        self.__actionsList.SetMinSize((200, -1))

        filterSizer = wx.FlexGridSizer(cols=2)
        filterSizer.AddGrowableCol(1)

        filterLabel = wx.StaticText(self, label=_('Search'))
        self.__filterText = wx.TextCtrl(self)

        filterSizer.Add(filterLabel,
                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                        border=2)

        filterSizer.Add(self.__filterText,
                        flag=wx.EXPAND | wx.ALL,
                        border=2)

        # Sizer for hotkey and label for it
        hotkeySizer = wx.FlexGridSizer(cols=2)
        hotkeySizer.AddGrowableCol(1)

        # Comment to hotkeysCtrl
        hotkeyLabel = wx.StaticText(
            self,
            -1,
            _('Hotkey.\nPress the Backspace key to clear'))

        self.__hotkeyCtrl = HotkeyCtrl(self)
        self.__hotkeyCtrl.Disable()
        self.__hotkeyCtrl.SetMinSize((200, -1))

        hotkeySizer.Add(hotkeyLabel,
                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                        border=2)

        hotkeySizer.Add(
            self.__hotkeyCtrl,
            flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.ALIGN_RIGHT,
            border=2)

        self.__descriptionText = wx.TextCtrl(
            self,
            style=wx.TE_WORDWRAP | wx.TE_MULTILINE | wx.TE_READONLY)
        self.__descriptionText.SetMinSize((-1, 75))
        self.__descriptionText.Disable()

        mainSizer.Add(filterSizer, flag=wx.EXPAND | wx.ALL, border=2)
        mainSizer.Add(self.__actionsList, flag=wx.EXPAND | wx.ALL, border=2)
        mainSizer.Add(self.__descriptionText,
                      flag=wx.EXPAND | wx.ALL, border=2)
        mainSizer.Add(hotkeySizer, flag=wx.EXPAND | wx.ALL, border=2)

        self.SetSizer(mainSizer)

    def __findConflict(self, hotkey, area: str):
        if hotkey is None or hotkey.isEmpty():
            return None

        stridCurrent = self.__getSelectedStrid()

        for strid, hotkeyCurrent in self.__hotkeys.items():
            if stridCurrent == strid or hotkey is None:
                continue
            if (hotkey == hotkeyCurrent and
                    self._application.actionController.getArea(strid) == area):
                return strid

        return None

self.__fillActionsList()
        self.__initHotKeys()

    def __initHotKeys(self):
        """
        Заполнить словарь __hotkeys текущими значениями
        """
        actionController = self._application.actionController
        strIdList = self.__getActionsStrId()
        for strid in strIdList:
            self.__hotkeys[strid] = actionController.getHotKey(strid)

    def __getActionsStrId(self):
        actionController = self._application.actionController
        return [strid
                for strid in actionController.getActionsStrId()
                if not actionController.isHidden(strid)]

    def __onFilterEdit(self, event):
        self.__fillActionsList()

    def __onActionSelect(self, event):
        self.__descriptionText.Value = ''

        strid = event.GetClientData()
        if strid is not None:
            self.__descriptionText.Value = self._application.actionController.getAction(
                strid).description
            self.__hotkeyCtrl.Enable()
            self.__hotkeyCtrl.SetValue(self.__hotkeys[strid])

    def __fillActionsList(self):
        """
        Заполнить список actions зарегистрированными действиями
        """
        actionController = self._application.actionController
        strIdList = self.__getActionsStrId()

        titleStridList = [
            (actionController.getTitle(strid), strid)
            for strid in strIdList
            if self.__filter(actionController.getAction(strid))
        ]
        titleStridList.sort()

        self.__actionsList.Clear()
        for (title, strid) in titleStridList:
            self.__actionsList.Append(title, strid)

    def __filter(self, action):
        if len(self.__filterText.Value.strip()) == 0:
            return True

        filterText = self.__filterText.Value.lower()

        return (filterText in action.title.lower() or
                filterText in action.description.lower())

    def Save(self):
        newHotkeys = list(self.__hotkeys.items())
        self._application.actionController.changeHotkeys(newHotkeys)


actionController = self._application.actionController
        return [strid
                for strid in actionController.getActionsStrId()
                if not actionController.isHidden(strid)]

import wx

from outwiker.gui.preferences.baseprefpanel import BasePrefPanel
from outwiker.gui.controls.hotkeyctrl import HotkeyCtrl, EVT_HOTKEY_EDIT
from outwiker.core.commands import MessageBox

class HotKeysPanel(BasePrefPanel):
    """
    Панель с настройками, связанными с редактором
    """

    def __init__(self, parent, application):
        super().__init__(parent)

        self._application = application
        self.__hotkeys = {}

        self.__createGui()
        self.LoadState()

        self.__filterText.Bind(wx.EVT_TEXT, self.__onFilterEdit)
        self.__actionsList.Bind(wx.EVT_LISTBOX, self.__onActionSelect)
        self.__hotkeyCtrl.Bind(EVT_HOTKEY_EDIT, self.__onHotkeyEdit)
        self.SetupScrolling()

    def __onHotkeyEdit(self, event):
        newActionStrId = self.__getSelectedStrid()
        if newActionStrId is None:
            return

        newhotkey = event.hotkey
        oldActionStrId = self.__findConflict(
            newhotkey,
            self._application.actionController.getArea(newActionStrId))

        if oldActionStrId is not None:
            newAction = self._application.actionController.getTitle(
                newActionStrId)
            oldAction = self._application.actionController.getTitle(
                oldActionStrId)

            text = _('{hotkey} hotkey assigned for "{old}".\nAssign this hotkey for "{new}"?').format(
                hotkey=newhotkey,
                old=oldAction,
                new=newAction)

            if (MessageBox(text,
                           _('Hotkeys conflict'),
                           wx.ICON_QUESTION | wx.YES | wx.NO) == wx.YES):
                self.__hotkeys[oldActionStrId] = None
            else:
                self.__hotkeyCtrl.SetValue(self.__hotkeys[newActionStrId])
                return

        self.__hotkeys[newActionStrId] = newhotkey

    def __getSelectedStrid(self):
        """
        Возвращает strid выбранного действия или None,
        если в списке ничего не выбрано
        """
        index = self.__actionsList.GetSelection()
        if index == wx.NOT_FOUND:
            return None

        return self.__actionsList.GetClientData(index)

    def __createGui(self):
        mainSizer = wx.FlexGridSizer(cols=1)
        mainSizer.AddGrowableRow(1)
        mainSizer.AddGrowableCol(0)

        self.__actionsList = wx.ListBox(self)
        self.__actionsList.SetMinSize((200, -1))

        filterSizer = wx.FlexGridSizer(cols=2)
        filterSizer.AddGrowableCol(1)

        filterLabel = wx.StaticText(self, label=_('Search'))
        self.__filterText = wx.TextCtrl(self)

        filterSizer.Add(filterLabel,
                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                        border=2)

        filterSizer.Add(self.__filterText,
                        flag=wx.EXPAND | wx.ALL,
                        border=2)

        # Sizer for hotkey and label for it
        hotkeySizer = wx.FlexGridSizer(cols=2)
        hotkeySizer.AddGrowableCol(1)

        # Comment to hotkeysCtrl
        hotkeyLabel = wx.StaticText(
            self,
            -1,
            _('Hotkey.\nPress the Backspace key to clear'))

        self.__hotkeyCtrl = HotkeyCtrl(self)
        self.__hotkeyCtrl.Disable()
        self.__hotkeyCtrl.SetMinSize((200, -1))

        hotkeySizer.Add(hotkeyLabel,
                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                        border=2)

        hotkeySizer.Add(
            self.__hotkeyCtrl,
            flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.ALIGN_RIGHT,
            border=2)

        self.__descriptionText = wx.TextCtrl(
            self,
            style=wx.TE_WORDWRAP | wx.TE_MULTILINE | wx.TE_READONLY)
        self.__descriptionText.SetMinSize((-1, 75))
        self.__descriptionText.Disable()

        mainSizer.Add(filterSizer, flag=wx.EXPAND | wx.ALL, border=2)
        mainSizer.Add(self.__actionsList, flag=wx.EXPAND | wx.ALL, border=2)
        mainSizer.Add(self.__descriptionText,
                      flag=wx.EXPAND | wx.ALL, border=2)
        mainSizer.Add(hotkeySizer, flag=wx.EXPAND | wx.ALL, border=2)

        self.SetSizer(mainSizer)

    def __findConflict(self, hotkey, area: str):
        if hotkey is None or hotkey.isEmpty():
            return None

        stridCurrent = self.__getSelectedStrid()

        for strid, hotkeyCurrent in self.__hotkeys.items():
            if stridCurrent == strid or hotkey is None:
                continue
            if (hotkey == hotkeyCurrent and
                    self._application.actionController.getArea(strid) == area):
                return strid

        return None

    def LoadState(self):
        self.__fillActionsList()
        self.__initHotKeys()

    def __initHotKeys(self):
        """
        Заполнить словарь __hotkeys текущими значениями
        """
        actionController = self._application.actionController
        strIdList = self.__getActionsStrId()
        for strid in strIdList:
            self.__hotkeys[strid] = actionController.getHotKey(strid)

    def __getActionsStrId(self):

    def __onFilterEdit(self, event):
        self.__fillActionsList()

    def __onActionSelect(self, event):
        self.__descriptionText.Value = ''

        strid = event.GetClientData()
        if strid is not None:
            self.__descriptionText.Value = self._application.actionController.getAction(
                strid).description
            self.__hotkeyCtrl.Enable()
            self.__hotkeyCtrl.SetValue(self.__hotkeys[strid])

    def __fillActionsList(self):
        """
        Заполнить список actions зарегистрированными действиями
        """
        actionController = self._application.actionController
        strIdList = self.__getActionsStrId()

        titleStridList = [
            (actionController.getTitle(strid), strid)
            for strid in strIdList
            if self.__filter(actionController.getAction(strid))
        ]
        titleStridList.sort()

        self.__actionsList.Clear()
        for (title, strid) in titleStridList:
            self.__actionsList.Append(title, strid)

    def __filter(self, action):
        if len(self.__filterText.Value.strip()) == 0:
            return True

        filterText = self.__filterText.Value.lower()

        return (filterText in action.title.lower() or
                filterText in action.description.lower())

    def Save(self):
        newHotkeys = list(self.__hotkeys.items())
        self._application.actionController.changeHotkeys(newHotkeys)


import wx

from outwiker.gui.preferences.baseprefpanel import BasePrefPanel
from outwiker.gui.controls.hotkeyctrl import HotkeyCtrl, EVT_HOTKEY_EDIT
from outwiker.core.commands import MessageBox

class HotKeysPanel(BasePrefPanel):
    """
    Панель с настройками, связанными с редактором
    """

    def __init__(self, parent, application):
        super().__init__(parent)

        self._application = application
        self.__hotkeys = {}

        self.__createGui()
        self.LoadState()

        self.__filterText.Bind(wx.EVT_TEXT, self.__onFilterEdit)
        self.__actionsList.Bind(wx.EVT_LISTBOX, self.__onActionSelect)
        self.__hotkeyCtrl.Bind(EVT_HOTKEY_EDIT, self.__onHotkeyEdit)
        self.SetupScrolling()

    def __onHotkeyEdit(self, event):
        newActionStrId = self.__getSelectedStrid()
        if newActionStrId is None:
            return

        newhotkey = event.hotkey
        oldActionStrId = self.__findConflict(
            newhotkey,
            self._application.actionController.getArea(newActionStrId))

        if oldActionStrId is not None:
            newAction = self._application.actionController.getTitle(
                newActionStrId)
            oldAction = self._application.actionController.getTitle(
                oldActionStrId)

            text = _('{hotkey} hotkey assigned for "{old}".\nAssign this hotkey for "{new}"?').format(
                hotkey=newhotkey,
                old=oldAction,
                new=newAction)

            if (MessageBox(text,
                           _('Hotkeys conflict'),
                           wx.ICON_QUESTION | wx.YES | wx.NO) == wx.YES):
                self.__hotkeys[oldActionStrId] = None
            else:
                self.__hotkeyCtrl.SetValue(self.__hotkeys[newActionStrId])
                return

        self.__hotkeys[newActionStrId] = newhotkey

    def __getSelectedStrid(self):
        """
        Возвращает strid выбранного действия или None,
        если в списке ничего не выбрано
        """
        index = self.__actionsList.GetSelection()
        if index == wx.NOT_FOUND:
            return None

        return self.__actionsList.GetClientData(index)

    def __createGui(self):
        mainSizer = wx.FlexGridSizer(cols=1)
        mainSizer.AddGrowableRow(1)
        mainSizer.AddGrowableCol(0)

        self.__actionsList = wx.ListBox(self)
        self.__actionsList.SetMi

        filterSizer = wx.FlexGridSizer(cols=2)
        filterSizer.AddGrowableCol(1)

        filterLabel = wx.StaticText(self, label=_('Search'))
        self.__filterText = wx.TextCtrl(self)

        filterSizer.Add(filterLabel,
                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                        border=2)

        filterSizer.Add(self.__filterText,
                        flag=wx.EXPAND | wx.ALL,
                        border=2)

        # Sizer for hotkey and label for it
        hotkeySizer = wx.FlexGridSizer(cols=2)
        hotkeySizer.AddGrowableCol(1)

        # Comment to hotkeysCtrl
        hotkeyLabel = wx.StaticText(
            self,
            -1,
            _('Hotkey.\nPress the Backspace key to clear'))

        self.__hotkeyCtrl = HotkeyCtrl(self)
        self.__hotkeyCtrl.Disable()
        self.__hotkeyCtrl.SetMinSize((200, -1))

        hotkeySizer.Add(hotkeyLabel,
                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                        border=2)

        hotkeySizer.Add(
            self.__hotkeyCtrl,
            flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.ALIGN_RIGHT,
            border=2)

        self.__descriptionText = wx.TextCtrl(
            self,
            style=wx.TE_WORDWRAP | wx.TE_MULTILINE | wx.TE_READONLY)
        self.__descriptionText.SetMinSize((-1, 75))
        self.__descriptionText.Disable()

        mainSizer.Add(filterSizer, flag=wx.EXPAND | wx.ALL, border=2)
        mainSizer.Add(self.__actionsList, flag=wx.EXPAND | wx.ALL, border=2)
        mainSizer.Add(self.__descriptionText,
                      flag=wx.EXPAND | wx.ALL, border=2)
        mainSizer.Add(hotkeySizer, flag=wx.EXPAND | wx.ALL, border=2)

        self.SetSizer(mainSizer)

    def __findConflict(self, hotkey, area: str):
        if hotkey is None or hotkey.isEmpty():
            return None

        stridCurrent = self.__getSelectedStrid()

        for strid, hotkeyCurrent in self.__hotkeys.items():
            if stridCurrent == strid or hotkey is None:
                continue
            if (hotkey == hotkeyCurrent and
                    self._application.actionController.getArea(strid) == area):
                return strid

        return None

    def LoadState(self):
        self.__fillActionsList()
        self.__initHotKeys()

    def __initHotKeys(self):
        """
        Заполнить словарь __hotkeys текущими значениями
        """
        actionController = self._application.actionController
        strIdList = self.__getActionsStrId()
        for strid in strIdList:
            self.__hotkeys[strid] = actionController.getHotKey(strid)

    def __getActionsStrId(self):
        actionController = self._application.actionController
        return [strid
                for strid in actionController.getActionsStrId()
                if not actionController.isHidden(strid)]

    def __onFilterEdit(self, event):
        self.__fillActionsList()

    def __onActionSelect(self, event):
        self.__descriptionText.Value = ''

        strid = event.GetClientData()
        if strid is not None:
            self.__descriptionText.Value = self._application.actionController.getAction(
                strid).description
            self.__hotkeyCtrl.Enable()
            self.__hotkeyCtrl.SetValue(self.__hotkeys[strid])

    def __fillActionsList(self):
        """
        Заполнить список actions зарегистрированными действиями
        """
        actionController = self._application.actionController
        strIdList = self.__getActionsStrId()

        titleStridList = [
            (actionController.getTitle(strid), strid)
            for strid in strIdList
            if self.__filter(actionController.getAction(strid))
        ]
        titleStridList.sort()

        self.__actionsList.Clear()
        for (title, strid) in titleStridList:
            self.__actionsList.Append(title, strid)

    def __filter(self, action):
        if len(self.__filterText.Value.strip()) == 0:
            return True

        filterText = self.__filterText.Value.lower()

        return (filterText in action.title.lower() or
                filterText in action.description.lower())

    def Save(self):
        newHotkeys = list(self.__hotkeys.items())
        self._application.actionController.changeHotkeys(newHotkeys)


        index = self.__actionsList.GetSelection()
        if index == wx.NOT_FOUND:
            return None

        return self.__actionsList.GetClientData(index)

import wx

from outwiker.gui.preferences.baseprefpanel import BasePrefPanel
from outwiker.gui.controls.hotkeyctrl import HotkeyCtrl, EVT_HOTKEY_EDIT
from outwiker.core.commands import MessageBox

class HotKeysPanel(BasePrefPanel):
    """
    Панель с настройками, связанными с редактором
    """

    def __init__(self, parent, application):
        super().__init__(parent)

        self._application = application
        self.__hotkeys = {}

        self.__createGui()
        self.LoadState()

        self.__filterText.Bind(wx.EVT_TEXT, self.__onFilterEdit)
        self.__actionsList.Bind(wx.EVT_LISTBOX, self.__onActionSelect)
        self.__hotkeyCtrl.Bind(EVT_HOTKEY_EDIT, self.__onHotkeyEdit)
        self.SetupScrolling()

    def __onHotkeyEdit(self, event):
        newActionStrId = self.__getSelectedStrid()
        if newActionStrId is None:
            return

        newhotkey = event.hotkey
        oldActionStrId = self.__findConflict(
            newhotkey,
            self._application.actionController.getArea(newActionStrId))

        if oldActionStrId is not None:
            newAction = self._application.actionController.getTitle(
                newActionStrId)
            oldAction = self._application.actionController.getTitle(
                oldActionStrId)

            text = _('{hotkey} hotkey assigned for "{old}".\nAssign this hotkey for "{new}"?').format(
                hotkey=newhotkey,
                old=oldAction,
                new=newAction)

            if (MessageBox(text,
                           _('Hotkeys conflict'),
                           wx.ICON_QUESTION | wx.YES | wx.NO) == wx.YES):
                self.__hotkeys[oldActionStrId] = None
            else:
                self.__hotkeyCtrl.SetValue(self.__hotkeys[newActionStrId])
                return

        self.__hotkeys[newActionStrId] = newhotkey

    def __getSelectedStrid(self):
        """
        Возвращает strid выбранного действия или None,
        если в списке ничего не выбрано
        """

    def __createGui(self):
        mainSizer = wx.FlexGridSizer(cols=1)
        mainSizer.AddGrowableRow(1)
        mainSizer.AddGrowableCol(0)

        self.__actionsList = wx.ListBox(self)
        self.__actionsList.SetMinSize((200, -1))

        filterSizer = wx.FlexGridSizer(cols=2)
        filterSizer.AddGrowableCol(1)

        filterLabel = wx.StaticText(self, label=_('Search'))
        self.__filterText = wx.TextCtrl(self)

        filterSizer.Add(filterLabel,
                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                        border=2)

        filterSizer.Add(self.__filterText,
                        flag=wx.EXPAND | wx.ALL,
                        border=2)

        # Sizer for hotkey and label for it
        hotkeySizer = wx.FlexGridSizer(cols=2)
        hotkeySizer.AddGrowableCol(1)

        # Comment to hotkeysCtrl
        hotkeyLabel = wx.StaticText(
            self,
            -1,
            _('Hotkey.\nPress the Backspace key to clear'))

        self.__hotkeyCtrl = HotkeyCtrl(self)
        self.__hotkeyCtrl.Disable()
        self.__hotkeyCtrl.SetMinSize((200, -1))

        hotkeySizer.Add(hotkeyLabel,
                        flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL,
                        border=2)

        hotkeySizer.Add(
            self.__hotkeyCtrl,
            flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.ALIGN_RIGHT,
            border=2)

        self.__descriptionText = wx.TextCtrl(
            self,
            style=wx.TE_WORDWRAP | wx.TE_MULTILINE | wx.TE_READONLY)
        self.__descriptionText.SetMinSize((-1, 75))
        self.__descriptionText.Disable()

        mainSizer.Add(filterSizer, flag=wx.EXPAND | wx.ALL, border=2)
        mainSizer.Add(self.__actionsList, flag=wx.EXPAND | wx.ALL, border=2)
        mainSizer.Add(self.__descriptionText,
                      flag=wx.EXPAND | wx.ALL, border=2)
        mainSizer.Add(hotkeySizer, flag=wx.EXPAND | wx.ALL, border=2)

        self.SetSizer(mainSizer)

    def __findConflict(self, hotkey, area: str):
        if hotkey is None or hotkey.isEmpty():
            return None

        stridCurrent = self.__getSelectedStrid()

        for strid, hotkeyCurrent in self.__hotkeys.items():
            if stridCurrent == strid or hotkey is None:
                continue
            if (hotkey == hotkeyCurrent and
                    self._application.actionController.getArea(strid) == area):
                return strid

        return None

    def LoadState(self):
        self.__fillActionsList()
        self.__initHotKeys()

    def __initHotKeys(self):
        """
        Заполнить словарь __hotkeys текущими значениями
        """
        actionController = self._application.actionController
        strIdList = self.__getActionsStrId()
        for strid in strIdList:
            self.__hotkeys[strid] = actionController.getHotKey(strid)

    def __getActionsStrId(self):
        actionController = self._application.actionController
        return [strid
                for strid in actionController.getActionsStrId()
                if not actionController.isHidden(strid)]

    def __onFilterEdit(self, event):
        self.__fillActionsList()

    def __onActionSelect(self, event):
        self.__descriptionText.Value = ''

        strid = event.GetClientData()
        if strid is not None:
            self.__descriptionText.Value = self._application.actionController.getAction(
                strid).description
            self.__hotkeyCtrl.Enable()
            self.__hotkeyCtrl.SetValue(self.__hotkeys[strid])

    def __fillActionsList(self):
        """
        Заполнить список actions зарегистрированными действиями
        """
        actionController = self._application.actionController
        strIdList = self.__getActionsStrId()

        titleStridList = [
            (actionController.getTitle(strid), strid)
            for strid in strIdList
            if self.__filter(actionController.getAction(strid))
        ]
        titleStridList.sort()

        self.__actionsList.Clear()
        for (title, strid) in titleStridList:
            self.__actionsList.Append(title, strid)

    def __filter(self, action):
        if len(self.__filterText.Value.strip()) == 0:
            return True

        filterText = self.__filterText.Value.lower()

        return (filterText in action.title.lower() or
                filterText in action.description.lower())

    def Save(self):
        newHotkeys = list(self.__hotkeys.items())
        self._application.actionController.changeHotkeys(newHotkeys)


# Embedded file name: scripts/client/gui/Scaleform/daapi/view/meta/BCMessageWindowMeta.py
from tutorial.gui.Scaleform.pop_ups import TutorialDialog

class BCMessageWindowMeta(TutorialDialog):

    def onMessageRemoved(self):
        self._printOverrideError('onMessageRemoved')

    def onMessageAppear(self, rendrerer):
        self._printOverrideError('onMessageAppear')

    def onMessageDisappear(self, rendrerer, animation):
        self._printOverrideError('onMessageDisappear')

self._printOverrideError('onMessageExecuted')

    def onMessageButtonClicked(self):
        self._printOverrideError('onMessageButtonClicked')

    def onMessageAnimationStopped(self, animation):
        self._printOverrideError('onMessageAnimationStopped')

    def onMessageAnimationStarted(self, animation):
        self._printOverrideError('onMessageAnimationStarted')

    def hideBlur(self):
        self._printOverrideError('hideBlur')

    def as_setMessageDataS(self, value):
        return self.flashObject.as_setMessageData(value) if self._isDAAPIInited() else None

    def as_blurOtherWindowsS(self, layer):
        return self.flashObject.as_blurOtherWindows(layer) if self._isDAAPIInited() else None


# Embedded file name: scripts/client/gui/Scaleform/daapi/view/meta/BCMessageWindowMeta.py
from tutorial.gui.Scaleform.pop_ups import TutorialDialog

class BCMessageWindowMeta(TutorialDialog):

    def onMessageRemoved(self):
        self._printOverrideError('onMessageRemoved')

    def onMessageAppear(self, rendrerer):
        self._printOverrideError('onMessageAppear')

    def onMessageDisappear(self, rendrerer, animation):
        self._printOverrideError('onMessageDisappear')

    def onMessageExecuted(self, rendrerer):
        self._printOverrideError('onMessageExecuted')

    def onMessageButtonClicked(self):

    def onMessageAnimationStopped(self, animation):
        self._printOverrideError('onMessageAnimationStopped')

    def onMessageAnimationStarted(self, animation):
        self._printOverrideError('onMessageAnimationStarted')

    def hideBlur(self):
        self._printOverrideError('hideBlur')

    def as_setMessageDataS(self, value):
        return self.flashObject.as_setMessageData(value) if self._isDAAPIInited() else None

    def as_blurOtherWindowsS(self, layer):
        return self.flashObject.as_blurOtherWindows(layer) if self._isDAAPIInited() else None


# Embedded file name: scripts/client/gui/Scaleform/daapi/view/meta/BCMessageWindowMeta.py
from tutorial.gui.Scaleform.pop_ups import TutorialDialog

class BCMessageWindowMeta(TutorialDialog):

    def onMessageRemoved(self):
        self._printOverrideError('onMessageRemoved')

    def onMessageAppear(self, rendrerer):
        self._printOverrideError('onMessageAppear')

    def onMessageDisappear(self, rendrerer, animation):
        self._printOverrideError('onMessageDisappear')

    def onMessageExecuted(self, rendrerer):
        self._printOverrideError('onMessageExecuted')

    def onMessageButtonClicked(self):
        self._printOverrideError('onMessageButtonClicked')

    def onMessageAnimationStopped(self, animation):
        self._printOverrideError('onMessageAnimationStopped')

    def onMessageAnimationStarted(self, animation):
        self._printOverrideError('onMessageAnimationStarted')

    def hideBlur(self):
        self._printOverri

    def as_setMessageDataS(self, value):
        return self.flashObject.as_setMessageData(value) if self._isDAAPIInited() else None

    def as_blurOtherWindowsS(self, layer):
        return self.flashObject.as_blurOtherWindows(layer) if self._isDAAPIInited() else None


"""Symmetrically normalize adjacency matrix."""
    adj = sp.coo_matrix(adj)
    rowsum = np.array(adj.sum(1))
    d_inv_sqrt = np.power(rowsum, -0.5).flatten()
    d_inv_sqrt[np.isinf(d_inv_sqrt)] = 0.
    d_mat_inv_sqrt = sp.diags(d_inv_sqrt)
    return adj.dot(d_mat_inv_sqrt).transpose().dot(d_mat_inv_sqrt).tocoo()

def preprocess_adj(adj):
    """Preprocessing of adjacency matrix for simple GCN model and conversion to tuple representation."""
    adj = nx.adjacency_matrix(nx.from_dict_of_lists(adj)) # return a adjacency matrix of adj ( type is numpy)
    adj_normalized = normalize_adj(adj + sp.eye(adj.shape[0])) #
    return adj_normalized.todense()

def row_norm(inputs):
    outputs = []
    for x in inputs:
        xsum = x.sum()
        x = x / xsum
        outputs.append(x)
    return outputs

def normalize_adj_torch(adj):
    if len(adj.size()) == 4:
        new_r = torch.zeros(adj.size()).type_as(adj)
        for i in range(adj.size(1)):
            adj_item = adj[0,i]
            rowsum = adj_item.sum(1)
            d_inv_sqrt = rowsum.pow_(-0.5)
            d_inv_sqrt[torch.isnan(d_inv_sqrt)] = 0
            d_mat_inv_sqrt = torch.diag(d_inv_sqrt)
            r = torch.matmul(torch.matmul(d_mat_inv_sqrt, adj_item), d_mat_inv_sqrt)
            new_r[0,i,...] = r
        return new_r
    rowsum = adj.sum(1)
    d_inv_sqrt = rowsum.pow_(-0.5)
    d_inv_sqrt[torch.isnan(d_inv_sqrt)] = 0
    d_mat_inv_sqrt = torch.diag(d_inv_sqrt)
    r = torch.matmul(torch.matmul(d_mat_inv_sqrt,adj),d_mat_inv_sqrt)
    return r

if __name__ == '__main__':
    a= row_norm(cihp2pascal_adj)
    print(a)
    print(cihp2pascal_adj)


"""Preprocessing of adjacency matrix for simple GCN model and conversion to tuple representation."""
    adj = nx.adjacency_matrix(nx.from_dict_of_lists(adj)) # return a adjacency matrix of adj ( type is numpy)
    adj_normalized = normalize_adj(adj + sp.eye(adj.shape[0])) #
    return adj_normalized.todense()

def row_norm(inputs):
    outputs = []
    for x in inputs:
        xsum = x.sum()
        x = x / xsum
        outputs.append(x)
    return outputs

def normalize_adj_torch(adj):
    if len(adj.size()) == 4:
        new_r = torch.zeros(adj.size()).type_as(adj)
        for i in range(adj.size(1)):
            adj_item = adj[0,i]
            rowsum = adj_item.sum(1)
            d_inv_sqrt = rowsum.pow_(-0.5)
            d_inv_sqrt[torch.isnan(d_inv_sqrt)] = 0
            d_mat_inv_sqrt = torch.diag(d_inv_sqrt)
            r = torch.matmul(torch.matmul(d_mat_inv_sqrt, adj_item), d_mat_inv_sqrt)
            new_r[0,i,...] = r
        return new_r
    rowsum = adj.sum(1)
    d_inv_sqrt = rowsum.pow_(-0.5)
    d_inv_sqrt[torch.isnan(d_inv_sqrt)] = 0
    d_mat_inv_sqrt = torch.diag(d_inv_sqrt)
    r = torch.matmul(torch.matmul(d_mat_inv_sqrt,adj),d_mat_inv_sqrt)
    return r

if __name__ == '__main__':
    a= row_norm(cihp2pascal_adj)
    print(a)
    print(cihp2pascal_adj)


 # return a adjacency matrix of adj ( type is numpy)
    adj_normalized = normalize_adj(adj + sp.eye(adj.shape[0])) #
    return adj_normalized.todense()

def row_norm(inputs):
    outputs = []
    for x in inputs:
        xsum = x.sum()
        x = x / xsum
        outputs.append(x)
    return outputs

def normalize_adj_torch(adj):
    if len(adj.size()) == 4:
        new_r = torch.zeros(adj.size()).type_as(adj)
        for i in range(adj.size(1)):
            adj_item = adj[0,i]
            rowsum = adj_item.sum(1)
            d_inv_sqrt = rowsum.pow_(-0.5)
            d_inv_sqrt[torch.isnan(d_inv_sqrt)] = 0
            d_mat_inv_sqrt = torch.diag(d_inv_sqrt)
            r = torch.matmul(torch.matmul(d_mat_inv_sqrt, adj_item), d_mat_inv_sqrt)
            new_r[0,i,...] = r
        return new_r
    rowsum = adj.sum(1)
    d_inv_sqrt = rowsum.pow_(-0.5)
    d_inv_sqrt[torch.isnan(d_inv_sqrt)] = 0
    d_mat_inv_sqrt = torch.diag(d_inv_sqrt)
    r = torch.matmul(torch.matmul(d_mat_inv_sqrt,adj),d_mat_inv_sqrt)
    return r

if __name__ == '__main__':
    a= row_norm(cihp2pascal_adj)
    print(a)
    print(cihp2pascal_adj)


    adj = nx.adjacency_matrix(nx.from_dict_of_lists(adj)) # return a adjacency matrix of adj ( type is numpy)
    adj_normalized = normalize_adj(adj + sp.eye(adj.shape[0])) #
    return adj_normalized.todense()


def set_edge_by_name(self, a, b, weight):

"""Label Correction algorithm."""

import logging
import sys

logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
                    level=logging.DEBUG,
                    stream=sys.stdout)

class LIFO(list):
    """A LIFO storage."""

    def insert(self, el):
        self.append(el)

class Graph:
    """An undirected graph."""

    def __init__(self):
        self.nodes = []
        self.edges = []
        self.name2index = {}
        self.index2name = {}
        self.neighbors = []

    def add_node(self, name=None):
        """Add a new node and return its index."""
        node_index = len(self.nodes)
        if name.startswith('index-'):
            logging.warning('Node names beginning with "index-" may cause '
                            'problems.')
        if name is None:
            name = "index-%i" % node_index
        self.nodes.append(node_index)
        self.name2index[name] = node_index
        self.index2name[node_index] = name

        # Add weight from new node to other nodes and vice-versa
        self.edges.append([])
        for n1 in self.nodes:
            self.edges[node_index].append(float('inf'))
            if n1 != node_index:
                self.edges[n1].append(float('inf'))

        # From the node to itself has distance 0
        self.edges[node_index][node_index] = 0

        self.neighbors.append([])

        return node_index

    def get_node_index(self, name):
        """Get node index by name."""
        return self.name2index[name]

"""
        Set edge weight by node names.

        Parameters
        ----------
        a : str
            First edge name
        b : str
            Second edge name
        weight : number
            New edge weight
        """
        i1 = self.get_node_index(a)
        i2 = self.get_node_index(b)
        self.edges[i1][i2] = weight
        self.edges[i2][i1] = weight
        self.neighbors[i1].append(i2)
        self.neighbors[i2].append(i1)

def label_correction(graph,
                     start_node, t,
                     h=None, m=None,
                     K=None):
    """
    Label correction algorithm for graph searches.

    Parameters
    ----------
    graph :
        Needs 'graph.childs' which returns a list of child indices for each
        node, 'graph.edges[node1][node2]' which always returns an edge weight,
    start_node : int
        Index of start node as given by the graph node iterator
    t : int
        Index of target node as given by the graph node iterator
    h : lower_heuristic, optional
        Takes (graph, node1, node2) and returns a number which underestimates
        the distance from node1 to node2. If this is not given, the trivial
        distance 0 is chosen.
    m : upper_heuristic, optional
    K : list-like data structure, optional
        Needs 'insert', 'pop'
    """
    if h is None:
        h = lambda g, n1, n2: 0.0
    if m is None:
        m = lambda g, n1, n2: float('inf')
    if K is None:
        K = LIFO()
    d = []
    parents = []
    for node in graph.nodes:
        d.append(float('inf'))
        parents.append(None)
    d[start_node] = 0
    u = float('inf')  # shortest distance from start_node to t
    K.append(start_node)
    while len(K) > 0:
        logging.info("K=%s" % str(K))
        v = K.pop()
        for c in graph.neighbors[v]:
            if d[v] + graph.edges[v][c] + h(graph, c, t) < min(d[c], u):
                d[c] = d[v] + graph.edges[v][c]
                parents[c] = v
                if c != t and c not in K:
                    K.insert(c)
                if c == t:
                    u = d[v] + graph.edges[v][t]
            u = min(u, d[c] + m(graph, c, t))
    # Reconstruct the path
    path, named_path = [], []
    current = t
    while current != start_node:
        path.append(current)
        named_path.append(graph.index2name[current])
        current = parents[current]
    path.append(current)
    named_path.append(graph.index2name[current])
    return {'shortest_distance': u,
            'path': path[::-1],
            'named_path': named_path[::-1]}

def sample_1():
    """A simple search problem."""
    g = Graph()
    for i in range(13):
        g.add_node(name=chr(ord('A') + i))
    g.set_edge_by_name('A', 'B', 1)
    g.set_edge_by_name('A', 'C', 1)
    g.set_edge_by_name('B', 'D', 1)
    g.set_edge_by_name('B', 'E', 1)
    g.set_edge_by_name('C', 'F', 1)
    g.set_edge_by_name('C', 'G', 1)
    g.set_edge_by_name('D', 'H', 1)
    g.set_edge_by_name('D', 'I', 1)
    g.set_edge_by_name('E', 'J', 1)
    g.set_edge_by_name('G', 'K', 1)
    g.set_edge_by_name('H', 'L', 1)
    g.set_edge_by_name('J', 'M', 1)
    i1 = g.get_node_index('A')
    i2 = g.get_node_index('F')
    ret = label_correction(g, i1, i2)
    print(ret)

if __name__ == '__main__':
    sample_1()


"""
        Set edge weight by node names.

        Parameters
        ----------
        a : str
            First edge name
        b : str
            Second edge name
        weight : number
            New edge weight
        """
        i1 = self.get_node_index(a)
        i2 = self.get_node_index(b)
        self.edges[i1][i2] = weight
        self.edges[i2][i1] = weight
        self.neighbors[i1].append(i2)
        self.neighbors[i2].append(i1)

"""Label Correction algorithm."""

import logging
import sys

logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
                    level=logging.DEBUG,
                    stream=sys.stdout)

class LIFO(list):
    """A LIFO storage."""

    def insert(self, el):
        self.append(el)

class Graph:
    """An undirected graph."""

    def __init__(self):
        self.nodes = []
        self.edges = []
        self.name2index = {}
        self.index2name = {}
        self.neighbors = []

    def add_node(self, name=None):
        """Add a new node and return its index."""
        node_index = len(self.nodes)
        if name.startswith('index-'):
            logging.warning('Node names beginning with "index-" may cause '
                            'problems.')
        if name is None:
            name = "index-%i" % node_index
        self.nodes.append(node_index)
        self.name2index[name] = node_index
        self.index2name[node_index] = name

        # Add weight from new node to other nodes and vice-versa
        self.edges.append([])
        for n1 in self.nodes:
            self.edges[node_index].append(float('inf'))
            if n1 != node_index:
                self.edges[n1].append(float('inf'))

        # From the node to itself has distance 0
        self.edges[node_index][node_index] = 0

        self.neighbors.append([])

        return node_index

    def get_node_index(self, name):
        """Get node index by name."""
        return self.name2index[name]

    def set_edge_by_name(self, a, b, weight):

def label_correction(graph,
                     start_node, t,
                     h=None, m=None,
                     K=None):
    """
    Label correction algorithm for graph searches.

    Parameters
    ----------
    graph :
        Needs 'graph.childs' which returns a list of child indices for each
        node, 'graph.edges[node1][node2]' which always returns an edge weight,
    start_node : int
        Index of start node as given by the graph node iterator
    t : int
        Index of target node as given by the graph node iterator
    h : lower_heuristic, optional
        Takes (graph, node1, node2) and returns a number which underestimates
        the distance from node1 to node2. If this is not given, the trivial
        distance 0 is chosen.
    m : upper_heuristic, optional
    K : list-like data structure, optional
        Needs 'insert', 'pop'
    """
    if h is None:
        h = lambda g, n1, n2: 0.0
    if m is None:
        m = lambda g, n1, n2: float('inf')
    if K is None:
        K = LIFO()
    d = []
    parents = []
    for node in graph.nodes:
        d.append(float('inf'))
        parents.append(None)
    d[start_node] = 0
    u = float('inf')  # shortest distance from start_node to t
    K.append(start_node)
    while len(K) > 0:
        logging.info("K=%s" % str(K))
        v = K.pop()
        for c in graph.neighbors[v]:
            if d[v] + graph.edges[v][c] + h(graph, c, t) < min(d[c], u):
                d[c] = d[v] + graph.edges[v][c]
                parents[c] = v
                if c != t and c not in K:
                    K.insert(c)
                if c == t:
                    u = d[v] + graph.edges[v][t]
            u = min(u, d[c] + m(graph, c, t))
    # Reconstruct the path
    path, named_path = [], []
    current = t
    while current != start_node:
        path.append(current)
        named_path.append(graph.index2name[current])
        current = parents[current]
    path.append(current)
    named_path.append(graph.index2name[current])
    return {'shortest_distance': u,
            'path': path[::-1],
            'named_path': named_path[::-1]}

def sample_1():
    """A simple search problem."""
    g = Graph()
    for i in range(13):
        g.add_node(name=chr(ord('A') + i))
    g.set_edge_by_name('A', 'B', 1)
    g.set_edge_by_name('A', 'C', 1)
    g.set_edge_by_name('B', 'D', 1)
    g.set_edge_by_name('B', 'E', 1)
    g.set_edge_by_name('C', 'F', 1)
    g.set_edge_by_name('C', 'G', 1)
    g.set_edge_by_name('D', 'H', 1)
    g.set_edge_by_name('D', 'I', 1)
    g.set_edge_by_name('E', 'J', 1)
    g.set_edge_by_name('G', 'K', 1)
    g.set_edge_by_name('H', 'L', 1)
    g.set_edge_by_name('J', 'M', 1)
    i1 = g.get_node_index('A')
    i2 = g.get_node_index('F')
    ret = label_correction(g, i1, i2)
    print(ret)

if __name__ == '__main__':
    sample_1()


"""Label Correction algorithm."""

import logging
import sys

logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
                    level=logging.DEBUG,
                    stream=sys.stdout)

class LIFO(list):
    """A LIFO storage."""

    def insert(self, el):
        self.append(el)

class Graph:
    """An undirected graph."""

    def __init__(self):
        self.nodes = []
        self.edges = []
        self.name2index = {}
        self.index2name = {}
        self.neighbors = []

    def add_node(self, name=None):
        """Add a new node and return its index."""
        node_index = len(self.nodes)
        if name.startswith('index-'):
            logging.warning('Node names beginning with "index-" may cause '
                            'problems.')
        if name is None:
            name = "index-%i" % node_index
        self.nodes.append(node_index)
        self.name2index[name] = node_index
        self.index2name[node_index] = name

        # Add weight from new node to other nodes and vice-versa
        self.edges.append([])
        for n1 in self.nodes:
            self.edges[node_index].append(float('inf'))
            if n1 != node_index:
                self.edges[n1].append(float('inf'))

        # From the node to itself has distance 0
        self.edges[node_index][node_index] = 0

        self.neighbors.append([])

        return node_index

    def get_node_index(self, name):
        """Get node index by name."""
        return self.name2index[name]

    def set_edge_by_name(self, a, b, weight):
        """
        Set edge weight by node names.

        Parameters
        ----------
        a : str
            First edge name
        b : str
            Second edge name
        weight : number
            New edge weight
        """
        i1 = self.get_node_index(a)
        i2 = self.get_node_index(b)
        self.edges[i1][i2] = weight
        self.edges[i2][i1] = weight
        self.neighbors[i1].append(i2)
        self.neighbors[i2].append(i1)

def label_correction(graph,
                     start_node, t,
                     h=None, m=None,
                     K=None):
    """
    Label correction algorithm for graph searches.

    Parameters
    ----------
    graph :
        Needs 'graph.childs' which returns a list of child indices for each
        node, 'graph.edges[node1][node2]' which always returns an edge weight,
    start_node : int
        Index of start node as given by the graph node iterator
    t : int
        Index of target node as given by the graph node iterator
    h : lower_heuristic, optional
        Takes (graph, node1, node2) and returns a number which underestimates
        the distance from node1 to node2. If this is not given, the trivial
        distance 0 is chosen.
    m : upper_heuristic, optional
    K : list-like data structure, optional
        Needs 'insert', 'pop'
    """
    if h is None:
        h = lambda g, n1, n2: 0.0
    if m is None:
        m = lambda g, n1, n2: float('inf')
    if K is None:
        K = LIFO()
    d = []
    parents = []
    for node in graph.nodes:
        d.append(float('inf'))
        parents.append(None)
    d[start_node] = 0
    u = float('inf')  # shortest distance from start_node to t
    K.append(start_node)
    while len(K) > 0:
        logging.info("K=%s" % str(K))
        v = K.pop()
        for c in graph.neighbors[v]:
            if d[v] + graph.edges[v][c] + h(graph, c, t) < min(d[c], u):
                d[c] = d[v] + graph.edges[v][c]
                parents[c] = v
                if c != t and c not in K:
                    K.insert(c)
                if c == t:
                    u = d[v] + graph.edges[v][t]
            u = min(u, d[c] + m(graph, c, t))
    # Reconstruct the path
    path, named_path = [], []
    current = t
    while current != start_node:
        path.append(current)
        named_path.append(graph.index2name[current])
        current = parents[current]
    path.append(current)
    named_path.append(graph.index2name[current])
    return {'shortest_distance': u,
            'path': path[::-1],
            'named_path': named_path[::-1]}

def sample_1():
    """A simple search problem."""
    g = Graph()
    for i in range(13):
        g.add_node(name=chr(ord('A') + i))
    g.set_edge_by_name('A', 'B', 1)
    g.set_edge_by_name('A', 'C', 1)
    g.set_edge_by_name('B', 'D', 1)
    g.set_edge_by_name('B', 'E', 1)
    g.set_edge_by_name('C', 'F', 1)
    g.set_e

    g.set_edge_by_name('D', 'H', 1)
    g.set_edge_by_name('D', 'I', 1)
    g.set_edge_by_name('E', 'J', 1)
    g.set_edge_by_name('G', 'K', 1)
    g.set_edge_by_name('H', 'L', 1)
    g.set_edge_by_name('J', 'M', 1)
    i1 = g.get_node_index('A')
    i2 = g.get_node_index('F')
    ret = label_correction(g, i1, i2)
    print(ret)

if __name__ == '__main__':
    sample_1()


        i1 = self.get_node_index(a)
        i2 = self.get_node_index(b)
        self.edges[i1][i2] = weight
        self.edges[i2][i1] = weight
        self.neighbors[i1].append(i2)
        self.neighbors[i2].append(i1)

"""Label Correction algorithm."""

import logging
import sys

logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
                    level=logging.DEBUG,
                    stream=sys.stdout)

class LIFO(list):
    """A LIFO storage."""

    def insert(self, el):
        self.append(el)

class Graph:
    """An undirected graph."""

    def __init__(self):
        self.nodes = []
        self.edges = []
        self.name2index = {}
        self.index2name = {}
        self.neighbors = []

    def add_node(self, name=None):
        """Add a new node and return its index."""
        node_index = len(self.nodes)
        if name.startswith('index-'):
            logging.warning('Node names beginning with "index-" may cause '
                            'problems.')
        if name is None:
            name = "index-%i" % node_index
        self.nodes.append(node_index)
        self.name2index[name] = node_index
        self.index2name[node_index] = name

        # Add weight from new node to other nodes and vice-versa
        self.edges.append([])
        for n1 in self.nodes:
            self.edges[node_index].append(float('inf'))
            if n1 != node_index:
                self.edges[n1].append(float('inf'))

        # From the node to itself has distance 0
        self.edges[node_index][node_index] = 0

        self.neighbors.append([])

        return node_index

    def get_node_index(self, name):
        """Get node index by name."""
        return self.name2index[name]

    def set_edge_by_name(self, a, b, weight):
        """
        Set edge weight by node names.

        Parameters
        ----------
        a : str
            First edge name
        b : str
            Second edge name
        weight : number
            New edge weight
        """


while len(K) > 0:
        logging.info("K=%s" % str(K))
        v = K.pop()
        for c in graph.neighbors[v]:
            if d[v] + graph.edges[v][c] + h(graph, c, t) < min(d[c], u):
                d[c] = d[v] + graph.edges[v][c]
                parents[c] = v
                if c != t and c not in K:
                    K.insert(c)
                if c == t:
                    u = d[v] + graph.edges[v][t]
            u = min(u, d[c] + m(graph, c, t))

"""Label Correction algorithm."""

import logging
import sys

logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
                    level=logging.DEBUG,
                    stream=sys.stdout)

class LIFO(list):
    """A LIFO storage."""

    def insert(self, el):
        self.append(el)

class Graph:
    """An undirected graph."""

    def __init__(self):
        self.nodes = []
        self.edges = []
        self.name2index = {}
        self.index2name = {}
        self.neighbors = []

    def add_node(self, name=None):
        """Add a new node and return its index."""
        node_index = len(self.nodes)
        if name.startswith('index-'):
            logging.warning('Node names beginning with "index-" may cause '
                            'problems.')
        if name is None:
            name = "index-%i" % node_index
        self.nodes.append(node_index)
        self.name2index[name] = node_index
        self.index2name[node_index] = name

        # Add weight from new node to other nodes and vice-versa
        self.edges.append([])
        for n1 in self.nodes:
            self.edges[node_index].append(float('inf'))
            if n1 != node_index:
                self.edges[n1].append(float('inf'))

        # From the node to itself has distance 0
        self.edges[node_index][node_index] = 0

        self.neighbors.append([])

        return node_index

    def get_node_index(self, name):
        """Get node index by name."""
        return self.name2index[name]

    def set_edge_by_name(self, a, b, weight):
        """
        Set edge weight by node names.

        Parameters
        ----------
        a : str
            First edge name
        b : str
            Second edge name
        weight : number
            New edge weight
        """
        i1 = self.get_node_index(a)
        i2 = self.get_node_index(b)
        self.edges[i1][i2] = weight
        self.edges[i2][i1] = weight
        self.neighbors[i1].append(i2)
        self.neighbors[i2].append(i1)

def label_correction(graph,
                     start_node, t,
                     h=None, m=None,
                     K=None):
    """
    Label correction algorithm for graph searches.

    Parameters
    ----------
    graph :
        Needs 'graph.childs' which returns a list of child indices for each
        node, 'graph.edges[node1][node2]' which always returns an edge weight,
    start_node : int
        Index of start node as given by the graph node iterator
    t : int
        Index of target node as given by the graph node iterator
    h : lower_heuristic, optional
        Takes (graph, node1, node2) and returns a number which underestimates
        the distance from node1 to node2. If this is not given, the trivial
        distance 0 is chosen.
    m : upper_heuristic, optional
    K : list-like data structure, optional
        Needs 'insert', 'pop'
    """
    if h is None:
        h = lambda g, n1, n2: 0.0
    if m is None:
        m = lambda g, n1, n2: float('inf')
    if K is None:
        K = LIFO()
    d = []
    parents = []
    for node in graph.nodes:
        d.append(float('inf'))
        parents.append(None)
    d[start_node] = 0
    u = float('inf')  # shortest distance from start_node to t
    K.append(start_node)

    # Reconstruct the path
    path, named_path = [], []
    current = t
    while current != start_node:
        path.append(current)
        named_path.append(graph.index2name[current])
        current = parents[current]
    path.append(current)
    named_path.append(graph.index2name[current])
    return {'shortest_distance': u,
            'path': path[::-1],
            'named_path': named_path[::-1]}

def sample_1():
    """A simple search problem."""
    g = Graph()
    for i in range(13):
        g.add_node(name=chr(ord('A') + i))
    g.set_edge_by_name('A', 'B', 1)
    g.set_edge_by_name('A', 'C', 1)
    g.set_edge_by_name('B', 'D', 1)
    g.set_edge_by_name('B', 'E', 1)
    g.set_edge_by_name('C', 'F', 1)
    g.set_edge_by_name('C', 'G', 1)
    g.set_edge_by_name('D', 'H', 1)
    g.set_edge_by_name('D', 'I', 1)
    g.set_edge_by_name('E', 'J', 1)
    g.set_edge_by_name('G', 'K', 1)
    g.set_edge_by_name('H', 'L', 1)
    g.set_edge_by_name('J', 'M', 1)
    i1 = g.get_node_index('A')
    i2 = g.get_node_index('F')
    ret = label_correction(g, i1, i2)
    print(ret)

if __name__ == '__main__':
    sample_1()


"""
# Ralf Mouthaan, Ilya Manyakin, Ermanno Miele
# University of Cambridge
# Class to operate Pixis CCD camera. Communicates with Picam library to achieve
# this. Aim is to use this class in conjunction with Acton spectormeter for
# Raman measurements. Work done with Ermanno Miele.
#   * Script connects to first camera it finds and uses this. This will cause
#       problems if no camera is connected, or more than one camera is
#       connected, or if an unexpected camera is connected.
#       Should iterate through cameras, checking IDs to find the right one.
#       This is complicated due to the way the C++ code uses lots of structures
#       instead of native data types.
#   * Will not find a camera if it is in use by another process or has not
#       been shut down properly.

Development notes:
    * API for DLL: Picam 5.x Programmers Manual, 4411-0161, Issue 5, August 2018

"""

import ctypes as ct
import numpy as np
from matplotlib import pyplot as plt
from nplab.instrument.camera import Camera
import sys,os, time

from .picam_constants import PicamSensorTemperatureStatus,PicamParameter,PicamValueType,PicamError,transpose_dictionary,PI_V,PicamConstraintType

import logging
PARENT_DIR = os.path.dirname(os.path.realpath(__file__))

class clsPicamReadoutStruct(ct.Structure):
    _fields_ = [("ptr", ct.c_void_p),
                ("intCount", ct.c_int64)]

class Pixis(Camera):
    def __init__(self,with_start_up = False,debug=0):
        self.debug = debug
        self.bolRunning = False
        self.y_max = 0
        self.x_max = 0
        if with_start_up == True:
            self.StartUp()
            self.SetExposureTime(10)

        self.boundary_cut = 5
    def __del__(self):
        if self.bolRunning == True:
            self.ShutDown()

    def raw_snapshot(self, suppress_errors=False):
        """
            Camera class override
        """
        try:
            image  = self.GetCurrentFrame()
            return True, image
        except Exception as e:
            if suppress_errors==True:
                False, None
            else:
                raise e

    def get_roi(self,x_min=0, x_max = None, y_min=0,y_max = None, suppress_errors=False,debug=0):
        _,raw_image = self.raw_snapshot(suppress_errors=suppress_errors)
        if x_max is None:
            x_max = self.x_max
        if y_max is None:
            y_max = self.y_max

        if debug > 0:
            print("Pixis.get_roi region of interest:",x_min,x_max,y_min,y_max)
        roi_image = raw_image[max(0,y_min):min(y_max,self.y_max),max(0,x_min):min(self.x_max,x_max)]
        if debug > 0:
            print("Pixis.roi_image.shape:",roi_image.shape)
        return roi_image

    def get_spectrum(self, x_min=0, x_max = None, y_min=0,y_max = None,with_boundary_cut = True, suppress_errors=False):
        roi_image = self.get_roi(x_min,x_max,y_min,y_max,suppress_errors)
        #cut edge values from raw spectrum - remove edge effects
        raw_spectrum = np.mean(roi_image,axis=0)
        pixel_offsets = np.array(list(range(0,len(raw_spectrum))))-int(self.FrameWidth/2)
        if with_boundary_cut == True:
            return raw_spectrum[self.boundary_cut:-self.boundary_cut], pixel_offsets[self.boundary_cut:-self.boundary_cut]

        else:
            return raw_spectrum,pixel_offsets

    def get_parameter(self,parameter_name, label="unknown"):
        """
        Perform GetParameterIntegerValue calls to DLL
        parameter_name : name of parameter as specified in the picam_constants.py file
        """

        if self.debug > 0:
            print("pixis.get_parameter::parameter_name:{}".format(parameter_name))
        self.picam.PicamAdvanced_RefreshParametersFromCameraDevice(self.CameraHandle)
        assert(parameter_name in list(PicamParameter.keys())) #Check that the passed parameter name is valid (ie. in constants file)
        param_type, constraint_type, n = PicamParameter[parameter_name]
        if self.debug > 0:
            print("pixis:get_parameter::param_type: {}".format(param_type))
            print("pixis:get_parameter::constraint_type: {}".format(constraint_type))
            print("pixis:get_parameter::n: {}".format(n))

        param_id = PI_V(value_type=param_type, constraint_type= constraint_type, parameter_index=n)

        #assert returned parameter value type is valid one
        valid_value_types = list(transpose_dictionary(PicamValueType).keys())
        assert(param_type in valid_value_types)

        #assert returned parameter constraint type is valid one
        valid_constraint_types = list(transpose_dictionary(PicamConstraintType).keys())
        assert(constraint_type in valid_constraint_types)

        paramtype = param_type.replace("PicamValueType_","")

        if self.debug > 0:
            print("paramtype:", paramtype)

        if paramtype == "Enumeration":
            paramtype="IntegerValue"

        else:
            paramtype=paramtype+"Value"

        function_name = "Picam_GetParameter{}".format(paramtype)
        if self.debug > 0:
            print("Function name:",function_name)
            print("Parameter name:", parameter_name)
            print("Parameter id:",param_id)
            # print "Function object", f

        getter = getattr(self.picam,function_name,None)
        if getter is None:
            raise ValueError("Getter is none!")
        else:
            if self.debug > 0:
                print(getter)
        temp =  {
            "PicamValueType_Integer" : ct.c_int(),
            "PicamValueType_Boolean" : ct.c_bool(),
            "PicamValueType_LargeInteger" : ct.c_long(),

            "PicamValueType_FloatingPoint" : ct.c_double(),

            "PicamValueType_Enumeration": ct.c_int(), #TODO
            "PicamValueType_Rois": None, #TODO
            "PicamValueType_Pulse": None, #TODO
            "PicamValueType_Modulations": None #None
        }

        value = temp[param_type]
        if self.debug > 0:
            print("pixis.get_parameter::param_type: {}".format(param_type))
            print("pixis.get_parameter::value: {}".format(value))
        if value is not None:
            response = getter(self.CameraHandle,param_id, ct.pointer(value))

            if response != 0:
                print(("Could not GET value of parameter {0} [label:{1}]".format(parameter_name,label)))
                print(("[Code:{0}] {1}".format(response, PicamError[response])))
                return np.nan

            return value.value
        else:
            '''
            Cases left to implement:
                PicamValueType_Enumeration,
                PicamValueType_Rois,
                PicamValueType_Pulse,
                PicamValueType_Modulations
            '''
            raise NotImplementedError()

    def set_parameter(self,parameter_name,parameter_value):
        '''
        Perform GetParameterIntegerValue calls to DLL
        parameter_name : name of parameter as specified in the picam_constants.py file
        '''
        assert(parameter_name in list(PicamParameter.keys())) #Check that the passed parameter name is valid (ie. in constants file)
        param_type, constraint_type, n = PicamParameter[parameter_name]
        param_id = PI_V(value_type=param_type, constraint_type= constraint_type, parameter_index=n)

        #assert returned parameter value type is valid one
        valid_value_types = list(transpose_dictionary(PicamValueType).keys())
        assert(param_type in valid_value_types)

        #assert returned parameter constraint type is valid one
        valid_constraint_types = list(transpose_dictionary(PicamConstraintType).keys())
        assert(constraint_type in valid_constraint_types)

        function_name = "Picam_SetParameter{}Value".format(param_type.replace("PicamValueType_",""))
        setter = getattr(self.picam,function_name)
        # setter = self.picam.Picam_SetParameterFloatingPointValue
        if self.debug > 0:
            print("Function name:",function_name)
            print("Paramer type, Constraint type, n:", param_type, constraint_type, n)
            print("Function object", setter)

        temp =  {
            "PicamValueType_Integer" : ct.c_int,
            "PicamValueType_Boolean" : ct.c_bool,
            "PicamValueType_LargeInteger" : ct.c_long,
            "PicamValueType_FloatingPoint" : ct.c_double, #WARNING - THIS SHOULD BE A DOUBLE (64bit), NOT FLOAT (32bit) [for 32bit change to float]
            "PicamValueType_Enumeration": ct.c_int, #Maybe an int
            "PicamValueType_Rois": None, #TODO
            "PicamValueType_Pulse": None, #TODO
            "PicamValueType_Modulations": None #None
        }

        #allocate memory for parameter for DLL to populate
        value = temp[param_type](parameter_value)

        if value is not None:
            if self.debug > 0:
                print("setting: param_id:  {0}, value:{1}".format(param_id,value))

            response = setter(self.CameraHandle,param_id, value)
            if response != 0:
                print(("Could not SET value of parameter {0} [label:{1}]".format(parameter,label)))
                print(("[Code:{0}] {1}".format(response, PicamError[response])))
                return np.nan
            #check if commit failed
            failed_commit = (ct.c_int*10)()
            failed_count = ct.c_int()
            response = self.picam.Picam_CommitParameters(self.CameraHandle,ct.byref(failed_commit),ct.byref(failed_count))
            if self.debug > 0:
                print("Picam_CommitParameters response:",response, failed_count, list(failed_commit))

            assert(int(failed_count.value) == 0)
            #check if commit has passed
            committed = ct.c_bool(False)
            response = self.picam.Picam_AreParametersCommitted(self.CameraHandle,ct.byref(committed))
            if self.debug> 0:
                    print("Picam_CommitParameters response:",response, committed)

            assert(bool(committed.value) == True)

            return

        else:
            '''
            Cases left to implement:
                PicamValueType_Enumeration,
                PicamValueType_Rois,
                PicamValueType_Pulse,
                PicamValueType_Modulations
            '''
            raise NotImplementedError()

    def StartUp(self):
        cint_temp = ct.c_int()
        # Find DLL
        try:
            self.picam = ct.WinDLL(os.path.normpath('{}/picam_64bit.dll'.format(PARENT_DIR)))
        except Exception as e:
            logging.warning("Error:",e)
            logging.info("Could not find picam dll")
            return
        # Initialise library
        bolInitialised = ct.c_bool(False)
        if self.picam.Picam_InitializeLibrary() != 0:
            print("Could not initialise library")
            return
        self.picam.Picam_IsLibraryInitialized(ct.byref(bolInitialised))
        if bolInitialised == ct.c_bool(False):
            print("Library was not initialised")
            return
        # Get camera handle
        self.CameraHandle = ct.c_void_p()
        if self.picam.Picam_OpenFirstCamera(ct.byref(self.CameraHandle)) != 0:
            print("Could not find camera")
            return

        self.x_max = self.FrameWidth = self.get_parameter(parameter_name="PicamParameter_SensorActiveWidth", label="frame width")
        self.y_max = self.FrameHeight = self.get_parameter(parameter_name="PicamParameter_SensorActiveHeight", label="frame height")
        print("Frame size:", self.x_max, self.y_max)
        self.bolRunning = True
        self.SetTemperatureWithLock(-80.0)

    def ShutDown(self):
        if self.bolRunning == False:
            return
        if self.picam.Picam_CloseCamera(self.CameraHandle) != 0:
            print("Could not close camera")
            return
        if self.picam.Picam_UninitializeLibrary() != 0:
            print("Could not shut down library")
            return
        self.bolRunning = False

    def SetExposureTime(self,time):

        param_name = "PicamParameter_ExposureTime"
        param_value = time #in milliseconds
        self.set_parameter(parameter_name=param_name,parameter_value=param_value)

self.__SetSensorTemperatureSetPoint(temperature)
        status_code = p.GetTemperatureStatus()
        while PicamSensorTemperatureStatus[status_code] != "PicamSensorTemperatureStatus_Locked":
            print("TemperatureStatus: {3}[{2}] (current: {0}, target:{1})".format(p.GetSensorTemperatureReading(), temperature,status_code, PicamSensorTemperatureStatus[status_code]))
            time.sleep(0.5)
            status_code = p.GetTemperatureStatus()

        status_code = p.GetTemperatureStatus()
        print("TemperatureStatus: {0} [{1}]".format(PicamSensorTemperatureStatus[status_code], status_code))
        return

    def GetSensorTemperatureReading(self):
        param_name = "PicamParameter_SensorTemperatureReading"
        return self.get_parameter(param_name)

    def __SetSensorTemperatureSetPoint(self,temperature):
        '''
            Do not use this method if you want to wait for temperature to stabilize, use SetTemperatureWithLock
        '''
        param_name = "PicamParameter_SensorTemperatureSetPoint"
        return self.set_parameter(parameter_name=param_name,parameter_value=temperature)

    def GetTemperatureStatus(self):
        '''
        See picam_constants.PicamSensorTemperatureStatus for
            int <-> status mappings
        '''
        param_name = "PicamParameter_SensorTemperatureStatus"
        return self.get_parameter(param_name)

    def GetExposureTime(self):
        param_name = "PicamParameter_ExposureTime"
        #function call: PicamEnumeratedType_CoolingFanStatus
        return self.get_parameter(parameter_name=param_name)

    def GetSensorType(self):
        param_name = "PicamParameter_SensorType"
        return self.get_parameter(parameter_name=param_name)

    def GetIntensifierStatus(self):
        param_name = "PicamParameter_IntensifierStatus"
        return self.get_parameter(parameter_name=param_name)

    def GetCurrentFrame(self):

        if self.bolRunning == False:
            self.StartUp()

        structReadout = clsPicamReadoutStruct()
        intErrorMask = ct.c_int()

        # Read in pointer to image buffer
        if self.picam.Picam_Acquire(self.CameraHandle, 1, -1,
                ct.byref(structReadout), ct.byref(intErrorMask)) != 0:
            print("Image acquisition failed")
            return
        if intErrorMask.value != 0:
            print("Image acquisition returned an error")
            return

        # Get image
        ctarr = (ct.c_uint16*(self.FrameWidth*self.FrameHeight)) # Create ctypes array
        ctarr = ctarr.from_address(structReadout.ptr) # Read in array from pointer
        nparr = np.array(ctarr) # Convert to numpy array
        nparr = nparr.reshape((self.FrameWidth, self.FrameHeight)) # Reshape numpy array

        return nparr

if __name__ == "__main__":

    p = Pixis(debug=0)
    p.StartUp()

    p.SetTemperatureWithLock(-75)

    #     print i

    p.ShutDown()


self.debug = debug
        self.bolRunning = False
        self.y_max = 0
        self.x_max = 0
        if with_start_up == True:
            self.StartUp()
            self.SetExposureTime(10)

        self.boundary_cut = 5

"""
# Ralf Mouthaan, Ilya Manyakin, Ermanno Miele
# University of Cambridge
# Class to operate Pixis CCD camera. Communicates with Picam library to achieve
# this. Aim is to use this class in conjunction with Acton spectormeter for
# Raman measurements. Work done with Ermanno Miele.
#   * Script connects to first camera it finds and uses this. This will cause
#       problems if no camera is connected, or more than one camera is
#       connected, or if an unexpected camera is connected.
#       Should iterate through cameras, checking IDs to find the right one.
#       This is complicated due to the way the C++ code uses lots of structures
#       instead of native data types.
#   * Will not find a camera if it is in use by another process or has not
#       been shut down properly.

Development notes:
    * API for DLL: Picam 5.x Programmers Manual, 4411-0161, Issue 5, August 2018

"""

import ctypes as ct
import numpy as np
from matplotlib import pyplot as plt
from nplab.instrument.camera import Camera
import sys,os, time

from .picam_constants import PicamSensorTemperatureStatus,PicamParameter,PicamValueType,PicamError,transpose_dictionary,PI_V,PicamConstraintType

import logging
PARENT_DIR = os.path.dirname(os.path.realpath(__file__))

class clsPicamReadoutStruct(ct.Structure):
    _fields_ = [("ptr", ct.c_void_p),
                ("intCount", ct.c_int64)]

class Pixis(Camera):
    def __init__(self,with_start_up = False,debug=0):

    def __del__(self):
        if self.bolRunning == True:
            self.ShutDown()

    def raw_snapshot(self, suppress_errors=False):
        """
            Camera class override
        """
        try:
            image  = self.GetCurrentFrame()
            return True, image
        except Exception as e:
            if suppress_errors==True:
                False, None
            else:
                raise e

    def get_roi(self,x_min=0, x_max = None, y_min=0,y_max = None, suppress_errors=False,debug=0):
        _,raw_image = self.raw_snapshot(suppress_errors=suppress_errors)
        if x_max is None:
            x_max = self.x_max
        if y_max is None:
            y_max = self.y_max

        if debug > 0:
            print("Pixis.get_roi region of interest:",x_min,x_max,y_min,y_max)
        roi_image = raw_image[max(0,y_min):min(y_max,self.y_max),max(0,x_min):min(self.x_max,x_max)]
        if debug > 0:
            print("Pixis.roi_image.shape:",roi_image.shape)
        return roi_image

    def get_spectrum(self, x_min=0, x_max = None, y_min=0,y_max = None,with_boundary_cut = True, suppress_errors=False):
        roi_image = self.get_roi(x_min,x_max,y_min,y_max,suppress_errors)
        #cut edge values from raw spectrum - remove edge effects
        raw_spectrum = np.mean(roi_image,axis=0)
        pixel_offsets = np.array(list(range(0,len(raw_spectrum))))-int(self.FrameWidth/2)
        if with_boundary_cut == True:
            return raw_spectrum[self.boundary_cut:-self.boundary_cut], pixel_offsets[self.boundary_cut:-self.boundary_cut]

        else:
            return raw_spectrum,pixel_offsets

    def get_parameter(self,parameter_name, label="unknown"):
        """
        Perform GetParameterIntegerValue calls to DLL
        parameter_name : name of parameter as specified in the picam_constants.py file
        """

        if self.debug > 0:
            print("pixis.get_parameter::parameter_name:{}".format(parameter_name))
        self.picam.PicamAdvanced_RefreshParametersFromCameraDevice(self.CameraHandle)
        assert(parameter_name in list(PicamParameter.keys())) #Check that the passed parameter name is valid (ie. in constants file)
        param_type, constraint_type, n = PicamParameter[parameter_name]
        if self.debug > 0:
            print("pixis:get_parameter::param_type: {}".format(param_type))
            print("pixis:get_parameter::constraint_type: {}".format(constraint_type))
            print("pixis:get_parameter::n: {}".format(n))

        param_id = PI_V(value_type=param_type, constraint_type= constraint_type, parameter_index=n)

        #assert returned parameter value type is valid one
        valid_value_types = list(transpose_dictionary(PicamValueType).keys())
        assert(param_type in valid_value_types)

        #assert returned parameter constraint type is valid one
        valid_constraint_types = list(transpose_dictionary(PicamConstraintType).keys())
        assert(constraint_type in valid_constraint_types)

        paramtype = param_type.replace("PicamValueType_","")

        if self.debug > 0:
            print("paramtype:", paramtype)

        if paramtype == "Enumeration":
            paramtype="IntegerValue"

        else:
            paramtype=paramtype+"Value"

        function_name = "Picam_GetParameter{}".format(paramtype)
        if self.debug > 0:
            print("Function name:",function_name)
            print("Parameter name:", parameter_name)
            print("Parameter id:",param_id)
            # print "Function object", f

        getter = getattr(self.picam,function_name,None)
        if getter is None:
            raise ValueError("Getter is none!")
        else:
            if self.debug > 0:
                print(getter)
        temp =  {
            "PicamValueType_Integer" : ct.c_int(),
            "PicamValueType_Boolean" : ct.c_bool(),
            "PicamValueType_LargeInteger" : ct.c_long(),

            "PicamValueType_FloatingPoint" : ct.c_double(),

            "PicamValueType_Enumeration": ct.c_int(), #TODO
            "PicamValueType_Rois": None, #TODO
            "PicamValueType_Pulse": None, #TODO
            "PicamValueType_Modulations": None #None
        }

        value = temp[param_type]
        if self.debug > 0:
            print("pixis.get_parameter::param_type: {}".format(param_type))
            print("pixis.get_parameter::value: {}".format(value))
        if value is not None:
            response = getter(self.CameraHandle,param_id, ct.pointer(value))

            if response != 0:
                print(("Could not GET value of parameter {0} [label:{1}]".format(parameter_name,label)))
                print(("[Code:{0}] {1}".format(response, PicamError[response])))
                return np.nan

            return value.value
        else:
            '''
            Cases left to implement:
                PicamValueType_Enumeration,
                PicamValueType_Rois,
                PicamValueType_Pulse,
                PicamValueType_Modulations
            '''
            raise NotImplementedError()

    def set_parameter(self,parameter_name,parameter_value):
        '''
        Perform GetParameterIntegerValue calls to DLL
        parameter_name : name of parameter as specified in the picam_constants.py file
        '''
        assert(parameter_name in list(PicamParameter.keys())) #Check that the passed parameter name is valid (ie. in constants file)
        param_type, constraint_type, n = PicamParameter[parameter_name]
        param_id = PI_V(value_type=param_type, constraint_type= constraint_type, parameter_index=n)

        #assert returned parameter value type is valid one
        valid_value_types = list(transpose_dictionary(PicamValueType).keys())
        assert(param_type in valid_value_types)

        #assert returned parameter constraint type is valid one
        valid_constraint_types = list(transpose_dictionary(PicamConstraintType).keys())
        assert(constraint_type in valid_constraint_types)

        function_name = "Picam_SetParameter{}Value".format(param_type.replace("PicamValueType_",""))
        setter = getattr(self.picam,function_name)
        # setter = self.picam.Picam_SetParameterFloatingPointValue
        if self.debug > 0:
            print("Function name:",function_name)
            print("Paramer type, Constraint type, n:", param_type, constraint_type, n)
            print("Function object", setter)

        temp =  {
            "PicamValueType_Integer" : ct.c_int,
            "PicamValueType_Boolean" : ct.c_bool,
            "PicamValueType_LargeInteger" : ct.c_long,
            "PicamValueType_FloatingPoint" : ct.c_double, #WARNING - THIS SHOULD BE A DOUBLE (64bit), NOT FLOAT (32bit) [for 32bit change to float]
            "PicamValueType_Enumeration": ct.c_int, #Maybe an int
            "PicamValueType_Rois": None, #TODO
            "PicamValueType_Pulse": None, #TODO
            "PicamValueType_Modulations": None #None
        }

        #allocate memory for parameter for DLL to populate
        value = temp[param_type](parameter_value)

        if value is not None:
            if self.debug > 0:
                print("setting: param_id:  {0}, value:{1}".format(param_id,value))

            response = setter(self.CameraHandle,param_id, value)
            if response != 0:
                print(("Could not SET value of parameter {0} [label:{1}]".format(parameter,label)))
                print(("[Code:{0}] {1}".format(response, PicamError[response])))
                return np.nan
            #check if commit failed
            failed_commit = (ct.c_int*10)()
            failed_count = ct.c_int()
            response = self.picam.Picam_CommitParameters(self.CameraHandle,ct.byref(failed_commit),ct.byref(failed_count))
            if self.debug > 0:
                print("Picam_CommitParameters response:",response, failed_count, list(failed_commit))

            assert(int(failed_count.value) == 0)
            #check if commit has passed
            committed = ct.c_bool(False)
            response = self.picam.Picam_AreParametersCommitted(self.CameraHandle,ct.byref(committed))
            if self.debug> 0:
                    print("Picam_CommitParameters response:",response, committed)

            assert(bool(committed.value) == True)

            return

        else:
            '''
            Cases left to implement:
                PicamValueType_Enumeration,
                PicamValueType_Rois,
                PicamValueType_Pulse,
                PicamValueType_Modulations
            '''
            raise NotImplementedError()

    def StartUp(self):
        cint_temp = ct.c_int()
        # Find DLL
        try:
            self.picam = ct.WinDLL(os.path.normpath('{}/picam_64bit.dll'.format(PARENT_DIR)))
        except Exception as e:
            logging.warning("Error:",e)
            logging.info("Could not find picam dll")
            return
        # Initialise library
        bolInitialised = ct.c_bool(False)
        if self.picam.Picam_InitializeLibrary() != 0:
            print("Could not initialise library")
            return
        self.picam.Picam_IsLibraryInitialized(ct.byref(bolInitialised))
        if bolInitialised == ct.c_bool(False):
            print("Library was not initialised")
            return
        # Get camera handle
        self.CameraHandle = ct.c_void_p()
        if self.picam.Picam_OpenFirstCamera(ct.byref(self.CameraHandle)) != 0:
            print("Could not find camera")
            return

        self.x_max = self.FrameWidth = self.get_parameter(parameter_name="PicamParameter_SensorActiveWidth", label="frame width")
        self.y_max = self.FrameHeight = self.get_parameter(parameter_name="PicamParameter_SensorActiveHeight", label="frame height")
        print("Frame size:", self.x_max, self.y_max)
        self.bolRunning = True
        self.SetTemperatureWithLock(-80.0)

    def ShutDown(self):
        if self.bolRunning == False:
            return
        if self.picam.Picam_CloseCamera(self.CameraHandle) != 0:
            print("Could not close camera")
            return
        if self.picam.Picam_UninitializeLibrary() != 0:
            print("Could not shut down library")
            return
        self.bolRunning = False

    def SetExposureTime(self,time):

        param_name = "PicamParameter_ExposureTime"
        param_value = time #in milliseconds
        self.set_parameter(parameter_name=param_name,parameter_value=param_value)

    def SetTemperatureWithLock(self,temperature):
        self.__SetSensorTemperatureSetPoint(temperature)
        status_code = p.GetTemperatureStatus()
        while PicamSensorTemperatureStatus[status_code] != "PicamSensorTemperatureStatus_Locked":
            print("TemperatureStatus: {3}[{2}] (current: {0}, target:{1})".format(p.GetSensorTemperatureReading(), temperature,status_code, PicamSensorTemperatureStatus[status_code]))
            time.sleep(0.5)
            status_code = p.GetTemperatureStatus()

        status_code = p.GetTemperatureStatus()
        print("TemperatureStatus: {0} [{1}]".format(PicamSensorTemperatureStatus[status_code], status_code))
        return

    def GetSensorTemperatureReading(self):
        param_name = "PicamParameter_SensorTemperatureReading"
        return self.get_parameter(param_name)

    def __SetSensorTemperatureSetPoint(self,temperature):
        '''
            Do not use this method if you want to wait for temperature to stabilize, use SetTemperatureWithLock
        '''
        param_name = "PicamParameter_SensorTemperatureSetPoint"
        return self.set_parameter(parameter_name=param_name,parameter_value=temperature)

    def GetTemperatureStatus(self):
        '''
        See picam_constants.PicamSensorTemperatureStatus for
            int <-> status mappings
        '''
        param_name = "PicamParameter_SensorTemperatureStatus"
        return self.get_parameter(param_name)

    def GetExposureTime(self):
        param_name = "PicamParameter_ExposureTime"
        #function call: PicamEnumeratedType_CoolingFanStatus
        return self.get_parameter(parameter_name=param_name)

    def GetSensorType(self):
        param_name = "PicamParameter_SensorType"
        return self.get_parameter(parameter_name=param_name)

    def GetIntensifierStatus(self):
        param_name = "PicamParameter_IntensifierStatus"
        return self.get_parameter(parameter_name=param_name)

    def GetCurrentFrame(self):

        if self.bolRunning == False:
            self.StartUp()

        structReadout = clsPicamReadoutStruct()
        intErrorMask = ct.c_int()

        # Read in pointer to image buffer
        if self.picam.Picam_Acquire(self.CameraHandle, 1, -1,
                ct.byref(structReadout), ct.byref(intErrorMask)) != 0:
            print("Image acquisition failed")
            return
        if intErrorMask.value != 0:
            print("Image acquisition returned an error")
            return

        # Get image
        ctarr = (ct.c_uint16*(self.FrameWidth*self.FrameHeight)) # Create ctypes array
        ctarr = ctarr.from_address(structReadout.ptr) # Read in array from pointer
        nparr = np.array(ctarr) # Convert to numpy array
        nparr = nparr.reshape((self.FrameWidth, self.FrameHeight)) # Reshape numpy array

        return nparr

if __name__ == "__main__":

    p = Pixis(debug=0)
    p.StartUp()

    p.SetTemperatureWithLock(-75)

    #     print i

    p.ShutDown()