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

import copy
import wx
import wxx
import tran
import deco
import app
import app.resources as rc
import model
import model.tasks as tasks
from ctx import localcontext as context
from app.ui.view import BaseView
from activity.tasks.ui import ui
from activity.tasks.ui import dlg as mdlg
import wx.propgrid as pg
import app.clipboard as clipboard


# base class for clipboard data
class clip_item_tasks(object):
    """clipboard format"""

    def __init__(self, object):
        """
        Initialize clipboard data.
        The object is the selected data
        """
        self.proj = object.project
        self.type = type(object)
        self.args = object.get_kwargs()


CLIP_FORMAT_TASKS = clipboard.register(clip_item_tasks)


# Implementing TasksView
class TasksView(BaseView, ui.TasksView):
    """Class for tasks view"""
    perspective = ''

    # add folder
    _addFolderId = wx.Window.NewControlId()
    _newTaskId = wx.Window.NewControlId()

    #update_context : these properties will be used for update menus
    @property
    def can_copy(self):
        """return info about the possibility to copy"""
        selected = self.selected
        if selected and type(self.selected) is tasks.Task:
            return True
        return False

    @property
    def can_paste(self):
        """is paste possible?"""
        selected = self.selected
        if not selected or clipboard.info != CLIP_FORMAT_TASKS:
            return False
        if not selected.inner_task_container:
            return False
        return True

    @property
    def can_edit_properties(self):
        """is possible to edit properties?"""
        if type(self.selected) is tasks.Tasks:
            return True
        return False

    @property
    def can_delete(self):
        """can delete selected object?"""
        if not self.selected:
            return False
        if type(self.selected) in [model.Project, model.Workspace]:
            return False
        return self.selected.can_delete

    @property
    def can_add_folder(self):
        """can be a folder addeded?"""
        if not self.selected:
            return False
        if type(self.selected) in [model.Project, model.Workspace]:
            return False
        return True

    def __init__(self, parent, root=None):
        """initialize view"""
        self.frame = context.frame
        self._infoHeight = -200
        super(TasksView, self).__init__(parent)
        self.imglist = rc.GetBitmapImageList()
        self.m_tree.SetImageList(self.imglist)
        self.m_tree.AddRoot('Tasks')
        #self.m_evtHandler = wx.PyEvtHandler()
        self._show_info = False
        self._create_menus()
        self._create_toolbars()
        self._bind_events()
        if root is None:
            theApp = context.app
            for wrk in theApp.workspaces:
                self.insert(wrk)
        # enhacement for popu subviews
        else:
            self.insert(root)

    def GetViewStatus(self):
        """Get working info about the view"""
        return str(self.m_tree.GetExpansionState())

    def SetViewStatus(self, status):
        """Set working info about the view"""
        try:
            l = eval(status)
            self.m_tree.SetExpansionState(l)
            return True
        except:
            return False

    def _create_menus(self):
        """Create a custom menu entry in main menu"""
        self._menu = wx.Menu()
        # add folder
        self._addFolder = wx.MenuItem(self._menu, self._addFolderId, u"Folder ...\tShift+Ctrl+F",
            u"add folder", wx.ITEM_NORMAL)
        self._addFolder.SetBitmap(wx.Bitmap(u"app/res/folder.xpm", wx.BITMAP_TYPE_ANY))
        self._menu.AppendItem(self._addFolder)

        # New task
        self._newTask = wx.MenuItem(self._menu, self._newTaskId, u"New task",
            u"create new task repository", wx.ITEM_NORMAL)
        self._newTask.SetBitmap(wx.Bitmap('app/res/new_task.xpm'))
        #self._newTask.SetBitmap(wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_MENU))
        self._menu.AppendItem(self._newTask)
        self.RegisterMenu('Tasks', self._menu)

    def _create_toolbars(self):
        """Create the associated toolbars"""
        # common elements
        self._auiToolBarElements = wx.aui.AuiToolBar(self.frame, wx.ID_ANY, wx.DefaultPosition,
            wx.DefaultSize, wx.aui.AUI_TB_GRIPPER | wx.aui.AUI_TB_HORZ_LAYOUT)
        els = [self._addFolder, self._newTask]
        bar = self._auiToolBarElements
        bar.SetMinSize(wx.Size(24, 24))
        for el in els:
            bar.AddTool(el.GetId(), el.GetLabel(), el.GetBitmap())
        bar.Realize()
        self.frame.m_mgr.AddPane(bar, wx.aui.AuiPaneInfo().Name(u"tasks_toolbar").Top().Hide().
            Caption(u"elements").PinButton(True).Gripper().Dock().Resizable().DockFixed(False).Row(1).Position(0).Layer(10).ToolbarPane())
        self.RegisterToolbar(bar)

    def _bind_events(self):
        """Connect handlers"""
        self.m_tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeSelChanged)
        self.m_tree.Bind(wx.EVT_RIGHT_DOWN, self.OnTreeMenu)

        self.m_tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnEditProperties)

        self.m_tree.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnTasksBeginDrag)
        self.m_tree.Bind(wx.EVT_TREE_END_DRAG, self.OnTasksEndDrag)

        self.BindSpecial(wx.EVT_UPDATE_UI, self.OnUpdateAddFolder, id=self._addFolderId)
        self.BindSpecial(wx.EVT_MENU, self.OnAddFolder, id=self._addFolder.GetId())

        self.BindSpecial(wx.EVT_UPDATE_UI, self.OnUpdateAddNewTask, id=self._newTaskId)
        self.BindSpecial(wx.EVT_MENU, self.OnAddNewTask, id=self._newTask.GetId())

        super(TasksView, self)._bind_events()

    def insert(self, element):
        """Nested insert elements in tree"""
        if self.DoRenderAddElement(element):
            for cls in element._child:
                for k in element[cls]:
                    self.insert(k)

    def DoRenderAddElement(self, obj):
        """Inserts element in tree"""
        # model tree
        treeOrder = [model.Workspace, model.Project, tasks.PendingTasks,
            tasks.CurrentTasks, tasks.FinishedTasks, tasks.TaskFolder, tasks.Task]
        if type(obj) not in treeOrder:
            return False
        ti = treeOrder.index(type(obj))
        #check parent
        if self.m_tree.HoldsObject(obj.parent):
            p = obj.parent
        else:
            p = self.m_tree.GetRootItem()
        if obj.parent is not None:
            # find some major friend item with the same class
            tribal = obj.parent[type(obj)]
            index = tribal.index(obj)
            pre = None
            while index > 0 and pre is None:
                index = index - 1
                candidate = tribal[index]
                if not self.m_tree.HoldsObject(candidate):
                    continue
                pre = candidate
            if pre is not None:
                self.m_tree.InsertItem(p, pre, obj.label,
                    obj.bitmap_index, obj.bitmap_index, obj)
                if hasattr(obj, 'bitmap_open_index'):
                    self.m_tree.SetItemImage(obj,
                        obj.bitmap_open_index, wx.TreeItemIcon_Expanded)
                    self.m_tree.SetItemImage(obj,
                        obj.bitmap_open_index, wx.TreeItemIcon_SelectedExpanded)
                return True
        itemCount = 0
        citem, cookie = self.m_tree.GetFirstChild(p)
        if type(citem) is wx.TreeItemId:
            citem = self.m_tree.__fer__(citem)
        if type(citem) in treeOrder:
            if ti <= treeOrder.index(type(citem)):
                self.m_tree.PrependItem(p, obj.label,
                     obj.bitmap_index, obj.bitmap_index, obj)
                if hasattr(obj, 'bitmap_open_index'):
                    self.m_tree.SetItemImage(obj,
                        obj.bitmap_open_index, wx.TreeItemIcon_Expanded)
                    self.m_tree.SetItemImage(obj,
                        obj.bitmap_open_index, wx.TreeItemIcon_SelectedExpanded)
                return True
        while type(citem) is not wx.TreeItemId or citem.IsOk():
            itemCount = itemCount + 1
            citem, cookie = self.m_tree.GetNextChild(p, cookie)
            if type(citem) not in treeOrder:
                continue
            if ti <= treeOrder.index(type(citem)):
                self.m_tree.InsertItemBefore(p, itemCount,
                     obj.label,
                     obj.bitmap_index, obj.bitmap_index, data=obj)
                if hasattr(obj, 'bitmap_open_index'):
                    self.m_tree.SetItemImage(obj,
                        obj.bitmap_open_index, wx.TreeItemIcon_Expanded)
                    self.m_tree.SetItemImage(obj,
                        obj.bitmap_open_index, wx.TreeItemIcon_SelectedExpanded)
                return True
        #Ok, do apppend
        self.m_tree.AppendItem(p, obj.label,
            obj.bitmap_index, obj.bitmap_index, obj)
        if hasattr(obj, 'bitmap_open_index'):
            self.m_tree.SetItemImage(obj,
                obj.bitmap_open_index, wx.TreeItemIcon_Expanded)
            self.m_tree.SetItemImage(obj,
                obj.bitmap_open_index, wx.TreeItemIcon_SelectedExpanded)
        return True

    def DoRenderRemoveElement(self, obj):
        """Do remove element in tree"""
        if self.m_tree.HoldsObject(obj):
            self.m_tree.Delete(obj)

    def OnUpdateEditProperties(self, event):
        """Do update edit properties"""
        event.Enable(self.can_edit_properties)

    def OnEditProperties(self, event):
        """Edit the task"""
        if type(self.selected) is model.tasks.TaskFolder:
            self.OnEditTaskFolderProperties(self.selected)
        else:
            self.OnEditTaskProperties(self.selected)
        return (context.frame, self.selected)

    @tran.TransactionalMethod('edit task {}')
    @wxx.EditionDialog(mdlg.TaskDialog)
    def OnEditTaskProperties(self, obj):
        """Edit the task"""
        return (context.frame, obj)

    @tran.TransactionalMethod('edit task folder {}')
    @wxx.EditionDialog(mdlg.TaskFolderDialog)
    def OnEditTaskFolderProperties(self, obj):
        """Edit the task folder"""
        return (context.frame, obj)

    def OnTasksBeginDrag(self, event):
        '''Allow drag-and-drop for leaf nodes.'''
        obj = self.m_tree.__fer__(event.GetItem())
        if obj is None:
            return
        if obj.draggable():
            event.Allow()
            self.dragObject = obj

    def OnTasksEndDrag(self, event):
        '''Handle drop operation'''
        if not self.dragObject:
            return
        obj = self.m_tree.__fer__(event.GetItem())
        if obj is None or self.dragObject in obj.path:
            return
        self.dragObject.drop(obj)

    def UpdateElement(self, obj):
        """Update the tree label for a object"""
        if not self.m_tree.HoldsObject(obj):
            return
        self.m_tree.SetItemText(obj, obj.label)
        self.m_tree.SetItemImage(obj,
            obj.bitmap_index, wx.TreeItemIcon_Normal)
        if hasattr(obj, 'bitmap_open_index'):
            self.m_tree.SetItemImage(obj,
                obj.bitmap_open_index, wx.TreeItemIcon_Expanded)
            self.m_tree.SetItemImage(obj,
                obj.bitmap_open_index, wx.TreeItemIcon_SelectedExpanded)
        self.m_tree.SetItemImage(obj,
            obj.bitmap_index, wx.TreeItemIcon_Selected)

    def OnUpdateDelete(self, event):
        """Update delete"""
        event.Enable(self.can_delete)

    def OnTreeSelChanged(self, event):
        """Handle select changed"""
        self.selected = self.m_tree.GetSelection()
        if self.selected and type(self.selected) is tasks.Task:
            if not self._show_info:
                self.m_info = ui.Info(self.m_splitter)
                self.m_splitter.SplitHorizontally(self.m_treePane, self.m_info, self._infoHeight)
                self._show_info = True
                # after show the info, scroll the tree to ensure the item is visible
                wx.YieldIfNeeded()
                self.m_tree.EnsureVisible(self.selected)
            else:
                self.m_info.m_propertyGrid.Clear()
            # fill the grid with the relevant information
            self.m_info.m_text.SetValue(self.selected.note)
            prop = pg.NewStringProperty(label='status', value=self.selected._status)
            self.m_info.m_propertyGrid.Append(prop)
            self.m_info.m_propertyGrid.SetPropertyReadOnly('status')
            prop = pg.NewStringProperty(label='priority', value=self.selected._priority)
            self.m_info.m_propertyGrid.Append(prop)
            self.m_info.m_propertyGrid.SetPropertyReadOnly('priority')
            prop = pg.NewStringProperty(label='type', value=self.selected._taskType)
            self.m_info.m_propertyGrid.Append(prop)
            self.m_info.m_propertyGrid.SetPropertyReadOnly('type')
            prop = pg.NewStringProperty(label='created', value=self.selected._dateCreated)
            self.m_info.m_propertyGrid.Append(prop)
            self.m_info.m_propertyGrid.SetPropertyReadOnly('created')
            prop = pg.NewStringProperty(label='started', value=self.selected._dateBegin)
            self.m_info.m_propertyGrid.Append(prop)
            self.m_info.m_propertyGrid.SetPropertyReadOnly('started')
            prop = pg.NewStringProperty(label='finished', value=self.selected._dateEnd)
            self.m_info.m_propertyGrid.Append(prop)
            self.m_info.m_propertyGrid.SetPropertyReadOnly('finished')
            prop = pg.NewStringProperty(label='reference', value=self.selected._reference)
            self.m_info.m_propertyGrid.Append(prop)
            self.m_info.m_propertyGrid.SetPropertyReadOnly('reference')
        elif self._show_info:
            self._infoHeight = self.m_splitter.GetSashPosition()
            self.m_splitter.Unsplit(self.m_info)
            self.m_info.Destroy()
            self.m_info = None
            self._show_info = False

    def OnTreeMenu(self, event):
        """Handles context tree popup menu"""
        (item, where) = self.m_tree.HitTest(event.GetPosition())
        if item is None:
            return
        self.m_tree.SelectItem(item)
        obj = self.selected
        if obj is None:
            return
        menu = wx.Menu()
        # add elements filtering disabled
        res = app.ui.clone_mnu(self._menu, parent=menu, enabled=True)
        if res is not None:
            menu.AppendSeparator()
            app.ui.append_menuitem_copy(menu, self.frame.editProperties)
            self.PopupMenu(menu, event.GetPosition())
        menu.Destroy()

    def OnDelete(self, event):
        """delete element"""
        obj = self.selected
        if type(obj) is model.tasks.TaskFolder:
            tran.TransactionStack.DoBeginTransaction("delete task folder {}".format(obj._name))
        else:
            tran.TransactionStack.DoBeginTransaction("delete task {}".format(obj._name))
        obj.Delete()
        tran.TransactionStack.DoCommit()

    def OnUpdateAddFolder(self, event):
        """Update add folder method"""
        event.Enable(self.can_add_folder)

    def OnUpdateAddNewTask(self, event):
        """Update add task"""
        event.Enable(self.can_add_task)

    @property
    def can_add_task(self):
        """a task may be added?"""
        if not self.selected:
            return False
        if type(self.selected) in [model.Project, model.Workspace]:
            return False
        return True

    def OnUpdateSaveProject(self, event):
        """Handle update save project"""
        event.Enable(bool(self.selected and self.selected.project))

    def OnSaveProject(self, event):
        """Handle save project"""
        obj = self.selected
        project = obj.project
        if project is None:
            return
        context.app.SaveProject(project)

    @tran.TransactionalMethod('add new task {}')
    @wxx.CreationDialog(mdlg.TaskDialog, model.tasks.Task)
    def OnAddNewTask(self, event):
        """Add task"""
        return (context.frame, self.selected)

    @tran.TransactionalMethod('add task folder {}')
    @wxx.CreationDialog(mdlg.TaskFolderDialog, model.tasks.TaskFolder)
    def OnAddFolder(self, event):
        """Handle add folder command"""
        return (context.frame, self.selected)

    def OnUpdateEditCopy(self, event):
        """Handle update edit copy"""
        event.Enable(self.can_copy)

    def OnEditCopy(self, event):
        """Handle edit copy event"""
        self.copyType = type(self.selected)
        self.copyArgs = self.selected.get_kwargs()

    def OnUpdateEditCut(self, event):
        """Handle cut event"""
        event.Enable(self.can_copy and self.can_delete)

    @tran.TransactionalMethod('cut task')
    def OnEditCut(self, event):
        """Handle cut event"""
        self.copyType = type(self.selected)
        self.copyArgs = self.selected.get_kwargs()
        self.OnDelete(event)

    def OnUpdateEditPaste(self, event):
        """Update edit paste"""
        event.Enable(self.can_paste)

    @tran.TransactionalMethod('paste task')
    def OnEditPaste(self, event):
        """Handle paste event"""
        """Handle paste argument"""
        kwargs = copy.copy(self.copyArgs)
        kwargs['parent'] = self.selected.inner_task_container
        model.tasks.Task(**kwargs)
        return True

    @deco.classproperty
    def name(cls):
        """returns the name of this view"""
        return 'Tasks'

    @classmethod
    def bitmap_index(cls):
        """return the bitmap index"""
        return rc.GetBitmapIndex('tasks')

    @classmethod
    def bitmap(cls):
        """return the bitmap"""
        return rc.GetBitmap('tasks')

    def TreeLeftKey(self, event):
        """If the selected node is expanded, simply collapse it.
        If not, navigate through parent"""
        if not self.selected:
            return
        if self.m_tree.IsExpanded(self.selected):
            self.m_tree.Collapse(self.selected)
        else:
            parent = self.selected.parent
            if self.m_tree.HoldsObject(parent):
                self.m_tree.SelectItem(parent)


