# -*- coding: utf-8 -*-

__title__ = "HQ Ruled surface"
__author__ = "Christophe Grellier (Chris_G)"
__license__ = "LGPL 2.1"
__doc__ = """High Quality ruled surface.
The 2 edges (or wires) are reparametrized before surface creation."""

import sys
if sys.version_info.major >= 3:
    from importlib import reload

import os
import FreeCAD
import FreeCADGui
import Part
from freecad.Curves import reparametrize as rp

from freecad.Curves import _utils
from freecad.Curves import ICONPATH

TOOL_ICON = os.path.join( ICONPATH, 'ruled_surface.svg')
#debug = _utils.debug
#debug = _utils.doNothing

props = """
App::PropertyBool
App::PropertyBoolList
App::PropertyFloat
App::PropertyFloatList
App::PropertyFloatConstraint
App::PropertyQuantity
App::PropertyQuantityConstraint
App::PropertyAngle
App::PropertyDistance
App::PropertyLength
App::PropertySpeed
App::PropertyAcceleration
App::PropertyForce
App::PropertyPressure
App::PropertyInteger
App::PropertyIntegerConstraint
App::PropertyPercent
App::PropertyEnumeration
App::PropertyIntegerList
App::PropertyIntegerSet
App::PropertyMap
App::PropertyString
App::PropertyUUID
App::PropertyFont
App::PropertyStringList
App::PropertyLink
App::PropertyLinkSub
App::PropertyLinkList
App::PropertyLinkSubList
App::PropertyMatrix
App::PropertyVector
App::PropertyVectorList
App::PropertyPlacement
App::PropertyPlacementLink
App::PropertyColor
App::PropertyColorList
App::PropertyMaterial
App::PropertyPath
App::PropertyFile
App::PropertyFileIncluded
App::PropertyPythonObject
Part::PropertyPartShape
Part::PropertyGeometryList
Part::PropertyShapeHistory
Part::PropertyFilletEdges
Sketcher::PropertyConstraintList
"""

class HQ_Ruled_SurfaceFP:
    """Creates a ..."""
    def __init__(self, obj, sources):
        """Add the properties"""
        obj.addProperty("App::PropertyLinkList",    "SourceObjects", "HQ_Ruled_Surface", "SourceObjects")
        obj.addProperty("App::PropertyLinkSubList", "SourceShapes",  "HQ_Ruled_Surface", "SourceShapes")
        obj.addProperty("App::PropertyInteger",     "Samples",       "HQ_Ruled_Surface", "Number of orthogonal samples").Samples = 20
        obj.addProperty("App::PropertyFloatConstraint","SmoothingFactorStart", "HQ_Ruled_Surface", "Smoothing factor on curve start")
        obj.addProperty("App::PropertyFloatConstraint","SmoothingFactorEnd", "HQ_Ruled_Surface", "Smoothing factor on curve end")
        obj.addProperty("App::PropertyInteger",     "Method", "HQ_Ruled_Surface", "Projection method (1,2,3,4)").Method = 3
        obj.addProperty("App::PropertyFloat", "Tol3D", "HQ_Ruled_Surface", "3D tolerance").Tol3D = 1e-5
        obj.addProperty("App::PropertyFloat", "Tol2D", "HQ_Ruled_Surface", "Parametric tolerance").Tol2D = 1e-8
        obj.SmoothingFactorStart = (0.2, 0.0, 0.5, 0.05)
        obj.SmoothingFactorEnd = (0.2, 0.0, 0.5, 0.05)
        objs = []
        shapes = []
        for s in sources:
            if isinstance(s, (list, tuple)):
                shapes.append(s)
            else:
                objs.append(s)
        obj.SourceObjects = objs
        obj.SourceShapes = shapes
        obj.setEditorMode("Tol3D",2)
        obj.setEditorMode("Tol2D",2)
        obj.setEditorMode("Method",0)
        obj.Proxy = self

    def get_curves(self, obj):
        curves = []
        edges = []
        for o in obj.SourceObjects:
            curves.extend(o.Shape.Wires)
            edges.extend(o.Shape.Edges)
        if len(curves) == 2:
            return curves[0], curves[1]
        if len(edges) == 2:
            return edges[0], edges[1]
        edges = _utils.getShape(obj, "SourceShapes", "Edge")
        if len(edges) == 2:
            return edges[0], edges[1]

    def execute(self, obj):
        c1, c2 = self.get_curves(obj)
        nc1, nc2 = rp.reparametrize(c1, c2, num=obj.Samples, smooth_start=obj.SmoothingFactorStart, smooth_end=obj.SmoothingFactorEnd, method=obj.Method )
        #com = Part.Compound([nc1.toShape(), nc2.toShape()])
        rs = Part.makeRuledSurface(nc1.toShape(), nc2.toShape())
        if isinstance(rs, Part.Face) and rs.isValid():
            obj.Shape = rs

    def onChanged(self, obj, prop):
        return(False)

class HQ_Ruled_SurfaceVP:
    def __init__(self,vobj):
        vobj.Proxy = self
       
    def getIcon(self):
        return(TOOL_ICON)

    def attach(self, vobj):
        self.Object = vobj.Object

    def __getstate__(self):
        return({"name": self.Object.Name})

    def __setstate__(self,state):
        self.Object = FreeCAD.ActiveDocument.getObject(state["name"])
        return(None)

class HQ_Ruled_Surface_Command:
    """Creates a ..."""
    def makeFeature(self, edges):
        fp = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","HQ Ruled Surface")
        HQ_Ruled_SurfaceFP(fp, edges)
        HQ_Ruled_SurfaceVP(fp.ViewObject)
        FreeCAD.ActiveDocument.recompute()

    def Activated(self):
        s = FreeCADGui.Selection.getSelectionEx()
        edges = []
        for so in s:
            for i in range(len(so.SubObjects)):
                #subshapes(su)
                if isinstance(so.SubObjects[i], Part.Edge):
                    edges.append((so.Object,(so.SubElementNames[i], )))
            if not so.HasSubObjects:
                if so.Object.Shape.Wires:
                    edges.append(so.Object)
                elif so.Object.Shape.Edges:
                    edges.append(so.Object)

        if len(edges) < 1:
            FreeCAD.Console.PrintError("Select something first !\n")
        else:
            self.makeFeature(edges)

    def IsActive(self):
        if FreeCAD.ActiveDocument:
            return(True)
        else:
            return(False)

    def GetResources(self):
        return {'Pixmap' : TOOL_ICON, 'MenuText': __title__, 'ToolTip': __doc__}

FreeCADGui.addCommand('hq_ruled_surface', HQ_Ruled_Surface_Command())