import math

class MyWall(object):

    def __init__(self, obj=None):
        print("runing init method")
        self.Type = 'Wall'

        if obj:
            print("runing obj init method")

            obj.Proxy = self
            self.Object = obj
            self.attach(obj)
            self.Execute(obj)

    def init_properties(self, obj):
        obj.addProperty('App::PropertyString', 'Description', 'Base', 'Wall description').Description = ""

        # level properties
        obj.addProperty('App::PropertyBool', 'BaseConstrain', 'Level properties', 'Constrain the wall base to the parent level').BaseConstrain = True
        obj.addProperty('App::PropertyLength', 'BaseOffset', 'Level properties', 'If the wall base is constrained to the parent level, set Z offset').BaseOffset = '0'
        obj.addProperty('App::PropertyBool', 'TopConstrain', 'Level properties', 'Constrain the wall top to the upper level').TopConstrain = True
        obj.addProperty('App::PropertyLength', 'TopOffset', 'Level properties', 'If the wall top is constrained to the parent level, set Z offset').TopOffset = '0'

        # children joining
        obj.addProperty('App::PropertyLinkChild', 'BaseGeometry', 'Children', 'Link to the child representing the base geometry of the wall shape')
        obj.addProperty('App::PropertyLinkListChild', 'Openings', 'Children', 'Link to the children that will be subtracted from the wall shape')
        obj.addProperty('App::PropertyLinkListChild', 'Fusions', 'Children', 'Link to the children that will be fused with the wall shape')
        obj.addProperty('App::PropertyLinkListChild', 'Components', 'Children', 'Link to the structural children members of the wall')
        obj.addProperty('App::PropertyLinkListChild', 'Windows', 'Children', 'Link to the windows inserted into the wall ')


    def attach(self,obj):

        print("running obj attach method")
        obj.addExtension('App::OriginGroupExtensionPython', None)
        obj.Origin = FreeCAD.ActiveDocument.addObject('App::Origin','Origin')
        self.init_properties(obj)


    def onDocumentRestored(self, obj):

        self.Object = obj


    def __getstate__(self):

        return


    def __setstate__(self,_state):

        return


    def execute(self,obj):

        print("running Wall Execute")

        "builds the wall shape"
        import Part
        
        wall_shape = None
        subtractive_geometries = []

        if hasattr(obj, "BaseGeometry"):
            if obj.BaseGeometry:
                if hasattr(obj.BaseGeometry, "Shape"):
                    wall_shape = obj.BaseGeometry.Shape

        if wall_shape is None:
            return

        # perform boolean cuts of Wall Openings and collect subtractive_geometries
        if hasattr(obj,"Openings"):
            if obj.Openings is not None and obj.Openings != []:
                if len(obj.Openings) > 0:
                    for o in obj.Openings:
                        subtractive_geometries.append(o)
                        ns = wall_shape.cut(o.Shape)
                        wall_shape = ns
        # perform boolean cut of Windows openings (to be implemented)

        # collect additive_geometries
        additive_geometries = [wall_shape]
        for child in obj.Group:
            if hasattr(child, "Shape") and child != obj.BaseGeometry and not child in subtractive_geometries:
                additive_geometries.append(child.Shape)

        # Make a compound out of the wall BaseGeometry and other additive_geometries
        obj.Shape = Part.Compound(additive_geometries)

    def get_wall_points(self, obj):
        return obj.Placement.Base, obj.Placement.multVec(App.Vector(obj.Length,0,0))





class ViewProviderMyWall(object):

    def __init__(self,vobj=None):

        if vobj:
            vobj.Proxy = self
            self.attach(vobj)
        else:
            self.ViewObject = None


    def updateData(self, obj, prop):

        return


    def attach(self,vobj):

        print("running vobj attach method")
        vobj.addExtension('Gui::ViewProviderOriginGroupExtensionPython', None)
        self.ViewObject = vobj


    def __getstate__(self):

        return None


    def __setstate__(self, _state):

        return None


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

    def toggle_display_mode(self, vobj):
        """
        Return the name of the default display mode. It must be defined in getDisplayModes.
        """
        if self.ViewObject.DisplayMode == "Group":
            self.ViewObject.DisplayMode = "Flat Lines"
        elif self.ViewObject.DisplayMode == "Flat Lines":
            self.ViewObject.DisplayMode = "Group"


    def setupContextMenu(self, vobj, menu):
        from PySide import QtCore,QtGui
        action1 = QtGui.QAction("Toggle display mode", menu)
        QtCore.QObject.connect(action1,QtCore.SIGNAL("triggered()"),lambda f=self.toggle_display_mode, arg=vobj:f(arg))
        menu.addAction(action1)

# ---------------------------------------------------------------------------------------------------------------


class WallShape():
    
    def __init__(self, obj):
        """
        Default Constructor
        """
        
        self.Type = 'box'
        self.ratios = None
        
        self.set_properties(obj)
        obj.Proxy = self
        self.Object = obj
    
    def set_properties(self, obj):

        obj.addProperty('App::PropertyString', 'Description', 'Base', 'Wall description').Description = ""
        obj.addProperty('App::PropertyLength', 'LengthForward', 'Dimensions', 'Wall length').LengthForward = '2 m'
        obj.addProperty('App::PropertyLength', 'LengthBackward', 'Dimensions', 'Wall length').LengthBackward = '2 m'
        obj.addProperty('App::PropertyLength', 'LengthTotal', 'Dimensions', 'Wall length').LengthTotal = '4 m'
        obj.addProperty('App::PropertyLength', 'Width', 'Dimensions', 'Wall width').Width = '35 cm'
        obj.addProperty('App::PropertyLength', 'Height', 'Dimensions', 'Wall height').Height = '2.7 m'

        # wall joining
        obj.addProperty('App::PropertyAngle', 'FirstAngle', 'Wall Joining', 'Angular cut of first wall end (to be implemented)').FirstAngle = '90 deg'
        obj.addProperty('App::PropertyAngle', 'LastAngle', 'Wall Joining', 'Angular cut of last wall end (to be implemented)').LastAngle = '90 deg'
        #obj.addProperty('App::PropertyLinkGlobal', 'FirstJoin', 'Wall Joining', 'Join fist wall end with linked wall')
        #obj.addProperty('App::PropertyLinkGlobal', 'LastJoin', 'Wall Joining', 'Join last wall end with linked wall')

        # level properties
        obj.addProperty('App::PropertyBool', 'BaseConstrain', 'Level properties', 'Constrain the wall base to the parent level').BaseConstrain = True
        obj.addProperty('App::PropertyLength', 'BaseOffset', 'Level properties', 'If the wall base is constrained to the parent level, set Z offset').BaseOffset = '0'
        obj.addProperty('App::PropertyBool', 'TopConstrain', 'Level properties', 'Constrain the wall top to the upper level').TopConstrain = True
        obj.addProperty('App::PropertyLength', 'TopOffset', 'Level properties', 'If the wall top is constrained to the parent level, set Z offset').TopOffset = '0'

    def __getstate__(self):
        return self.Type
    
    def __setstate__(self, state):
        if state:
            self.Type = state
    
    def execute(self, obj):
        """
        Called on document recompute
        """
        import Draft, Part
        
        if hasattr(obj,"Length") and hasattr(obj,"Width") and hasattr(obj,"Height"):
            #calculates wall joining trough angles
            #Draft.DraftGeomUtils.findIntersection(p1,p2,p3,p4)
            '''if hasattr(obj, "FirstJoin") and hasattr(obj, "LastJoin"):
                if obj.FirstJoin:
                    p1,p2 = self.get_wall_points(obj)
                    p3,p4 = self.get_wall_points(obj.FirstJoin)
                    base_line_1 = Part.Line(p1,p2)
                    base_line_2 = Part.Line(p3,p4)
                    intersection = Draft.DraftGeomUtils.findIntersection(base_line_1.toShape(),base_line_2.toShape())
                    print(p1,p2,p3,p4,intersection[0])
                    angle = Draft.DraftVecUtils.angle(p2-p1,p4-p3)
                    print(angle)
                    obj.FirstAngle = math.degrees(angle)
            # calculates wedge splays
            first_splay = obj.Width * math.tan(math.pi/2-math.radians(obj.FirstAngle))
            last_splay = obj.Width * math.tan(math.pi/2-math.radians(obj.LastAngle))
        wall_shape = None'''


        obj.Shape = Part.makeBox(obj.LengthTotal, obj.Width, obj.Height)


class ViewProviderWallShape:
    def __init__(self, vobj):
        """
        Set this object to the proxy object of the actual view provider
        """
        self.set_properties(vobj)
        vobj.Proxy = self

    def set_properties(self, vobj):
        if hasattr(vobj, "Transparency"):
            vobj.Transparency = 90
        if hasattr(vobj, "DrawStyle"):
            vobj.DrawStyle = "Dashed"
        pass


# ---------------------------------------------------------------------------------------------------------------

#Add a Wall object to the document
obj = App.ActiveDocument.addObject('Part::FeaturePython', 'Wall', MyWall(), ViewProviderMyWall(), True)

#Add a WallShape object to the document
shp = App.ActiveDocument.addObject('Part::FeaturePython', 'WallShape')
WallShape(shp)
ViewProviderWallShape(shp.ViewObject)

#Add the WallShape as the Wall BaseGeometry
obj.addObject(shp)
obj.BaseGeometry = shp




