from __future__ import division # allows floating point division from integers
import FreeCAD, Part, math
import os, dummy, FreeCADGui
from FreeCAD import Base
from pivy import coin
import CoinNodes

path_curvesWB = os.path.dirname(dummy.__file__)
path_curvesWB_icons =  os.path.join( path_curvesWB, 'Resources', 'icons')

DEBUG = 1

def debug(string):
    if DEBUG:
        FreeCAD.Console.PrintMessage(string)
        FreeCAD.Console.PrintMessage("\n")


class hook:
    def __init__(self, obj , edge):
        ''' Add the properties '''
        debug("\Hook class Init\n")
        obj.addProperty("App::PropertyLinkSub",      "Edge",          "Base",     "Support edge").Edge = edge
        obj.addProperty("App::PropertyEnumeration",  "Method",        "Position", "Position").Method=["Fixed","Parameter","Distance-From-Start","Distance-From-End"]
        obj.addProperty("App::PropertyFloat",        "X",             "Value", "X coordinate")
        obj.addProperty("App::PropertyFloat",        "Y",             "Value", "Y coordinate")
        obj.addProperty("App::PropertyFloat",        "Z",             "Value", "Z coordinate")
        obj.addProperty("App::PropertyFloat",        "Parameter",     "Value", "Parameter value")
        obj.addProperty("App::PropertyFloat",        "StartDistance", "Value", "Distance from edge start")
        obj.addProperty("App::PropertyFloat",        "EndDistance",   "Value", "Distance to edge end")
        obj.addProperty("App::PropertyVector",       "Center",        "Position", "Center")
        #obj.Method = "Parameter"
        obj.Proxy = self

    def getEdge(self, obj):
        if obj.Edge:
            o = obj.Edge[0]
            e = obj.Edge[1][0]
            n = eval(e.lstrip('Edge'))
            return o.Shape.Edges[n-1]
        else:
            debug("getEdge failed")
            return None

    def execute(self, obj):
        debug("* Hook : execute *\n")
        e = self.getEdge(obj)
        if e == None:
            return
        #center = FreeCAD.Vector(0,0,0)
        if obj.Method == "Fixed":
            p = FreeCAD.Vector(obj.X, obj.Y, obj.Z)
            v = Part.Vertex(p)
            obj.Center = v.distToShape(e)[1][0][1]
        elif obj.Method == "Parameter":
            obj.Center = e.valueAt(obj.Parameter)
        elif obj.Method == "Distance-From-Start":
            par = e.getParameterByLength(obj.StartDistance)
            obj.Center = e.valueAt(par)
        elif obj.Method == "Distance-From-End":
            par = e.getParameterByLength(e.Length - obj.EndDistance)
            obj.Center = e.valueAt(par)
        #radius = 1.0 * e.Length / 100.0
        #sphere = Part.Sphere()
        #sphere.Radius = radius
        #sphere.Center = obj.Center
        obj.Shape = Part.Vertex(obj.Center)

    def setEditormode(self, fp, l):
        if not len(l) == 6:
            return
        i = 0
        for prop in ["X","Y","Z","Parameter","StartDistance","EndDistance"]:
            fp.setEditorMode(prop, l[i])
            i += 1

    def onChanged(self, fp, prop):
        debug("Hook : onChanged -> %s"%str(prop))
        #print fp
        if not fp.Edge:
            return
        else:
            e = self.getEdge( fp)
        #if prop == "Edge":
            #self.setEdge( fp)

        if prop == "Method":
            if fp.Method == "Fixed":
                self.setEditormode(fp, [0,0,0,2,2,2])
                fp.X = fp.Center.x
                fp.Y = fp.Center.y
                fp.Z = fp.Center.z
                
            elif fp.Method == "Parameter":
                self.setEditormode(fp, [2,2,2,0,2,2])
                v = Part.Vertex( fp.Center )
                try:
                    fp.Parameter = e.Curve.parameter(fp.Center)
                except:
                    pass
            elif fp.Method == "Distance-From-Start":
                self.setEditormode(fp, [2,2,2,2,0,2])
                par = e.getParameterByLength(fp.StartDistance)
                fp.Center = e.valueAt(par)
            elif fp.Method == "Distance-From-End":
                self.setEditormode(fp, [2,2,2,2,2,0])
                par = e.getParameterByLength(e.Length - fp.EndDistance)
                fp.Center = e.valueAt(par)
        if prop in ['X','Y','Z']:
            p = FreeCAD.Vector(fp.X, fp.Y, fp.Z)
            v = Part.Vertex(p)
            center = v.distToShape(e)[1][0][1]
            fp.Center = center
        if prop == "Parameter":
            if fp.Parameter < e.FirstParameter:
                fp.Parameter = e.FirstParameter
            elif fp.Parameter > e.LastParameter:
                fp.Parameter = e.LastParameter
            debug("Hook : Parameter changed to %f"%(fp.Parameter))
            fp.Center = e.valueAt(fp.Parameter)
        if prop == "StartDistance":
            if fp.StartDistance < 0.0:
                fp.StartDistance = 0.0
            elif fp.StartDistance > e.Length:
                fp.StartDistance = e.Length
            par = e.getParameterByLength(fp.StartDistance)
            fp.Center = e.valueAt(par)
            debug("Hook : StartDistance changed to %f"%(fp.StartDistance))
        if prop == "EndDistance":
            if fp.EndDistance < 0:
                fp.EndDistance = 0
            elif fp.EndDistance > e.Length:
                fp.EndDistance = e.Length
            par = e.getParameterByLength(e.Length - fp.EndDistance)
            fp.Center = e.valueAt(par)
            debug("Hook : EndDistance changed to %f"%(fp.EndDistance))


class ViewProviderHook:
    def __init__(self,vobj):
        vobj.Proxy = self
       
    def getIcon(self):
        return (path_curvesWB_icons+'/discretize.svg')

    def attach(self, vobj):
        self.ViewObject = vobj
        self.Object = vobj.Object
        
        #self.selectionNode = coin.SoType.fromName("SoFCSelection").createInstance()
        #self.selectionNode.documentName.setValue(FreeCAD.ActiveDocument.Name)
        #self.selectionNode.objectName.setValue(vobj.Object.Name) # here obj is the ViewObject, we need its associated App Object
        #self.selectionNode.subElementName.setValue("Vertex")
        
        
        #self.node = coin.SoSeparator()
        #self.node.setName("Hook")
        #self.coord = coin.SoCoordinate3()
        #self.marker = coin.SoSphere() #coin.SoMarkerSet() #((1,0,0),coin.SoMarkerSet.DIAMOND_FILLED_9_9)
        ##self.marker.markerIndex = coin.SoMarkerSet.DIAMOND_FILLED_9_9
        #self.color = coin.SoBaseColor()
        #self.color.rgb = (1,0,0)
        
        
        ##self.node.addChild(self.color)
        ##self.node.addChild(self.coord)
        ##self.node.addChild(self.marker)
        #self.selectionNode.addChild(self.color)
        #self.selectionNode.addChild(self.coord)
        #self.selectionNode.addChild(self.marker)
        
        #vobj.addDisplayMode(self.selectionNode,"Wireframe")

    #def updateData(self, fp, prop):
        #if prop == "Center":
            #vec = coin.SbVec3f(fp.Center.x, fp.Center.y, fp.Center.z)
            #self.coord.point.setValue(vec)
            ##self.coord.point.setValues(0,len([vec]),[vec])

    #def getDisplayModes(self,obj):
         #"Return a list of display modes."
         #modes=[]
         #modes.append("Wireframe")
         #return modes

    #def getDefaultDisplayMode(self):
         #'''Return the name of the default display mode. It must be defined in getDisplayModes.'''
         #return "Wireframe"

    #def setDisplayMode(self,mode):
         #return mode
  
    def setEdit(self,vobj,mode):
        return False
    
    def unsetEdit(self,vobj,mode):
        return

    def __getstate__(self):
        return None

    def __setstate__(self,state):
        return None

    #def claimChildren(self):
        #return None #[self.Object.Edge[0]]
        
    #def onDelete(self, feature, subelements): # subelements is a tuple of strings
        #try:
            #self.Object.Edge[0].ViewObject.Visibility=True
            ##self.Object.Tool.ViewObject.show()
        #except Exception as err:
            #FreeCAD.Console.PrintError("Error in onDelete: {0} \n".format(err))
        #return True


class hookCmd:
    def parseSel(self, selectionObject):
        res = []
        for obj in selectionObject:
            if obj.HasSubObjects:
                subobj = obj.SubObjects[0]
                if issubclass(type(subobj),Part.Edge):
                    res.append((obj.Object,[obj.SubElementNames[0]]))
            else:
                res.append((obj.Object,["Edge1"]))
        return res

    def Activated(self):
        s = FreeCADGui.Selection.getSelectionEx()
        edges = self.parseSel(s)
        for e in edges:
            obj=FreeCAD.ActiveDocument.addObject("Part::FeaturePython",u"Hook") #add object to document
            hook(obj,e)
            ViewProviderHook(obj.ViewObject)
            obj.ViewObject.PointSize = 5
            obj.Method = "Parameter"
        FreeCAD.ActiveDocument.recompute()
            
    def GetResources(self):
        return {'Pixmap' : path_curvesWB_icons+'/discretize.svg', 'MenuText': 'Hook', 'ToolTip': 'Creates a hook on edge'}

FreeCADGui.addCommand('hook', hookCmd())