from draftobjects.base import DraftObject
from draftutils.utils import get_param


class circle(DraftObject):
    def __init__(self, obj):
        ''' Creates a circle object '''
        super(circle, self).__init__(obj, "Circle")
        self.type = 'circle'
        self.components = []

    def execute(self, obj):
        ''' Executes the circle '''
        import FreeCAD as App
        import DraftGeomUtils
        import DraftVecUtils

        center = get_param(obj, "center")
        radius = get_param(obj, "radius")

        if center is None:
            center = App.Vector(0, 0, 0)
        if radius is None:
            radius = 1

        center = DraftVecUtils.to_vector(center)
        radius = DraftVecUtils.to_vector(radius)

        circle = DraftGeomUtils.make_circle(center, radius)

        self.components.append(circle)

class line(DraftObject):
    def __init__(self, obj):
        ''' Creates a line object '''
        super(line, self).__init__(obj, "Line")
        self.type = 'line'
        self.components = []

    def execute(self, obj):
        ''' Executes the line '''
        import FreeCAD as App
        import DraftGeomUtils
        import DraftVecUtils

        start = get_param(obj, "start")
        end = get_param(obj, "end")

        if start is None:
            start = App.Vector(0, 0, 0)
        if end is None:
            end = App.Vector(1, 1, 1)

        start = DraftVecUtils.to_vector(start)
        end = DraftVecUtils.to_vector(end)

        line = DraftGeomUtils.make_line(start, end)

        self.components.append(line)


class polyline(DraftObject):
    def __init__(self, obj):
        ''' Creates a polyline object '''
        super(Wire, self).__init__(obj, "Wire")
        self.type = 'polyline'
        self.components = []

    def execute(self, obj):
        ''' Executes the polyline '''
        import FreeCAD as App
        import Part
        V1 = App.Vector(0, 10, 0)
        V2 = App.Vector(30, 10, 0)
        V3 = App.Vector(30, -10, 0)
        V4 = App.Vector(0, -10, 0)

        VC1 = App.Vector(-10, 0, 0)
        C1 = Part.Arc(V1, VC1, V4)
        VC2 = App.Vector(40, 0, 0)
        C2 = Part.Arc(V2, VC2, V3)

        L1 = Part.LineSegment(V1, V2)
        L2 = Part.LineSegment(V3, V4)

        S1 = Part.Shape([C1, L1, C2, L2])

        W = Part.Wire(S1.Edges)



import FreeCAD as App
import Part

class Polyline:
    def __init__(self):
        self.segments = []
        self.setProperties(obj)

    def setProperties(self, obj):
        ''' do something '''

    def onDocumentRestored(self,obj):
        self.setProperties(obj)

    def add_line(self, start, end):
        line_segment = Part.LineSegment(start, end)
        self.segments.append(line_segment)

    def add_arc(self, start, end, center, tangent=True):
        if tangent:
            arc = Part.ArcOfCircle(start, end, center)
        else:
            start_point = start - center
            end_point = end - center
            arc = Part.ArcOfCircle(start_point, end_point, center)
        self.segments.append(arc)

    def create_wire(self):
        wire = Part.Wire(self.segments)
        return wire

    def create_shape(self):
        wire = self.create_wire()
        shape = Part.Shape(wire)
        return shape

    def create_object(self, name):
        shape = self.create_shape()
        obj = App.ActiveDocument.addObject("Part::Feature", name)
        obj.Shape = shape
        return obj

    def execute(self,obj):
        ''' '''

class editPolyline:
    def __init__(self):
        import draftguitools.gui_trackers as DraftTrackers

        self.objects = []
        self.state = 0
        self.direction = None
        self.distance = 1500
        self.point = None
        self.tracker = DraftTrackers.wireTracker(Part.Wire(Part.makePolygon([FreeCAD.Vector(),FreeCAD.Vector(1,1,1)])))

        # event callbacks
        self._keyPressedCB = None
        self._mouseMovedCB = None
        self._mousePressedCB = None

        self.view = FreeCADGui.activeDocument().activeView()
        self.render_manager = FreeCADGui.ActiveDocument.ActiveView.getViewer().getSoRenderManager()

        #  Callbacks
        self.unregister_editing_callbacks()
        self.register_editing_callbacks()

    # -------------------------------------------------------------------------
    # SCENE EVENTS CALLBACKS
    # -------------------------------------------------------------------------
    def register_editing_callbacks(self):
        """ Register editing callbacks (former action function) """

        print("Registering callbacks")
        if self._keyPressedCB is None:
            self._keyPressedCB = self.view.addEventCallbackPivy(coin.SoKeyboardEvent.getClassTypeId(), self.keyPressed)

        if self._mousePressedCB is None:
            self._mousePressedCB = self.view.addEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), self.mousePressed)

        if self._mouseMovedCB is None:
            self._mouseMovedCB = self.view.addEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(), self.mouseMoved)

        print("end Registering callbacks")

    def unregister_editing_callbacks(self):
        """ Remove callbacks used during editing if they exist """

        print("Unregistering callbacks")
        if self._keyPressedCB:
            self.view.removeEventCallbackPivy(coin.SoKeyboardEvent.getClassTypeId(), self._keyPressedCB)
            self._keyPressedCB = None

        if self._mousePressedCB:
            self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), self._mousePressedCB)
            self._mousePressedCB = None

        if self._mouseMovedCB:
            self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(), self._mouseMovedCB)
            self._mouseMovedCB = None
        print("End unregistering callbacks")

    # -------------------------------------------------------------------------
    # SCENE EVENT HANDLERS
    # -------------------------------------------------------------------------
    def keyPressed(self, event_callback):
        event = event_callback.getEvent()
        print(event.getKey())
        if event.getState() == event.UP:
            if event.getKey() == 65307:
                self.quit()
            elif event.getKey() == 65293:
                print("ENTER")
                self.state += 1
                if self.state == 2:
                    '''print("----------------------------------------------------------------")
                    print(" -- objects: ")
                    print(self.objects)
                    print(" -- distance:")
                    print(self.distance)
                    print("----------------------------------------------------------------")'''
                    self.calculateTrenches()
                    self.quit()

            '''elif event.getKey() == ord("q"):  # or event.getKey() == ord(65307):
                if self.obj:
                    self.obj.ViewObject.Proxy.doubleClicked(self.obj.ViewObject)
                else:
                    self.quit()
            elif event.getKey() == ord("s"):
                sel = FreeCADGui.Selection.getSelectionEx()
                tup = None
                if len(sel) == 1:
                    tup = (sel[0].Object, sel[0].SubElementNames)
                for i in range(len(self.selected_objects)):
                    if isinstance(self.selected_objects[i], MarkerOnShape):
                        self.selected_objects[i].sublink = tup
                        # FreeCAD.Console.PrintMessage("Snapped to {}\n".format(str(self.selected_objects[i].sublink)))
                        self.selected_objects[i].drag_start()
                        self.selected_objects[i].drag((0, 0, 0.))
                        self.selected_objects[i].drag_release()
            elif (event.getKey() == 65535) or (event.getKey() == 65288):  # Suppr or Backspace
                # FreeCAD.Console.PrintMessage("Some objects have been deleted\n")
                pts = list()
                for o in self.dynamic_objects:
                    if isinstance(o, MarkerOnShape):
                        pts.append(o)
                self.points = pts
                self.setupInteractionSeparator()'''

    def mousePressed(self, event_callback):
        """ Mouse button event handler, calls: startEditing, endEditing, addPoint, delPoint """
        event = event_callback.getEvent()
        pos = event.getPosition().getValue()
        listObjects = FreeCADGui.ActiveDocument.ActiveView.getObjectsInfo((int(pos[0]), int(pos[1])))

        if event.getButton() == event.BUTTON1:  # left click
            if event.getState() == coin.SoMouseButtonEvent.DOWN:
                if self.state == 0:
                    ''' Select objects '''
                    obj = FreeCAD.ActiveDocument.getObject(listObjects[0]['Object'])
                    if obj in self.objects:
                        self.objects.remove(obj)
                    else:
                        self.objects.append(obj)
                    numobjs = len(self.objects)
                    if numobjs == 0:
                        self.tracker.finalize()
                    elif numobjs == 1:
                        self.tracker.updateFromPointlist([obj.Placement.Base for obj in self.objects])
                        self.tracker.on()
                    else:
                        self.tracker.updateFromPointlist([obj.Placement.Base for obj in self.objects])


                elif self.state == 1:
                    ''' Select distance and direction '''
                    self.direction = FreeCAD.Vector(listObjects[0]['x'], listObjects[0]['y'], listObjects[0]['z'])
                #self.point = None

            elif event.getState() == coin.SoMouseButtonEvent.UP:
                if listObjects and self.point:
                    if self.state == 0:
                        FreeCADGui.Selection.clearSelection()
                        for obj in listObjects:
                            FreeCADGui.Selection.addSelection(obj)

        """if (event.getState() == coin.SoMouseButtonEvent.DOWN) and (
                event.getButton() == event.BUTTON1):  # left click
            print("Mouse button down and mouse button 1")
            if not event.wasAltDown():
                if self.editing is None:
                    ''' do something'''
                else:
                    self.endEditing(self.obj, self.editing)

            elif event.wasAltDown():  # left click with ctrl down
                self.display_tracker_menu(event)

        elif (event.getState() == coin.SoMouseButtonEvent.DOWN) and (
                event.getButton() == event.BUTTON2):  # right click
            self.display_tracker_menu(event)"""

    def mouseMoved(self, event_callback):
        """ Execute as callback for mouse movement. Update tracker position and update preview ghost. """
        if self.state == 1:
            event = event_callback.getEvent()
            pos = event.getPosition().getValue()
            listObjects = FreeCADGui.ActiveDocument.ActiveView.getObjectsInfo((int(pos[0]), int(pos[1])))
            print(listObjects)
            point = FreeCAD.Vector(listObjects[0]['x'], listObjects[0]['y'], listObjects[0]['z'])
            pts = [obj.Placement.Base for obj in self.objects]
            offset = point.sub(pts[0])
            self.tracker.updateFromPointlist([point.add(offset) for point in pts])

        '''listObjects = FreeCADGui.ActiveDocument.ActiveView.getObjectsInfo((int(pos[0]), int(pos[1])))
        if listObjects:
            # {'x': 483239.09375, 'y': 783855.8125, 'z': 797695.0, 'Document': 'Salinas_II_GRG___v3',
            # 'Object': 'Wire023', 'Component': 'Edge30'}]
            for obj in listObjects:
                print(listObjects)
                if obj.Object == self.obj.Name:
                    print(listObjects)
        '''

    def calculateTrenches(self):
        if len(self.objects)>1:
            import Draft
            pts = [obj.Placement.Base for obj in self.objects]
            vec = self.direction.sub(pts[0])
            pts1 = [point.add(vec) for point in pts]
            for i in range(len(pts1) - 1):
                makeTrench(Draft.makeLine(pts1[i], pts1[i + 1]))

        return
        pts = [obj.Placement.Base for obj in FreeCADGui.Selection.getSelection()]
        from sklearn.cluster import OPTICS, cluster_optics_dbscan
        import numpy as np
        clust = OPTICS(min_samples = 5, xi=0.05, min_cluster_size=0.05)
        X = np.array(pts)

        # Run the fit
        clust.fit(X)

        labels_050 = cluster_optics_dbscan(
            reachability=clust.reachability_,
            core_distances=clust.core_distances_,
            ordering=clust.ordering_,
            eps=0.5,
        )
        labels_200 = cluster_optics_dbscan(
            reachability=clust.reachability_,
            core_distances=clust.core_distances_,
            ordering=clust.ordering_,
            eps=2,
        )

        space = np.arange(len(X))
        reachability = clust.reachability_[clust.ordering_]
        labels = clust.labels_[clust.ordering_]
        print("\n")
        print(" Space: ", space)
        print(" Reachability", reachability)
        print(" Labels", labels)

        return
        from scipy import stats
        xx = list()
        yy = list()
        zz = list()
        for point in pts:
            xx.append(point.x)
            yy.append(point.y)
            zz.append(point.z)
        slope, intercept, r, p, std_err = stats.linregress(xx, yy)
        def myfunc(val):
            return slope * val + intercept

        newzz = list(map(myfunc, [xx[0], xx[-1]]))
        points3D = list()
        points3D.append(FreeCAD.Vector(xx[0], yy[0], newzz[0]))
        points3D.append(FreeCAD.Vector(xx[-1], yy[-1], newzz[1]))

    def quit(self):
        print("Quit")
        self.tracker.finalize()
        self.unregister_editing_callbacks()
