"""Subclass of NewMember, which is generated by wxFormBuilder."""

import copy
import wx
import wxx
from activity.models.ui import ui as ui
import model
import app.resources as rc


# Implementing NewMember
class MemberDialog(ui.NewMember):
    """
    This dialog allows to setup data member of class
    or struct. You can set default value for using
    in constructors or as initialization of static
    members.
    """
    @wxx.SetInfo(__doc__)
    def __init__(self, parent, container):
        """Dialog initialization"""
        super(MemberDialog, self).__init__(parent)
        self._container = container
        scoped = lambda x: (hasattr(x, 'scoped') and x.scoped) or x.name
        self._types = dict([scoped(x), x] for x in container.types)
        self._autoname = ''  # proposed name
        # add types but not on-the-fly template type
        self.m_type.AppendItems([x for x in self._types.keys() if x != '@'])
        # we need to add types from template nested classes
        classes = container.nested_classes
        self._nested_template_types = []
        for clase in classes:
            for x in clase._template_types:
                if x not in self._nested_template_types:
                    self._nested_template_types.append(scoped(x))
        if len(self._nested_template_types) > 0:
            self.m_type.AppendItems(self._nested_template_types)
        self.choiceStr = ""
        self.m_type.SetFocus()
        icon = wx.EmptyIcon()
        icon.CopyFromBitmap(rc.GetBitmap("member"))
        self.SetIcon(icon)
        self._register_keybindings()

    def AutoName(self):
        """Suggest the argument name, based on type"""
        iSel = self.m_type.GetCurrentSelection()
        if iSel == wx.NOT_FOUND:
            return
        s = self.m_name.GetValue()
        if self._autoname != s and s:
            return
        kwargs = {
            'const': (self.m_const.IsChecked() and 'c') or '',
            'reference': (self.m_reference.IsChecked() and 'r') or '',
            'ptr': (self.m_ptr.IsChecked() and 'p') or '',
            'pptr': (self.m_pptr.IsChecked() and 'p') or '',
            'constptr': (self.m_constptr.IsChecked() and 'c') or '',
            'array': (self.m_array.IsChecked() and 'a') or '',
            'typename': self.m_type.GetString(iSel).replace('::', '_'),
        }
        #volatile = (self.m_volatile.IsChecked() and 'v') or ''
        self._autoname = '{const}{reference}{ptr}{pptr}{constptr}{array}{typename}'.format(
            **kwargs)
        self.m_name.SetValue(self._autoname)

    def _register_keybindings(self):
        """Register accelerators for static labels that must change the focus"""
        newId_t = wx.NewId()
        newId_n = wx.NewId()
        newId_a = wx.NewId()
        newId_d = wx.NewId()
        newId_o = wx.NewId()
        self.Bind(wx.EVT_MENU, self.OnActivateType, id=newId_t)
        self.Bind(wx.EVT_MENU, self.OnActivateName, id=newId_n)
        self.Bind(wx.EVT_MENU, self.OnActivateAccess, id=newId_a)
        self.Bind(wx.EVT_MENU, self.OnActivateDefault, id=newId_d)
        self.Bind(wx.EVT_MENU, self.OnActivateNotes, id=newId_o)
        aTable = wx.AcceleratorTable([
            wx.AcceleratorEntry(wx.ACCEL_ALT, ord('T'), newId_t),
            wx.AcceleratorEntry(wx.ACCEL_ALT, ord('N'), newId_n),
            wx.AcceleratorEntry(wx.ACCEL_ALT, ord('A'), newId_a),
            wx.AcceleratorEntry(wx.ACCEL_ALT, ord('D'), newId_d),
            wx.AcceleratorEntry(wx.ACCEL_ALT, ord('O'), newId_o)
            ])
        self.SetAcceleratorTable(aTable)

    def OnActivateType(self, event):
        """activate type combo"""
        self.m_type.SetFocus()

    def OnActivateName(self, event):
        """activate name entry"""
        self.m_name.SetFocus()

    def OnActivateAccess(self, event):
        """activate acces combo"""
        self.m_choice2.SetFocus()

    def OnActivateDefault(self, event):
        """activate default value"""
        self.m_textCtrl8.SetFocus()

    def OnActivateNotes(self, event):
        """Activate notes"""
        self.m_richText1.SetFocus()

    def OnEnterName(self, event):
        """This event is generated when the enter is pressed in the
        name entry"""
        self.m_choice2.SetFocus()

    def OnTypeChanged(self, event):
        """This event happens when the return type is changed. The main goal
        of this callback is handling template types for argument specification"""
        iSel = self.m_type.GetCurrentSelection()
        _type = self._types.get(self.m_type.GetString(iSel), None)
        template_args = False
        if _type is not None:
            if _type._template is not None:
                template_args = True
        if template_args is True:
            self.m_staticText67.Enable(True)
            self.m_template_args.Enable(True)
            self.m_staticText68.Enable(True)
        else:
            self.m_staticText67.Enable(False)
            self.m_template_args.Enable(False)
            self.m_staticText68.Enable(False)
            self.m_template_args.SetValue('')
        self.AutoName()

    def CopyAttributes(self, member):
        """Get the atributes"""
        member._name = self._name
        member._typei = copy.copy(self._typei)
        member._access = self._access
        member._static = self._static
        member._default = self._default
        member._volatile = self._volatile
        member._mutable = self._mutable
        member._bitField = self._bitField
        if self._bitField:
            member._bitFieldSize = self._bitFieldSize
        member._note = self._note
        member.inner_class.AutoInit()

    def SetAttributes(self, member):
        """Set the attributes"""
        self.m_name.SetValue(member._name)
        ti = member._typei
        iSel = self.m_type.FindString(ti.scoped)
        self.m_type.SetSelection(iSel)
        iSel = self.m_choice2.FindString(member._access)
        self.m_choice2.SetSelection(iSel)
        self.m_checkBox105.SetValue(member._static)
        self.m_textCtrl8.SetValue(member._default)
        self.m_checkBox49.SetValue(member._volatile)
        self.m_checkBox48.SetValue(member._mutable)
        self.m_const.SetValue(ti._const)
        self.m_ptr.SetValue(ti._ptr)
        self.m_reference.SetValue(ti._ref)
        self.m_pptr.SetValue(ti._ptr_to_ptr)
        self.m_constptr.SetValue(ti._const_ptr)
        self.m_array.SetValue(ti._array)
        if ti._array is True:
            self.m_textCtrl7.Show(True)
            self.m_textCtrl7.Enable(True)
            self.m_textCtrl7.SetValue(str(ti._array_size))
        else:
            self.m_textCtrl7.SetValue('0')
        self.m_checkBox51.SetValue(member._bitField)
        if ti._type_args is not None:
            self.m_staticText67.Enable(True)
            self.m_template_args.Enable(True)
            self.m_staticText68.Enable(True)
            self.m_template_args.SetValue(ti._type_args)

        if member._bitField is True:
            self.m_textCtrl39.Show(True)
            self.m_textCtrl39.Enable(True)
            self.m_textCtrl39.SetValue(str(member._bitFieldSize))
        self.m_richText1.SetValue(member._note)
        self.SetTitle("Edit member")

    def Validate(self):
        """Dialog validation"""
        self._name = self.m_name.GetValue()
        if len(self._name) == 0:
            wx.MessageBox("Member name must not be empty", "Error",
                wx.OK | wx.CENTER | wx.ICON_ERROR, self)
            return False
        iSel = self.m_type.GetCurrentSelection()
        if iSel == wx.NOT_FOUND:
            wx.MessageBox("Invalid type", "Error",
                wx.OK | wx.CENTER | wx.ICON_ERROR, self)
            return False
        typename = self.m_type.GetString(iSel)
        iSel = self.m_choice2.GetCurrentSelection()
        if iSel == wx.NOT_FOUND:
            wx.MessageBox("Invalid access", "Error",
                wx.OK | wx.CENTER | wx.ICON_ERROR, self)
            return False
        self._static = self.m_checkBox105.IsChecked()
        self._access = self.m_choice2.GetString(iSel)
        self._default = self.m_textCtrl8.GetValue()
        self._volatile = self.m_checkBox49.GetValue()
        self._mutable = self.m_checkBox48.GetValue()
        if self.m_array.IsChecked():
            try:
                asize = int(self.m_textCtrl7.GetValue())
            except:
                asize = ''
        else:
            asize = None
        if typename in self._nested_template_types:
            self._typei = model.cc.typeinst(
                type=self._types['@'],
                type_alias=typename,
                const=self.m_const.IsChecked(),
                ptr=self.m_ptr.IsChecked(),
                ref=self.m_reference.IsChecked(),
                ptrptr=self.m_pptr.IsChecked(),
                constptr=self.m_constptr.IsChecked(),
                array=self.m_array.IsChecked(),
                arraysize=asize
                )
        else:
            _type = self._types[typename]
            if _type._template is not None:
                #we construct type instance with explicit arguments
                type_args = self.m_template_args.GetValue()
                self._typei = model.cc.typeinst(
                    type=_type,
                    type_args=type_args,
                    const=self.m_const.IsChecked(),
                    ptr=self.m_ptr.IsChecked(),
                    ref=self.m_reference.IsChecked(),
                    ptrptr=self.m_pptr.IsChecked(),
                    constptr=self.m_constptr.IsChecked(),
                    array=self.m_array.IsChecked(),
                    arraysize=asize
                )
            else:
                self._typei = model.cc.typeinst(
                    type=self._types[typename],
                    const=self.m_const.IsChecked(),
                    ptr=self.m_ptr.IsChecked(),
                    ref=self.m_reference.IsChecked(),
                    ptrptr=self.m_pptr.IsChecked(),
                    constptr=self.m_constptr.IsChecked(),
                    array=self.m_array.IsChecked(),
                    arraysize=asize
            )
        self._bitField = self.m_checkBox51.IsChecked()
        if self._bitField is True:
            self._bitFieldSize = int(self.m_textCtrl39.GetValue())
        else:
            self._bitFieldSize = 0
        self._note = self.m_richText1.GetValue()
        return True

    def get_kwargs(self):
        """return arguments for object instance"""
        return  {'parent': self._container, 'name': self._name,
            'type': self._typei, 'access': self._access, 'static': self._static,
            'volatile': self._volatile, 'mutable': self._mutable,
            'bitfield': self._bitField, 'bitfieldsize': self._bitFieldSize,
            'default': self._default}

    # Handlers for NewMember events.
    def OnKeyDown(self, event):
        """Listbox selection"""
        keycode = event.GetKeyCode()
        if keycode == wx.WXK_UP or keycode == wx.WXK_NUMPAD_UP:
            i = self.m_type.GetSelection()
            if i is not wx.NOT_FOUND and i > 0:
                self.m_type.SetSelection(i - 1)
        elif keycode == wx.WXK_DOWN or keycode == wx.WXK_NUMPAD_DOWN:
            i = self.m_type.GetSelection() + 1
            if i > wx.NOT_FOUND and i < len(self._types):
                self.m_type.SetSelection(i)
        elif keycode < 256:
            keychar = chr(keycode)
            if keychar.isalnum() or keycode is wx.WXK_SPACE:
                self.choiceStr += keychar.lower()
                for t in self._types:
                    tl = t.lower()
                    if tl.find(self.choiceStr) == 0:
                        sel = self.m_type.FindString(t)
                        if sel is not wx.NOT_FOUND:
                            self.m_type.SetSelection(sel)
                            if keycode is not wx.WXK_SPACE:
                                event.Skip()
                            return
            self.choiceStr = ""
        event.Skip()

    def OnPointerToggle(self, event):
        """ptr toggle gui"""
        if self.m_ptr.IsChecked():
            self.m_constptr.Enable(True)
            self.m_checkBox50.Enable(True)
            self.m_pptr.Enable(True)
        else:
            self.m_constptr.Enable(False)
            self.m_checkBox50.Enable(False)
            self.m_pptr.Enable(False)
            self.m_constptr.SetValue(False)
            self.m_checkBox50.SetValue(False)
            self.m_pptr.SetValue(False)
        self.AutoName()

    def OnToggleArray(self, event):
        "toggle array event"
        if  self.m_array.IsChecked():
            self.m_checkBox51.SetValue(False)
            self.m_textCtrl39.Show(False)
            self.m_textCtrl39.Enable(False)
            self.m_textCtrl7.Show(True)
            self.m_textCtrl7.Enable(True)
        else:
            self.m_textCtrl7.Show(False)
            self.m_textCtrl7.Enable(False)
        self.AutoName()

    def OnToggleStatic(self, event):
        """toggle static event"""
        if self.m_checkBox105.IsChecked():
            #disable bit field
            self.m_checkBox51.SetValue(False)
            self.m_checkBox51.Enable(False)
            self.m_textCtrl39.Show(False)
            self.m_textCtrl39.Enable(False)
            #disable mutable
            self.m_checkBox48.SetValue(False)
            self.m_checkBox48.Enable(False)
        else:
            self.m_checkBox51.Enable(True)
            self.m_checkBox48.Enable(True)
        event.Skip()

    def OnToggleBitFiled(self, event):
        "toggle array event"
        if  self.m_checkBox51.IsChecked():
            self.m_array.SetValue(False)
            self.m_textCtrl7.Show(False)
            self.m_textCtrl7.Enable(False)
            self.m_textCtrl39.Show(True)
            self.m_textCtrl39.Enable(True)
        else:
            self.m_textCtrl39.Show(False)
            self.m_textCtrl39.Enable(False)
        event.Skip()

    def OnCancel(self, event):
        """cancel event handler"""
        self.EndModal(wx.ID_CANCEL)

    def OnOK(self, event):
        """ok event handler"""
        if self.Validate():
            self.EndModal(wx.ID_OK)


