from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QAction
from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal

from OCP.AIS import AIS_ColoredShape
from OCP.gp import gp_Ax3

from cadquery import Vector

from ..mixins import ComponentMixin
from ..icons import icon


        
class CQChildItem(QTreeWidgetItem):
    
    def __init__(self,cq_item,**kwargs):
        
        super(CQChildItem,self).\
            __init__([type(cq_item).__name__,str(cq_item)],**kwargs)
        
        self.cq_item = cq_item

class CQStackItem(QTreeWidgetItem):
    
    def __init__(self,name,workplane=None,**kwargs):
        
        super(CQStackItem,self).__init__([name,''],**kwargs)
        
        self.workplane = workplane


class CQObjectInspector(QTreeWidget,ComponentMixin):
    
    name = 'CQ Object Inspector'
    
    sigRemoveObjects = pyqtSignal(list)
    sigDisplayObjects = pyqtSignal(list,bool)
    sigShowPlane = pyqtSignal([bool],[bool,float])
    sigChangePlane = pyqtSignal(gp_Ax3)
    
    def  __init__(self,parent):
        
        super(CQObjectInspector,self).__init__(parent)
        self.setHeaderHidden(False)
        self.setRootIsDecorated(True)
        self.setContextMenuPolicy(Qt.ActionsContextMenu)
        self.setColumnCount(2)
        self.setHeaderLabels(['Type','Value'])
        
        self.root = self.invisibleRootItem()
        self.inspected_items = []
        
        self._toolbar_actions = \
            [QAction(icon('inspect'),'Inspect CQ object',self,\
                     toggled=self.inspect,checkable=True)]
        
        self.addActions(self._toolbar_actions)
        
    def menuActions(self):
        
        return {'Tools' : self._toolbar_actions}
    
    def toolbarActions(self):
        
        return self._toolbar_actions
    
    @pyqtSlot(bool)
    def inspect(self,value):
        
        if value:
            self.itemSelectionChanged.connect(self.handleSelection)
            self.itemSelectionChanged.emit()
        else:
            self.itemSelectionChanged.disconnect(self.handleSelection)
            self.sigRemoveObjects.emit(self.inspected_items)
            self.sigShowPlane.emit(False)
            
    @pyqtSlot()    
    def handleSelection(self):
        
        inspected_items = self.inspected_items
        self.sigRemoveObjects.emit(inspected_items)
        inspected_items.clear()
        
        items = self.selectedItems()
        if len(items) == 0:
            return
        
        item = items[-1]
        if type(item) is CQStackItem:
            cq_plane = item.workplane.plane
            dim = item.workplane.largestDimension()
            plane = gp_Ax3(cq_plane.origin.toPnt(),
                           cq_plane.zDir.toDir(),
                           cq_plane.xDir.toDir())
            self.sigChangePlane.emit(plane)
            self.sigShowPlane[bool,float].emit(True,dim)
            
            for child in (item.child(i) for i in range(item.childCount())):
                obj = child.cq_item
                if hasattr(obj,'wrapped') and type(obj) != Vector:
                    ais = AIS_ColoredShape(obj.wrapped)
                    inspected_items.append(ais)
                
        else:
            self.sigShowPlane.emit(False)
            obj = item.cq_item
            if hasattr(obj,'wrapped') and type(obj) != Vector:
                ais = AIS_ColoredShape(obj.wrapped)
                inspected_items.append(ais)
            
        self.sigDisplayObjects.emit(inspected_items,False)
    
    @pyqtSlot(object)
    def setObject(self,cq_obj):
        
        self.root.takeChildren()
        
        # iterate through parent objects if they exist
        while getattr(cq_obj, 'parent', None):
            current_frame = CQStackItem(str(cq_obj.plane.origin),workplane=cq_obj)
            self.root.addChild(current_frame)
            
            for obj in cq_obj.objects:
                current_frame.addChild(CQChildItem(obj))
            
            cq_obj = cq_obj.parent