# /**********************************************************************
# *                                                                     *
# * Copyright (c) 2021 Javier Braña <javier.branagutierrez@gmail.com>  *
# *                                                                     *
# * This program is free software; you can redistribute it and/or modify*
# * it under the terms of the GNU Lesser General Public License (LGPL)  *
# * as published by the Free Software Foundation; either version 2 of   *
# * the License, or (at your option) any later version.                 *
# * for detail see the LICENCE text file.                               *
# *                                                                     *
# * This program 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 program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307*
# * USA                                                                 *
# *                                                                     *
# ***********************************************************************

import ArchComponent
import FreeCAD
import Part

if FreeCAD.GuiUp:
    import FreeCADGui
    from PySide import QtCore, QtGui, QtSvg
    from PySide.QtCore import QT_TRANSLATE_NOOP
    import PySide.QtGui as QtGui
    import draftguitools.gui_trackers as DraftTrackers
else:
    # \cond
    def translate(ctxt, txt):
        return txt

    def QT_TRANSLATE_NOOP(ctxt, txt):
        return txt
    # \endcond

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

import os
import PVPlantResources
from PVPlantResources import DirIcons as DirIcons

def makePVPlantFence():
    obj = FreeCAD.ActiveDocument.addObject('Part::FeaturePython', 'FenceGate')
    FenceGate(obj)
    if FreeCAD.GuiUp:
        ViewProviderGate(obj.ViewObject)
    return obj


class FenceGate(ArchComponent.Component):
    def __init__(self, obj):
        ArchComponent.Component.__init__(self, obj)
        self.setProperties(obj)

    def setProperties(self, obj):
        pl = obj.PropertiesList

        if not ("GateType" in pl):
            obj.addProperty("App::PropertyEnumeration",
                            "GateType",
                            "Gate",
                            QT_TRANSLATE_NOOP("App::Property",
                                              "The facemaker type to use to build the profile of this object")
                            ).GateType = ["Single", "Double"]

        if not ("GateWidth" in pl):
            obj.addProperty("App::PropertyDistance",
                            "GateWidth",
                            "Gate",
                            "Base wire"
                            ).GateWidth = 3000

        if not ("GateHeight" in pl):
            obj.addProperty("App::PropertyDistance",
                            "GateHeight",
                            "Gate",
                            "Base wire"
                            ).GateHeight = 2000

        if not ("PostWidth" in pl):
            obj.addProperty("App::PropertyDistance",
                            "PostWidth",
                            "Gate",
                            "Base wire"
                            ).PostWidth = 60

        if not ("PostHeight" in pl):
            obj.addProperty("App::PropertyDistance",
                            "PostHeight",
                            "Gate",
                            "Base wire"
                            ).PostHeight = 2000

        if not "PostDepth" in pl:
            obj.addProperty("App::PropertyLength",
                            "PostDepth",
                            "Fence",
                            "A single fence post").PostDepth = 700

        self.Type = "PVPlatFenceGate"
        #obj.Type = self.Type
        obj.Proxy = self
        self.obj = obj

    def __getstate__(self):
        if hasattr(self, 'sectionFaceNumbers'):
            return (self.sectionFaceNumbers)
        return None

    def __setstate__(self, state):
        if state is not None and isinstance(state, tuple):
            self.sectionFaceNumbers = state[0]
        return None

    def onDocumentRestored(self, obj):
        """Method run when the document is restored."""
        self.setProperties(obj)

    def onChanged(self, obj, prop):
        '''Do something when a property has changed'''

    def execute(self, obj):
        tubewidth = 50
        gap = 20
        posts = Part.makeCompound([])
        gates = Part.makeCompound([])
        pl = obj.Placement

        post = Part.makeBox(obj.PostWidth.Value,
                            obj.PostWidth.Value,
                            obj.PostHeight.Value + obj.PostDepth.Value)

        gate = Part.makeBox(obj.GateWidth.Value,
                            tubewidth,
                            obj.GateHeight.Value)

        cut = Part.makeBox(obj.GateWidth.Value - tubewidth * 2,
                           tubewidth,
                           obj.GateHeight.Value - tubewidth * 2)
        cut.Placement.Base += FreeCAD.Vector(tubewidth, 0, tubewidth)
        gate = gate.cut(cut)

        if obj.GateType == "Single":
            post.Placement.Base = FreeCAD.Vector(-(obj.PostWidth.Value + gap + obj.GateWidth.Value / 2),
                                                 -obj.PostWidth.Value / 2,
                                                 -obj.PostDepth.Value)
            posts.add(post)
            post = post.copy()
            post.Placement.Base.x = -(post.Placement.Base.x + obj.PostWidth.Value)
            posts.add(post)
            gate.Placement.Base += FreeCAD.Vector(-obj.GateWidth.Value / 2,
                                                  obj.PostWidth.Value / 2 - tubewidth,
                                                  0)
            gates.add(gate)
        else:
            post.Placement.Base = FreeCAD.Vector(-(obj.PostWidth.Value + gap * 1.5 + obj.GateWidth.Value),
                                                 -obj.PostWidth.Value / 2,
                                                 -obj.PostDepth.Value)
            posts.add(post)
            post = post.copy()
            post.Placement.Base.x = -(post.Placement.Base.x + obj.PostWidth.Value)
            posts.add(post)

            gate.Placement.Base += FreeCAD.Vector(-(obj.GateWidth.Value + gap * 0.5),
                                                  obj.PostWidth.Value / 2 - tubewidth,
                                                  0)
            gates.add(gate)
            gate = gate.copy()
            gate.Placement.Base.x = gap * 0.5
            gates.add(gate)

        obj.Shape = Part.makeCompound([gates, posts])
        obj.Placement = pl


class ViewProviderGate:
    def __init__(self, vobj):
        ''' Set view properties. '''
        vobj.Proxy = self

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

    def getIcon(self):
        ''' Return object treeview icon. '''
        return str(os.path.join(DirIcons, "gate.svg"))

    def claimChildren(self):
        """ Provides object grouping """
        children = []
        if self.Object.Base:
            children.append(self.Object.Base)
        return children

class _CommandPVPlantGate:
    "the PVPlant Fence command definition"

    def __init__(self):
        ''' p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch")
        self.Thickness = p.GetFloat("WindowThickness", 50)
        self.Width = p.GetFloat("WindowWidth", 1000)
        self.Height = p.GetFloat("DoorHeight", 2100)'''

        self.Width = 0
        self.Height = 0
        self.Length = 0
        self.tracker = None

    def GetResources(self):
        return {'Pixmap': str(os.path.join(DirIcons, "gate.svg")),
                'Accel': "C, F",
                'MenuText': QT_TRANSLATE_NOOP("PVPlantFence", "Gate"),
                'ToolTip': QT_TRANSLATE_NOOP("PVPlantFence",
                                             "Creates a fence object from a selected section, post and path")}

    def IsActive(self):
        return not FreeCAD.ActiveDocument is None

    def Activated(self):
        self.tracker = DraftTrackers.boxTracker()
        self.tracker.length(self.Length)
        self.tracker.width(self.Width)
        self.tracker.height(self.Height)
        self.tracker.on()
        FreeCAD.Console.PrintMessage("Choose a face on an existing object or select a preset" + "\n")
        FreeCADGui.Snapper.getPoint(callback=self.getPoint,
                                    movecallback=self.update,
                                    extradlg=self.taskbox())

    def getPoint(self, point=None, obj=None):
        "this function is called by the snapper when it has a 3D point"

        if obj.Name[:5] == "Fence":
            self.tracker.finalize()
            if point is None:
                return
            ver = Part.Vertex(point)
            dist = ver.distToShape(obj.Base.Shape)
            point1 = dist[1][0][1]
            ed = None
            if dist[2][0][3] == "Edge":
                ed = obj.Base.Shape.Edges[int(dist[-1][0][4])]
            vec = ed.Vertexes[1].Point.sub(ed.Vertexes[0].Point)

            FreeCAD.ActiveDocument.openTransaction("Create Gate")
            gate = makePVPlantFence()
            try:
                import MeshPart as mp
                point1 = mp.projectPointsOnMesh([point1,], FreeCAD.ActiveDocument.Terrain.Mesh, FreeCAD.Vector(0, 0, 1))[0]

            except:
                FreeCAD.Console.PrintError("No se puede encontrar punto 3D.." + "\n")
                pass

            gate.Placement.Base = point1
            gate.Placement.Rotation = FreeCAD.Rotation(FreeCAD.Vector(-1, 0, 0), vec)
            tmp = obj.Gate
            tmp.append(gate)
            obj.Gate = tmp

            FreeCAD.ActiveDocument.commitTransaction()
            FreeCAD.ActiveDocument.recompute()
            return
        else:
            FreeCADGui.Snapper.getPoint(callback=self.getPoint,
                                        movecallback=self.update,
                                        extradlg=self.taskbox())
    def update(self, point, info):
        ''' this function is called by the Snapper when the mouse is moved '''

        delta = FreeCAD.Vector(self.Length / 2, self.Width / 2, self.Height / 2)
        rot = FreeCAD.Rotation()

        #self.tracker.setRotation(rot)
        self.tracker.pos(point)
        return

        delta = FreeCAD.Vector(self.Length / 2, self.Width / 2, self.Height / 2)
        delta = delta.add(FreeCAD.Vector(0, 0, self.Sill))
        rot = FreeCAD.Rotation()
        if info:
            if "Face" in info['Component']:
                import WorkingPlane
                o = FreeCAD.ActiveDocument.getObject(info['Object'])
                self.baseFace = [o, int(info['Component'][4:]) - 1]
                # print("switching to ",o.Label," face ",self.baseFace[1])
                f = o.Shape.Faces[self.baseFace[1]]
                p = WorkingPlane.getPlacementFromFace(f, rotated=True)
                if p:
                    rot = p.Rotation
                    self.tracker.setRotation(rot)
        r = self.tracker.trans.rotation.getValue().getValue()
        if r != (0, 0, 0, 1):
            delta = FreeCAD.Rotation(r[0], r[1], r[2], r[3]).multVec(FreeCAD.Vector(delta.x, -delta.y, -delta.z))
        self.tracker.pos(point.add(delta))

    def taskbox(self):
        "sets up a taskbox widget"

        w = FreeCADGui.PySideUic.loadUi(PVPlantResources.__dir__ + "/PVPlantFenceGate.ui")
        self.Width = 80
        self.Height = 2000
        self.Length = 6146
        return w

        w = QtGui.QWidget()
        ui = FreeCADGui.UiLoader()

        w.setWindowTitle("Window options")
        grid = QtGui.QGridLayout(w)

        # include box
        include = QtGui.QCheckBox(translate("Arch","Auto include in host object"))
        include.setChecked(True)
        grid.addWidget(include,0,0,1,2)
        QtCore.QObject.connect(include,QtCore.SIGNAL("stateChanged(int)"),self.setInclude)

        # sill height
        labels = QtGui.QLabel(translate("Arch","Sill height"))
        values = ui.createWidget("Gui::InputField")
        grid.addWidget(labels,1,0,1,1)
        grid.addWidget(values,1,1,1,1)
        QtCore.QObject.connect(values,QtCore.SIGNAL("valueChanged(double)"),self.setSill)

        # check for Parts library and Arch presets

        # because of the use of FreeCADGui.doCommand() backslashes in the
        # paths in librarypresets need to be double escaped "\\\\", so let's
        # use forward slashes instead...
        self.librarypresets = []
        librarypath = FreeCAD.ParamGet("User parameter:Plugins/parts_library").GetString("destination", "")
        # librarypath should have only forward slashes already, but let's use replace() anyway just to be sure:
        librarypath = librarypath.replace("\\", "/") + "/Architectural Parts"
        presetdir = FreeCAD.getUserAppDataDir().replace("\\", "/") + "/Arch"
        for path in [librarypath, presetdir]:
            if os.path.isdir(path):
                for wtype in ["Windows", "Doors"]:
                    wdir = path + "/" + wtype
                    if os.path.isdir(wdir):
                        for subtype in os.listdir(wdir):
                            subdir = wdir + "/" + subtype
                            if os.path.isdir(subdir):
                                for subfile in os.listdir(subdir):
                                    if (os.path.isfile(subdir + "/" + subfile)
                                            and subfile.lower().endswith(".fcstd")):
                                        self.librarypresets.append([wtype + " - " + subtype + " - " + subfile[:-6],
                                                                    subdir + "/" + subfile])

        # presets box
        labelp = QtGui.QLabel(translate("Arch","Preset"))
        valuep = QtGui.QComboBox()
        valuep.setMinimumContentsLength(6)
        valuep.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents)
        valuep.addItems(WindowPresets)
        valuep.setCurrentIndex(self.Preset)
        grid.addWidget(labelp,2,0,1,1)
        grid.addWidget(valuep,2,1,1,1)
        QtCore.QObject.connect(valuep,QtCore.SIGNAL("currentIndexChanged(int)"),self.setPreset)
        for it in self.librarypresets:
            valuep.addItem(it[0])

        # image display
        self.pic = QtGui.QLabel()
        grid.addWidget(self.pic,3,0,1,2)
        self.pic.setFixedHeight(128)
        self.pic.hide()

        # SVG display
        self.im = QtSvg.QSvgWidget(":/ui/ParametersWindowFixed.svg")
        self.im.setMaximumWidth(200)
        self.im.setMinimumHeight(120)
        grid.addWidget(self.im,4,0,1,2)
        #self.im.hide()

        # parameters
        i = 5
        for param in self.wparams:
            lab = QtGui.QLabel(translate("Arch",param))
            setattr(self,"val"+param,ui.createWidget("Gui::InputField"))
            wid = getattr(self,"val"+param)
            if param == "Width":
                wid.setText(FreeCAD.Units.Quantity(self.Width,FreeCAD.Units.Length).UserString)
            elif param == "Height":
                wid.setText(FreeCAD.Units.Quantity(self.Height,FreeCAD.Units.Length).UserString)
            elif param == "O1":
                n = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("WindowO1",0.0)
                wid.setText(FreeCAD.Units.Quantity(n,FreeCAD.Units.Length).UserString)
                setattr(self,param,n)
            elif param == "W1":
                n = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("WindowW1",self.Thickness*2)
                wid.setText(FreeCAD.Units.Quantity(n,FreeCAD.Units.Length).UserString)
                setattr(self,param,n)
            else:
                n = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("Window"+param,self.Thickness)
                wid.setText(FreeCAD.Units.Quantity(n,FreeCAD.Units.Length).UserString)
                setattr(self,param,n)
            grid.addWidget(lab,i,0,1,1)
            grid.addWidget(wid,i,1,1,1)
            i += 1
            valueChanged = self.getValueChanged(param)
            FreeCAD.wid = wid
            QtCore.QObject.connect(getattr(self,"val"+param),QtCore.SIGNAL("valueChanged(double)"), valueChanged)

        # restore saved states
        if self.doormode:
            i = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetInt("DoorPreset",0)
            d = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("DoorSill",0)
        else:
            i = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetInt("WindowPreset",0)
            d = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("WindowSill",0)
        if i < valuep.count():
            valuep.setCurrentIndex(i)
        values.setText(FreeCAD.Units.Quantity(d,FreeCAD.Units.Length).UserString)

        return w