# /******************************************************************************
# *   Copyright (c) 2012 Jan Rheinländer <jrheinlaender@users.sourceforge.net> *
# *                                                                            *
# *   This file is part of the FreeCAD CAx development system.                 *
# *                                                                            *
# *   This library is free software; you can redistribute it and/or            *
# *   modify it under the terms of the GNU Library General Public              *
# *   License as published by the Free Software Foundation; either             *
# *   version 2 of the License, or (at your option) any later version.         *
# *                                                                            *
# *   This library  is distributed in the hope that it will be useful,         *
# *   but WITHOUT ANY WARRANTY; without even the implied warranty of           *
# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
# *   GNU Library General Public License for more details.                     *
# *                                                                            *
# *   You should have received a copy of the GNU Library General Public        *
# *   License along with this library; see the file COPYING.LIB. If not,       *
# *   write to the Free Software Foundation, Inc., 59 Temple Place,            *
# *   Suite 330, Boston, MA  02111-1307, USA                                   *
# *                                                                            *
# ******************************************************************************/

import FreeCAD, FreeCADGui
import Part, Sketcher


class ShaftFeature:
    "Creates and updates the feature of the shaft"

    App = FreeCAD
    Gui = FreeCADGui

    def __init__(self, doc):
        "Create new feature"
        self.Doc = doc

        # TODO: Discover existing sketch and get data from it
        self.sketch = self.Doc.addObject("Sketcher::SketchObject", "SketchShaft")
        self.sketch.Placement = self.App.Placement(
            self.App.Vector(0, 0, 0), self.App.Rotation(0, 0, 0, 1)
        )

        self.feature = 0
        self.segments = 0  # number of segments
        self.totalLength = 0  # total length of all segments
        self.lastRadius = 0  # radius of last segment (required for adding segments)

    def addSegment(self, length, diameter, innerdiameter):
        "Add a segment at the end of the shaft"
        # Find constraint indices of vertical line constraint, horizontal line constraint
        # FIXME: Should have a unique id instead of indices that might change with user editing
        # 0-3 belong to the centerline
        # 4-6 to the first vertical section
        # 7-9 to the first horizontal section
        # 10-12 to the second vertical section
        # etc. etc.
        constrRadius = 4 + self.segments * 6
        constrLength = 7 + self.segments * 6
        constrInnerRadius = 1 + self.segments * 6
        # Find line index of vertical segment, horizontal segment, last shaft segment
        # FIXME: Should have a unique id instead of indices that might change with user editing
        segRadius = 1 + self.segments * 2
        segLength = 2 + self.segments * 2
        prevSegLength = 0 + self.segments * 2
        prevSegEnd = 3 + (self.segments - 1) * 2
        segEnd = prevSegEnd + 2

        radius = diameter / 2
        innerradius = innerdiameter / 2
        oldLength = self.totalLength
        self.totalLength += length
        self.segments += 1

        if oldLength == 0:
            # First segment of shaft
            # Create centerline
            self.sketch.addGeometry(
                Part.LineSegment(self.App.Vector(0, 0, 0), self.App.Vector(self.totalLength, 0, 0))
            )
            self.sketch.addConstraint(
                Sketcher.Constraint("DistanceX", 0, self.totalLength)
            )  # Constraint1
            self.sketch.addConstraint(
                Sketcher.Constraint("DistanceY", -1, 1, 0, 1, innerradius)
            )  # Constraint2
            self.sketch.addConstraint(Sketcher.Constraint("PointOnObject", 0, 1, -2))  # Constraint3
            self.sketch.addConstraint(Sketcher.Constraint("Horizontal", 0))  # Constraint4
            # Create first segment
            self.sketch.addGeometry(
                Part.LineSegment(self.App.Vector(0, innerradius, 0), self.App.Vector(0, radius, 0))
            )
            self.sketch.addConstraint(
                Sketcher.Constraint("DistanceY", -1, 1, 1, 2, radius)
            )  # Constraint5
            self.sketch.addConstraint(Sketcher.Constraint("Coincident", 0, 1, 1, 1))  # Constraint6
            self.sketch.addConstraint(Sketcher.Constraint("Vertical", 1))  # Constraint7
            self.sketch.addGeometry(
                Part.LineSegment(self.App.Vector(0, radius, 0), self.App.Vector(length, radius, 0))
            )
            self.sketch.addConstraint(Sketcher.Constraint("DistanceX", 2, length))  # Constraint8
            self.sketch.addConstraint(Sketcher.Constraint("Coincident", 2, 1, 1, 2))  # Constraint9
            self.sketch.addConstraint(Sketcher.Constraint("Horizontal", 2))  # Constraint10
        else:
            # remove line that closes the shaft
            self.sketch.delGeometry(prevSegEnd)
            # TODO: Delete the two constraints? Or will they disappear automatically?
            # Adjust length of centerline
            self.sketch.setDatum(0, self.totalLength)
            # Add segment at the end
            self.sketch.addGeometry(
                Part.LineSegment(
                    self.App.Vector(oldLength, self.lastRadius, 0),
                    self.App.Vector(oldLength, radius, 0),
                )
            )
            self.sketch.addConstraint(Sketcher.Constraint("DistanceY", -1, 1, segRadius, 2, radius))
            self.sketch.addConstraint(
                Sketcher.Constraint("Coincident", segRadius, 1, prevSegLength, 2)
            )
            self.sketch.addConstraint(Sketcher.Constraint("Vertical", segRadius))
            self.sketch.addGeometry(
                Part.LineSegment(
                    self.App.Vector(oldLength, radius, 0),
                    self.App.Vector(oldLength + length, radius, 0),
                )
            )
            self.sketch.addConstraint(Sketcher.Constraint("DistanceX", segLength, length))
            self.sketch.addConstraint(Sketcher.Constraint("Coincident", segLength, 1, segRadius, 2))
            self.sketch.addConstraint(Sketcher.Constraint("Horizontal", segLength))

        # close the sketch
        self.sketch.addGeometry(
            Part.LineSegment(
                self.App.Vector(oldLength + length, radius, 0),
                self.App.Vector(oldLength + length, innerradius, 0),
            )
        )
        self.sketch.addConstraint(Sketcher.Constraint("Coincident", 0, 2, segEnd, 2))
        self.sketch.addConstraint(Sketcher.Constraint("Coincident", segEnd, 1, segLength, 2))
        self.lastRadius = radius

        if oldLength == 0:
            # create feature
            self.feature = self.Doc.addObject("PartDesign::Revolution", "RevolutionShaft")
            self.feature.Profile = self.sketch
            self.feature.ReferenceAxis = (self.sketch, ["H_Axis"])
            self.feature.Angle = 360.0
            self.Doc.recompute()
            self.Gui.hide("SketchShaft")
        else:
            self.Doc.recompute()
        # FIXME: Will give a warning in the console if the active window is not the feature
        self.Gui.SendMsgToActiveView("ViewFit")

    def updateSegment(self, segment, oldLength, length, diameter, innerdiameter):
        constrRadius = 4 + segment * 6
        constrLength = 7 + segment * 6
        constrInnerRadius = 1  # Currently we don't allow multiple different innner diameters
        # update total length
        self.totalLength = self.totalLength - oldLength + length
        # Adjust length of centerline
        self.sketch.setDatum(0, self.totalLength)
        # Adjust segment length
        self.sketch.setDatum(constrLength, length)
        # Adjust diameter
        self.sketch.setDatum(constrRadius, diameter / 2)
        # Adjust inner diameter
        self.sketch.setDatum(constrInnerRadius, innerdiameter / 2)
        # Update feature
        self.Doc.recompute()
        self.Gui.SendMsgToActiveView("ViewFit")
