# SPDX-License-Identifier: LGPL-2.1-or-later

# ***************************************************************************
# *                                                                         *
# *   Copyright (c) 2016 Yorik van Havre <yorik@uncreated.net>              *
# *                                                                         *
# *   This file is part of FreeCAD.                                         *
# *                                                                         *
# *   FreeCAD is free software: you can redistribute it and/or modify it    *
# *   under the terms of the GNU Lesser General Public License as           *
# *   published by the Free Software Foundation, either version 2.1 of the  *
# *   License, or (at your option) any later version.                       *
# *                                                                         *
# *   FreeCAD 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      *
# *   Lesser General Public License for more details.                       *
# *                                                                         *
# *   You should have received a copy of the GNU Lesser General Public      *
# *   License along with FreeCAD. If not, see                               *
# *   <https://www.gnu.org/licenses/>.                                      *
# *                                                                         *
# ***************************************************************************

__title__ = "FreeCAD Precast concrete module"
__author__ = "Yorik van Havre"
__url__ = "https://www.freecad.org"

## @package ArchPrecast
#  \ingroup ARCH
#  \brief Precast options for ArchStructure
#
#  This module provides additional presets for the Arch Structure
#  tool, to build a series of precast concrete elements

"""This module contains tools to build basic precast concrete elements:
Beams, pillars, slabs and panels"""

import FreeCAD
import ArchCommands
import ArchComponent

from FreeCAD import Vector
from draftutils import params

if FreeCAD.GuiUp:
    from PySide.QtCore import QT_TRANSLATE_NOOP
    from draftutils.translate import translate
else:
    # \cond
    def translate(ctxt, txt):
        return txt

    def QT_TRANSLATE_NOOP(ctxt, txt):
        return txt

    # \endcond


class _Precast(ArchComponent.Component):
    "The base Precast class"

    def __init__(self, obj):

        ArchComponent.Component.__init__(self, obj)
        self.Type = "Precast"
        _Precast.setProperties(self, obj)

    def setProperties(self, obj):

        pl = obj.PropertiesList
        if not "Length" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "Length",
                "Structure",
                QT_TRANSLATE_NOOP("App::Property", "The length of this element"),
                locked=True,
            )
        if not "Width" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "Width",
                "Structure",
                QT_TRANSLATE_NOOP("App::Property", "The width of this element"),
                locked=True,
            )
        if not "Height" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "Height",
                "Structure",
                QT_TRANSLATE_NOOP("App::Property", "The height of this element"),
                locked=True,
            )
        if not "Nodes" in pl:
            obj.addProperty(
                "App::PropertyVectorList",
                "Nodes",
                "Structure",
                QT_TRANSLATE_NOOP("App::Property", "The structural nodes of this element"),
                locked=True,
            )

    def onDocumentRestored(self, obj):

        ArchComponent.Component.onDocumentRestored(self, obj)
        _Precast.setProperties(self, obj)

    def loads(self, state):

        self.Type = "Precast"

    def execute(self, obj):

        if self.clone(obj):
            return


class _PrecastBeam(_Precast):
    "The Precast Beam"

    def __init__(self, obj):

        _Precast.__init__(self, obj)
        self.setProperties(obj)
        obj.IfcType = "Beam"

    def setProperties(self, obj):

        pl = obj.PropertiesList
        if not "Chamfer" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "Chamfer",
                "Beam",
                QT_TRANSLATE_NOOP("App::Property", "The size of the chamfer of this element"),
                locked=True,
            )
        if not "DentLength" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "DentLength",
                "Beam",
                QT_TRANSLATE_NOOP("App::Property", "The dent length of this element"),
                locked=True,
            )
        if not "DentHeight" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "DentHeight",
                "Beam",
                QT_TRANSLATE_NOOP("App::Property", "The dent height of this element"),
                locked=True,
            )
        if not "Dents" in pl:
            obj.addProperty(
                "App::PropertyStringList",
                "Dents",
                "Beam",
                QT_TRANSLATE_NOOP("App::Property", "The dents of this element"),
                locked=True,
            )

    def onDocumentRestored(self, obj):

        _Precast.onDocumentRestored(self, obj)
        self.setProperties(obj)

    def execute(self, obj):

        if self.clone(obj):
            return

        pl = obj.Placement
        length = obj.Length.Value
        width = obj.Width.Value
        height = obj.Height.Value
        chamfer = obj.Chamfer.Value
        dentlength = obj.DentLength.Value
        dentheight = obj.DentHeight.Value
        dents = obj.Dents

        if (
            length == 0
            or width == 0
            or height == 0
            or chamfer >= width / 2
            or chamfer >= height / 2
        ):
            FreeCAD.Console.PrintWarning(
                obj.Label + " " + translate("Arch", "has a null shape") + "\n"
            )
            return

        import Part

        p = []
        if chamfer > 0:
            p.append(Vector(0, chamfer, 0))
            p.append(Vector(0, width - chamfer, 0))
            p.append(Vector(0, width, chamfer))
            p.append(Vector(0, width, height - chamfer))
            p.append(Vector(0, width - chamfer, height))
            p.append(Vector(0, chamfer, height))
            p.append(Vector(0, 0, height - chamfer))
            p.append(Vector(0, 0, chamfer))
        else:
            p.append(Vector(0, 0, 0))
            p.append(Vector(0, width, 0))
            p.append(Vector(0, width, height))
            p.append(Vector(0, 0, height))
        p.append(p[0])
        p = Part.makePolygon(p)
        f = Part.Face(p)
        shape = f.extrude(Vector(length, 0, 0))
        if (dentlength > 0) and (dentheight > 0):
            p = []
            p.append(Vector(0, 0, 0))
            p.append(Vector(dentlength, 0, 0))
            p.append(Vector(dentlength, width, 0))
            p.append(Vector(0, width, 0))
            p.append(p[0])
            p = Part.makePolygon(p)
            f = Part.Face(p)
            d1 = f.extrude(Vector(0, 0, dentheight))
            d2 = d1.copy()
            d2.translate(Vector(length - dentlength, 0, 0))
            shape = shape.cut(d1)
            shape = shape.cut(d2)
        for dent in dents:
            dent = dent.split(";")
            if len(dent) == 7:
                dentlength = float(dent[0])
                dentwidth = float(dent[1])
                dentheight = float(dent[2])
                dentslant = float(dent[3])
                dentchamfer = chamfer
                dentlevel = float(dent[4])
                dentrotation = float(dent[5])
                dentoffset = float(dent[6])
                if (dentlength == 0) or (dentwidth == 0) or (dentheight == 0):
                    continue
                if dentslant >= dentheight:
                    continue
                p = []
                p.append(Vector(0 - dentchamfer, 0, 0))
                p.append(Vector(dentlength, 0, dentslant))
                p.append(Vector(dentlength, 0, dentheight))
                p.append(Vector(0 - dentchamfer, 0, dentheight))
                p.append(p[0])
                p = Part.makePolygon(p)
                f = Part.Face(p)
                dentshape = f.extrude(Vector(0, dentwidth, 0))
                dentshape.rotate(Vector(0, 0, 0), Vector(0, 0, 1), dentrotation)
                if dentrotation == 0:
                    dentshape.translate(Vector(length, dentoffset, 0))
                elif dentrotation == 90:
                    dentshape.translate(Vector(length - dentoffset, width, 0))
                elif dentrotation == 180:
                    dentshape.translate(Vector(0, width - dentoffset, 0))
                elif dentrotation == 270:
                    dentshape.translate(Vector(dentoffset, 0, 0))
                dentshape.translate(Vector(0, 0, dentlevel))
                shape = shape.fuse(dentshape)
        shape = self.processSubShapes(obj, shape, pl)
        self.applyShape(obj, shape, pl)


class _PrecastIbeam(_Precast):
    "The Precast Ibeam"

    def __init__(self, obj):

        _Precast.__init__(self, obj)
        self.setProperties(obj)
        obj.IfcType = "Beam"

    def setProperties(self, obj):

        pl = obj.PropertiesList
        if not "Chamfer" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "Chamfer",
                "Beam",
                QT_TRANSLATE_NOOP("App::Property", "The chamfer length of this element"),
                locked=True,
            )
        if not "BeamBase" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "BeamBase",
                "Beam",
                QT_TRANSLATE_NOOP("App::Property", "The base length of this element"),
                locked=True,
            )

    def onDocumentRestored(self, obj):

        _Precast.onDocumentRestored(self, obj)
        self.setProperties(obj)

    def execute(self, obj):

        if self.clone(obj):
            return

        pl = obj.Placement
        length = obj.Length.Value
        width = obj.Width.Value
        height = obj.Height.Value
        base = obj.BeamBase.Value
        slant = obj.Chamfer.Value

        if (
            length == 0
            or width == 0
            or height == 0
            or slant * 2 >= width
            or base * 2 + slant * 2 >= height
        ):
            FreeCAD.Console.PrintWarning(
                obj.Label + " " + translate("Arch", "has a null shape") + "\n"
            )
            return

        import Part

        p = []
        p.append(Vector(0, 0, 0))
        p.append(Vector(0, 0, base))
        p.append(Vector(0, slant, base + slant))
        p.append(Vector(0, slant, height - (base + slant)))
        p.append(Vector(0, 0, height - base))
        p.append(Vector(0, 0, height))
        p.append(Vector(0, width, height))
        p.append(Vector(0, width, height - base))
        p.append(Vector(0, width - slant, height - (base + slant)))
        p.append(Vector(0, width - slant, base + slant))
        p.append(Vector(0, width, base))
        p.append(Vector(0, width, 0))
        p.append(p[0])
        p = Part.makePolygon(p)
        f = Part.Face(p)
        shape = f.extrude(Vector(length, 0, 0))

        shape = self.processSubShapes(obj, shape, pl)
        self.applyShape(obj, shape, pl)


class _PrecastPillar(_Precast):
    "The Precast Pillar"

    def __init__(self, obj):

        _Precast.__init__(self, obj)
        self.setProperties(obj)
        obj.IfcType = "Column"

    def setProperties(self, obj):

        pl = obj.PropertiesList
        if not "Chamfer" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "Chamfer",
                "Column",
                QT_TRANSLATE_NOOP("App::Property", "The size of the chamfer of this element"),
                locked=True,
            )
        if not "GrooveDepth" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "GrooveDepth",
                "Column",
                QT_TRANSLATE_NOOP("App::Property", "The groove depth of this element"),
                locked=True,
            )
        if not "GrooveHeight" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "GrooveHeight",
                "Column",
                QT_TRANSLATE_NOOP("App::Property", "The groove height of this element"),
                locked=True,
            )
        if not "GrooveSpacing" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "GrooveSpacing",
                "Column",
                QT_TRANSLATE_NOOP(
                    "App::Property", "The spacing between the grooves of this element"
                ),
                locked=True,
            )
        if not "GrooveNumber" in pl:
            obj.addProperty(
                "App::PropertyInteger",
                "GrooveNumber",
                "Column",
                QT_TRANSLATE_NOOP("App::Property", "The number of grooves of this element"),
                locked=True,
            )
        if not "Dents" in pl:
            obj.addProperty(
                "App::PropertyStringList",
                "Dents",
                "Column",
                QT_TRANSLATE_NOOP("App::Property", "The dents of this element"),
                locked=True,
            )

    def onDocumentRestored(self, obj):

        _Precast.onDocumentRestored(self, obj)
        self.setProperties(obj)

    def execute(self, obj):

        if self.clone(obj):
            return

        pl = obj.Placement
        length = obj.Length.Value
        width = obj.Width.Value
        height = obj.Height.Value
        chamfer = obj.Chamfer.Value
        groovedepth = obj.GrooveDepth.Value
        grooveheight = obj.GrooveHeight.Value
        spacing = obj.GrooveSpacing.Value
        number = obj.GrooveNumber
        dents = obj.Dents

        if (
            length == 0
            or width == 0
            or height == 0
            or chamfer >= width / 2
            or chamfer >= length / 2
        ):
            FreeCAD.Console.PrintWarning(
                obj.Label + " " + translate("Arch", "has a null shape") + "\n"
            )
            return

        import Part

        p = []
        if chamfer > 0:
            p.append(Vector(chamfer, 0, 0))
            p.append(Vector(length - chamfer, 0, 0))
            p.append(Vector(length, chamfer, 0))
            p.append(Vector(length, width - chamfer, 0))
            p.append(Vector(length - chamfer, width, 0))
            p.append(Vector(chamfer, width, 0))
            p.append(Vector(0, width - chamfer, 0))
            p.append(Vector(0, chamfer, 0))
        else:
            p.append(Vector(0, 0, 0))
            p.append(Vector(length, 0, 0))
            p.append(Vector(length, width, 0))
            p.append(Vector(0, width, 0))
        p.append(p[0])
        p = Part.makePolygon(p)
        f = Part.Face(p)
        shape = f.extrude(Vector(0, 0, height))

        if (
            (groovedepth > 0)
            and (grooveheight > 0)
            and (spacing > 0)
            and (number > 0)
            and (groovedepth < length / 2)
            and (groovedepth < width / 2)
        ):
            p1 = []
            p1.append(Vector(0, 0, 0))
            p1.append(Vector(length, 0, 0))
            p1.append(Vector(length, width, 0))
            p1.append(Vector(0, width, 0))
            p1.append(p1[0])
            p1 = Part.makePolygon(p1)
            f1 = Part.Face(p1)
            groove = f1.extrude(Vector(0, 0, grooveheight))
            p2 = []
            p2.append(Vector(groovedepth, groovedepth, 0))
            p2.append(Vector(length - groovedepth, groovedepth, 0))
            p2.append(Vector(length - groovedepth, width - groovedepth, 0))
            p2.append(Vector(groovedepth, width - groovedepth, 0))
            p2.append(p2[0])
            p2 = Part.makePolygon(p2)
            f2 = Part.Face(p2)
            s = f2.extrude(Vector(0, 0, grooveheight))
            groove = groove.cut(s)
            for i in range(number):
                g = groove.copy()
                g.translate(Vector(0, 0, spacing + i * (spacing + grooveheight)))
                shape = shape.cut(g)

        for dent in dents:
            dent = dent.split(";")
            if len(dent) == 7:
                dentlength = float(dent[0])
                dentwidth = float(dent[1])
                dentheight = float(dent[2])
                dentslant = float(dent[3])
                dentchamfer = chamfer
                dentlevel = float(dent[4])
                dentrotation = float(dent[5])
                dentoffset = float(dent[6])
                if (dentlength == 0) or (dentwidth == 0) or (dentheight == 0):
                    continue
                if dentslant >= dentheight:
                    continue
                p = []
                p.append(Vector(0 - dentchamfer, 0, 0))
                p.append(Vector(dentlength, 0, dentslant))
                p.append(Vector(dentlength, 0, dentheight))
                p.append(Vector(0 - dentchamfer, 0, dentheight))
                p.append(p[0])
                p = Part.makePolygon(p)
                f = Part.Face(p)
                dentshape = f.extrude(Vector(0, dentwidth, 0))
                dentshape.rotate(Vector(0, 0, 0), Vector(0, 0, 1), dentrotation)
                if dentrotation == 0:
                    dentshape.translate(Vector(length, dentoffset, 0))
                elif dentrotation == 90:
                    dentshape.translate(Vector(length - dentoffset, width, 0))
                elif dentrotation == 180:
                    dentshape.translate(Vector(0, width - dentoffset, 0))
                elif dentrotation == 270:
                    dentshape.translate(Vector(dentoffset, 0, 0))
                dentshape.translate(Vector(0, 0, dentlevel))
                shape = shape.fuse(dentshape)

        shape = self.processSubShapes(obj, shape, pl)
        self.applyShape(obj, shape, pl)


class _PrecastPanel(_Precast):
    "The Precast Panel"

    def __init__(self, obj):

        _Precast.__init__(self, obj)
        self.setProperties(obj)
        obj.IfcType = "Plate"

    def setProperties(self, obj):

        pl = obj.PropertiesList
        if not "Chamfer" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "Chamfer",
                "Panel",
                QT_TRANSLATE_NOOP("App::Property", "The size of the chamfer of this element"),
                locked=True,
            )
        if not "DentWidth" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "DentWidth",
                "Panel",
                QT_TRANSLATE_NOOP("App::Property", "The dent width of this element"),
                locked=True,
            )
        if not "DentHeight" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "DentHeight",
                "Panel",
                QT_TRANSLATE_NOOP("App::Property", "The dent height of this element"),
                locked=True,
            )

    def onDocumentRestored(self, obj):

        _Precast.onDocumentRestored(self, obj)
        self.setProperties(obj)

    def execute(self, obj):

        if self.clone(obj):
            return

        pl = obj.Placement
        length = obj.Length.Value
        width = obj.Width.Value
        height = obj.Height.Value
        chamfer = obj.Chamfer.Value
        dentheight = obj.DentHeight.Value
        dentwidth = obj.DentWidth.Value

        if (
            length == 0
            or width == 0
            or height == 0
            or chamfer + dentwidth >= width
            or dentheight >= height
        ):
            FreeCAD.Console.PrintWarning(
                obj.Label + " " + translate("Arch", "has a null shape") + "\n"
            )
            return

        import Part

        p = []
        p.append(Vector(0, 0, 0))
        p.append(Vector(length, 0, 0))
        p.append(Vector(length, width, 0))
        p.append(Vector(0, width, 0))
        p.append(p[0])
        p = Part.makePolygon(p)
        f = Part.Face(p)
        shape = f.extrude(Vector(0, 0, height))
        if chamfer > 0:
            p = []
            p.append(Vector(0, width - chamfer, 0))
            p.append(Vector(chamfer, width, 0))
            p.append(Vector(0, width, 0))
            p.append(p[0])
            p = Part.makePolygon(p)
            f = Part.Face(p)
            s = f.extrude(Vector(0, 0, height))
            shape = shape.cut(s)
            p = []
            p.append(Vector(length, width - chamfer, 0))
            p.append(Vector(length - chamfer, width, 0))
            p.append(Vector(length, width, 0))
            p.append(p[0])
            p = Part.makePolygon(p)
            f = Part.Face(p)
            s = f.extrude(Vector(0, 0, height))
            shape = shape.cut(s)
            p = []
            p.append(Vector(0, width - chamfer, 0))
            p.append(Vector(0, width, chamfer))
            p.append(Vector(0, width, 0))
            p.append(p[0])
            p = Part.makePolygon(p)
            f = Part.Face(p)
            s = f.extrude(Vector(length, 0, 0))
            shape = shape.cut(s)
            p = []
            p.append(Vector(0, width - chamfer, height))
            p.append(Vector(0, width, height - chamfer))
            p.append(Vector(0, width, height))
            p.append(p[0])
            p = Part.makePolygon(p)
            f = Part.Face(p)
            s = f.extrude(Vector(length, 0, 0))
            shape = shape.cut(s)
        if (dentheight > 0) and (dentwidth > 0):
            p = []
            p.append(Vector(0, ((width - chamfer) - dentwidth) / 2, 0))
            p.append(Vector(0, ((width - chamfer) - dentwidth) / 2 + dentwidth, 0))
            p.append(Vector(0, ((width - chamfer) - dentwidth) / 2 + dentwidth, dentheight))
            p.append(Vector(0, ((width - chamfer) - dentwidth) / 2, dentheight))
            p.append(p[0])
            p = Part.makePolygon(p)
            f = Part.Face(p)
            s = f.extrude(Vector(length, 0, 0))
            shape = shape.cut(s)
            s.translate(Vector(0, 0, height))
            shape = shape.fuse(s)

        shape = self.processSubShapes(obj, shape, pl)
        self.applyShape(obj, shape, pl)


class _PrecastSlab(_Precast):
    "The Precast Slab"

    def __init__(self, obj):

        _Precast.__init__(self, obj)
        self.setProperties(obj)
        obj.IfcType = "Slab"

    def setProperties(self, obj):

        pl = obj.PropertiesList
        if not "SlabType" in pl:
            obj.addProperty(
                "App::PropertyEnumeration",
                "SlabType",
                "Slab",
                QT_TRANSLATE_NOOP("App::Property", "The type of this slab"),
                locked=True,
            )
            obj.SlabType = ["Champagne", "Hat"]
        if not "SlabBase" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "SlabBase",
                "Slab",
                QT_TRANSLATE_NOOP("App::Property", "The size of the base of this element"),
                locked=True,
            )
        if not "HoleNumber" in pl:
            obj.addProperty(
                "App::PropertyInteger",
                "HoleNumber",
                "Slab",
                QT_TRANSLATE_NOOP("App::Property", "The number of holes in this element"),
                locked=True,
            )
        if not "HoleMajor" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "HoleMajor",
                "Slab",
                QT_TRANSLATE_NOOP("App::Property", "The major radius of the holes of this element"),
                locked=True,
            )
        if not "HoleMinor" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "HoleMinor",
                "Slab",
                QT_TRANSLATE_NOOP("App::Property", "The minor radius of the holes of this element"),
                locked=True,
            )
        if not "HoleSpacing" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "HoleSpacing",
                "Slab",
                QT_TRANSLATE_NOOP("App::Property", "The spacing between the holes of this element"),
                locked=True,
            )

    def onDocumentRestored(self, obj):

        _Precast.onDocumentRestored(self, obj)
        self.setProperties(obj)

    def execute(self, obj):

        if self.clone(obj):
            return

        pl = obj.Placement
        slabtype = obj.SlabType
        length = obj.Length.Value
        width = obj.Width.Value
        height = obj.Height.Value
        base = obj.SlabBase.Value
        holenumber = obj.HoleNumber
        holemajor = obj.HoleMajor.Value
        holeminor = obj.HoleMinor.Value
        holespacing = obj.HoleSpacing.Value

        slant = (height - base) / 3  # this gives the inclination of the vertical walls
        if base == 0:
            base = min(height / 4, 50)
            obj.SlabBase = base

        if (
            length == 0
            or width == 0
            or height == 0
            or width <= slant * 2
            or height < base * 2
            or (holenumber > 0 and (holespacing == 0 or holemajor == 0 or holeminor == 0))
            or holemajor < holeminor
        ):
            FreeCAD.Console.PrintWarning(
                obj.Label + " " + translate("Arch", "has a null shape") + "\n"
            )
            return

        import Part

        p = []
        if slabtype == "Champagne":
            p.append(Vector(0, 0, 0))
            p.append(Vector(0, slant, height - base))
            p.append(Vector(0, 0, height - base))
            p.append(Vector(0, 0, height))
            p.append(Vector(0, width, height))
            p.append(Vector(0, width, height - base))
            p.append(Vector(0, width - slant, height - base))
            p.append(Vector(0, width, 0))
        elif slabtype == "Hat":
            p.append(Vector(0, 0, 0))
            p.append(Vector(0, 0, base))
            p.append(Vector(0, slant, base))
            p.append(Vector(0, slant * 2, height))
            p.append(Vector(0, width - slant * 2, height))
            p.append(Vector(0, width - slant, base))
            p.append(Vector(0, width, base))
            p.append(Vector(0, width, 0))
        else:
            return None
        p.append(p[0])
        p = Part.makePolygon(p)
        f = Part.Face(p)
        shape = f.extrude(Vector(length, 0, 0))

        if holenumber > 0:
            holespan = holenumber * holeminor + (holenumber - 1) * holespacing
            holestart = (width / 2 - holespan / 2) + holeminor / 2
            if holeminor != holemajor:
                e = Part.Ellipse(
                    Vector(0, 0, 0), Vector(0, holeminor / 2, 0), Vector(0, 0, holemajor / 2)
                ).toShape()
                e.translate(Vector(0, 0, -holemajor / 2))
            else:
                e = Part.Circle(Vector(0, 0, 0), Vector(1, 0, 0), holemajor / 2).toShape()
            w = Part.Wire([e])
            f = Part.Face(w)
            tube = f.extrude(Vector(length, 0, 0))
            for i in range(holenumber):
                x = holestart + i * (holeminor + holespacing)
                s = tube.copy()
                s.translate(Vector(0, x, height / 2))
                shape = shape.cut(s)

        shape = self.processSubShapes(obj, shape, pl)
        self.applyShape(obj, shape, pl)


class _PrecastStairs(_Precast):
    "The Precast Stairs"

    def __init__(self, obj):

        _Precast.__init__(self, obj)
        self.setProperties(obj)
        obj.IfcType = "Stair"

    def setProperties(self, obj):

        pl = obj.PropertiesList
        if not "DownLength" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "DownLength",
                "Stairs",
                QT_TRANSLATE_NOOP("App::Property", "The length of the down floor of this element"),
                locked=True,
            )
        if not "RiserNumber" in pl:
            obj.addProperty(
                "App::PropertyInteger",
                "RiserNumber",
                "Stairs",
                QT_TRANSLATE_NOOP("App::Property", "The number of risers in this element"),
                locked=True,
            )
        if not "Riser" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "Riser",
                "Stairs",
                QT_TRANSLATE_NOOP("App::Property", "The riser height of this element"),
                locked=True,
            )
        if not "Tread" in pl:
            obj.addProperty(
                "App::PropertyDistance",
                "Tread",
                "Stairs",
                QT_TRANSLATE_NOOP("App::Property", "The tread depth of this element"),
                locked=True,
            )

    def onDocumentRestored(self, obj):

        _Precast.onDocumentRestored(self, obj)
        self.setProperties(obj)

    def execute(self, obj):

        if self.clone(obj):
            return

        pl = obj.Placement
        length = obj.Length.Value
        width = obj.Width.Value
        height = obj.Height.Value
        downlength = obj.DownLength.Value
        steps = obj.RiserNumber
        riser = obj.Riser.Value
        tread = obj.Tread.Value

        if width == 0 or steps == 0 or riser == 0 or tread == 0 or height == 0:
            FreeCAD.Console.PrintWarning(
                obj.Label + " " + translate("Arch", "has a null shape") + "\n"
            )
            return

        if length < tread:
            length = tread  # minimum

        import math
        import Part

        p = [Vector(0, 0, 0)]  # relative moves
        if downlength:
            p.append(Vector(0, downlength, 0))
        for i in range(steps - 1):
            p.append(Vector(0, 0, riser))
            p.append(Vector(0, tread, 0))
        p.append(Vector(0, 0, riser))
        p.append(Vector(0, length, 0))
        ang1 = math.atan(riser / tread)
        ang2 = ang1 / 2
        rdist = math.tan(ang2) * height
        if length > (tread + rdist):
            p.append(Vector(0, 0, -height))
            p.append(Vector(0, -(length - (tread + rdist))))
        else:
            rest = length - (tread + rdist)
            addh = math.tan(ang1) * rest
            p.append(Vector(0, 0, -(height + addh)))
        # absolutize
        r = [p[0]]
        for m in p[1:]:
            r.append(r[-1].add(m))
        p = r
        if downlength:
            bdist = math.tan(ang1) * height
            p.append(Vector(0, downlength + bdist, -height))
            p.append(Vector(0, 0, -height))
        else:
            hdist = height * (math.tan(ang1))
            p.append(Vector(0, hdist, 0))
        p.append(p[0])
        p = Part.makePolygon(p)
        f = Part.Face(p)
        shape = f.extrude(Vector(width, 0, 0))

        shape = self.processSubShapes(obj, shape, pl)
        self.applyShape(obj, shape, pl)


class _ViewProviderPrecast(ArchComponent.ViewProviderComponent):
    "The View Provider of the Precast object"

    def __init__(self, vobj):

        ArchComponent.ViewProviderComponent.__init__(self, vobj)
        vobj.ShapeColor = ArchCommands.getDefaultColor("Structure")

    def getIcon(self):

        import Arch_rc

        if hasattr(self, "Object"):
            if self.Object.CloneOf:
                return ":/icons/Arch_Structure_Clone.svg"
        return ":/icons/Arch_Structure_Tree.svg"

    def setEdit(self, vobj, mode):
        if mode != 0:
            return None

        import FreeCADGui

        taskd = ArchComponent.ComponentTaskPanel()
        taskd.obj = self.Object
        taskd.update()
        if hasattr(self.Object, "Dents"):
            self.dentd = _DentsTaskPanel()
            self.dentd.form.show()
            self.dentd.fillDents(self.Object.Dents)
            taskd.form = [taskd.form, self.dentd.form]
        FreeCADGui.Control.showDialog(taskd)
        return True

    def unsetEdit(self, vobj, mode):
        if mode != 0:
            return None

        import FreeCADGui

        if hasattr(self, "dentd"):
            self.Object.Dents = self.dentd.getValues()
            del self.dentd
        FreeCADGui.Control.closeDialog()
        return True


class _PrecastTaskPanel:
    """The TaskPanel for precast creation"""

    def __init__(self):

        import FreeCADGui
        from PySide import QtCore, QtGui, QtSvgWidgets

        self.form = QtGui.QWidget()
        self.grid = QtGui.QGridLayout(self.form)
        self.PrecastTypes = ["Beam", "I-Beam", "Pillar", "Panel", "Slab", "Stairs"]
        self.SlabTypes = ["Champagne", "Hat"]

        # image display
        self.preview = QtSvgWidgets.QSvgWidget(":/ui/ParametersBeam.svg")
        self.preview.setMaximumWidth(200)
        self.preview.setMinimumHeight(120)
        self.grid.addWidget(self.preview, 0, 0, 1, 2)

        # parameters
        self.labelSlabType = QtGui.QLabel()
        self.valueSlabType = QtGui.QComboBox()
        self.valueSlabType.addItems(self.SlabTypes)
        self.valueSlabType.setCurrentIndex(0)
        self.grid.addWidget(self.labelSlabType, 1, 0, 1, 1)
        self.grid.addWidget(self.valueSlabType, 1, 1, 1, 1)

        self.labelChamfer = QtGui.QLabel()
        self.valueChamfer = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelChamfer, 2, 0, 1, 1)
        self.grid.addWidget(self.valueChamfer, 2, 1, 1, 1)

        self.labelDentLength = QtGui.QLabel()
        self.valueDentLength = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelDentLength, 3, 0, 1, 1)
        self.grid.addWidget(self.valueDentLength, 3, 1, 1, 1)

        self.labelDentWidth = QtGui.QLabel()
        self.valueDentWidth = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelDentWidth, 4, 0, 1, 1)
        self.grid.addWidget(self.valueDentWidth, 4, 1, 1, 1)

        self.labelDentHeight = QtGui.QLabel()
        self.valueDentHeight = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelDentHeight, 5, 0, 1, 1)
        self.grid.addWidget(self.valueDentHeight, 5, 1, 1, 1)

        self.labelBase = QtGui.QLabel()
        self.valueBase = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelBase, 6, 0, 1, 1)
        self.grid.addWidget(self.valueBase, 6, 1, 1, 1)

        self.labelHoleNumber = QtGui.QLabel()
        self.valueHoleNumber = QtGui.QSpinBox()
        self.grid.addWidget(self.labelHoleNumber, 7, 0, 1, 1)
        self.grid.addWidget(self.valueHoleNumber, 7, 1, 1, 1)

        self.labelHoleMajor = QtGui.QLabel()
        self.valueHoleMajor = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelHoleMajor, 8, 0, 1, 1)
        self.grid.addWidget(self.valueHoleMajor, 8, 1, 1, 1)

        self.labelHoleMinor = QtGui.QLabel()
        self.valueHoleMinor = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelHoleMinor, 9, 0, 1, 1)
        self.grid.addWidget(self.valueHoleMinor, 9, 1, 1, 1)

        self.labelHoleSpacing = QtGui.QLabel()
        self.valueHoleSpacing = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelHoleSpacing, 10, 0, 1, 1)
        self.grid.addWidget(self.valueHoleSpacing, 10, 1, 1, 1)

        self.labelGrooveNumber = QtGui.QLabel()
        self.valueGrooveNumber = QtGui.QSpinBox()
        self.grid.addWidget(self.labelGrooveNumber, 11, 0, 1, 1)
        self.grid.addWidget(self.valueGrooveNumber, 11, 1, 1, 1)

        self.labelGrooveDepth = QtGui.QLabel()
        self.valueGrooveDepth = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelGrooveDepth, 12, 0, 1, 1)
        self.grid.addWidget(self.valueGrooveDepth, 12, 1, 1, 1)

        self.labelGrooveHeight = QtGui.QLabel()
        self.valueGrooveHeight = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelGrooveHeight, 13, 0, 1, 1)
        self.grid.addWidget(self.valueGrooveHeight, 13, 1, 1, 1)

        self.labelGrooveSpacing = QtGui.QLabel()
        self.valueGrooveSpacing = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelGrooveSpacing, 14, 0, 1, 1)
        self.grid.addWidget(self.valueGrooveSpacing, 14, 1, 1, 1)

        self.labelRiserNumber = QtGui.QLabel()
        self.valueRiserNumber = QtGui.QSpinBox()
        self.grid.addWidget(self.labelRiserNumber, 15, 0, 1, 1)
        self.grid.addWidget(self.valueRiserNumber, 15, 1, 1, 1)

        self.labelDownLength = QtGui.QLabel()
        self.valueDownLength = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelDownLength, 16, 0, 1, 1)
        self.grid.addWidget(self.valueDownLength, 16, 1, 1, 1)

        self.labelRiser = QtGui.QLabel()
        self.valueRiser = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelRiser, 17, 0, 1, 1)
        self.grid.addWidget(self.valueRiser, 17, 1, 1, 1)

        self.labelTread = QtGui.QLabel()
        self.valueTread = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelTread, 18, 0, 1, 1)
        self.grid.addWidget(self.valueTread, 18, 1, 1, 1)

        # signals/slots
        QtCore.QObject.connect(
            self.valueChamfer, QtCore.SIGNAL("valueChanged(double)"), self.setChamfer
        )
        QtCore.QObject.connect(
            self.valueDentLength, QtCore.SIGNAL("valueChanged(double)"), self.setDentLength
        )
        QtCore.QObject.connect(
            self.valueDentWidth, QtCore.SIGNAL("valueChanged(double)"), self.setDentWidth
        )
        QtCore.QObject.connect(
            self.valueDentHeight, QtCore.SIGNAL("valueChanged(double)"), self.setDentHeight
        )
        QtCore.QObject.connect(self.valueBase, QtCore.SIGNAL("valueChanged(double)"), self.setBase)
        QtCore.QObject.connect(
            self.valueHoleMajor, QtCore.SIGNAL("valueChanged(double)"), self.setHoleMajor
        )
        QtCore.QObject.connect(
            self.valueHoleMinor, QtCore.SIGNAL("valueChanged(double)"), self.setHoleMinor
        )
        QtCore.QObject.connect(
            self.valueHoleSpacing, QtCore.SIGNAL("valueChanged(double)"), self.setHoleSpacing
        )
        QtCore.QObject.connect(
            self.valueGrooveDepth, QtCore.SIGNAL("valueChanged(double)"), self.setGrooveDepth
        )
        QtCore.QObject.connect(
            self.valueGrooveHeight, QtCore.SIGNAL("valueChanged(double)"), self.setGrooveHeight
        )
        QtCore.QObject.connect(
            self.valueGrooveSpacing, QtCore.SIGNAL("valueChanged(double)"), self.setGrooveSpacing
        )
        QtCore.QObject.connect(
            self.valueDownLength, QtCore.SIGNAL("valueChanged(double)"), self.setDownLength
        )
        QtCore.QObject.connect(
            self.valueRiser, QtCore.SIGNAL("valueChanged(double)"), self.setRiser
        )
        QtCore.QObject.connect(
            self.valueTread, QtCore.SIGNAL("valueChanged(double)"), self.setTread
        )

        # restore presets
        self.restoreValue(self.valueChamfer, params.get_param_arch("PrecastChamfer"))
        self.restoreValue(self.valueDentLength, params.get_param_arch("PrecastDentLength"))
        self.restoreValue(self.valueDentWidth, params.get_param_arch("PrecastDentWidth"))
        self.restoreValue(self.valueDentHeight, params.get_param_arch("PrecastDentHeight"))
        self.restoreValue(self.valueBase, params.get_param_arch("PrecastBase"))
        self.restoreValue(self.valueHoleMajor, params.get_param_arch("PrecastHoleMajor"))
        self.restoreValue(self.valueHoleMinor, params.get_param_arch("PrecastHoleMinor"))
        self.restoreValue(self.valueHoleSpacing, params.get_param_arch("PrecastHoleSpacing"))
        self.restoreValue(self.valueGrooveDepth, params.get_param_arch("PrecastGrooveDepth"))
        self.restoreValue(self.valueGrooveHeight, params.get_param_arch("PrecastGrooveHeight"))
        self.restoreValue(self.valueGrooveSpacing, params.get_param_arch("PrecastGrooveSpacing"))
        self.restoreValue(self.valueDownLength, params.get_param_arch("PrecastDownLength"))
        self.restoreValue(self.valueRiser, params.get_param_arch("PrecastRiser"))
        self.restoreValue(self.valueTread, params.get_param_arch("PrecastTread"))

        self.retranslateUi(self.form)
        self.form.hide()

    def restoreValue(self, widget, val):
        widget.setText(FreeCAD.Units.Quantity(val, FreeCAD.Units.Length).UserString)

    def getValues(self):
        d = {}
        d["SlabType"] = self.SlabTypes[self.valueSlabType.currentIndex()]
        d["Chamfer"] = self.Chamfer
        d["DentLength"] = self.DentLength
        d["DentWidth"] = self.DentWidth
        d["DentHeight"] = self.DentHeight
        d["Base"] = self.Base
        d["HoleNumber"] = self.valueHoleNumber.value()
        d["HoleMajor"] = self.HoleMajor
        d["HoleMinor"] = self.HoleMinor
        d["HoleSpacing"] = self.HoleSpacing
        d["GrooveNumber"] = self.valueGrooveNumber.value()
        d["GrooveDepth"] = self.GrooveDepth
        d["GrooveHeight"] = self.GrooveHeight
        d["GrooveSpacing"] = self.GrooveSpacing
        d["RiserNumber"] = self.valueRiserNumber.value()
        d["DownLength"] = self.DownLength
        d["Riser"] = self.Riser
        d["Tread"] = self.Tread
        if hasattr(self, "Dents"):
            d["Dents"] = self.Dents.getValues()
        return d

    def setChamfer(self, value):
        self.Chamfer = value
        params.set_param_arch("PrecastChamfer", value)

    def setDentLength(self, value):
        self.DentLength = value
        params.set_param_arch("PrecastDentLength", value)

    def setDentWidth(self, value):
        self.DentWidth = value
        params.set_param_arch("PrecastDentWidth", value)

    def setDentHeight(self, value):
        self.DentHeight = value
        params.set_param_arch("PrecastDentHeight", value)

    def setBase(self, value):
        self.Base = value
        params.set_param_arch("PrecastBase", value)

    def setHoleMajor(self, value):
        self.HoleMajor = value
        params.set_param_arch("PrecastHoleMajor", value)

    def setHoleMinor(self, value):
        self.HoleMinor = value
        params.set_param_arch("PrecastHoleMinor", value)

    def setHoleSpacing(self, value):
        self.HoleSpacing = value
        params.set_param_arch("PrecastHoleSpacing", value)

    def setGrooveDepth(self, value):
        self.GrooveDepth = value
        params.set_param_arch("PrecastGrooveDepth", value)

    def setGrooveHeight(self, value):
        self.GrooveHeight = value
        params.set_param_arch("PrecastGrooveHeight", value)

    def setGrooveSpacing(self, value):
        self.GrooveSpacing = value
        params.set_param_arch("PrecastGrooveSpacing", value)

    def setDownLength(self, value):
        self.DownLength = value
        params.set_param_arch("PrecastDownLength", value)

    def setRiser(self, value):
        self.Riser = value
        params.set_param_arch("PrecastRiser", value)

    def setTread(self, value):
        self.Tread = value
        params.set_param_arch("PrecastTread", value)

    def retranslateUi(self, dialog):
        from PySide import QtGui

        self.form.setWindowTitle(translate("Arch", "Precast elements"))
        self.labelSlabType.setText(translate("Arch", "Slab type"))
        self.labelChamfer.setText(translate("Arch", "Chamfer"))
        self.labelDentLength.setText(translate("Arch", "Dent length"))
        self.labelDentWidth.setText(translate("Arch", "Dent width"))
        self.labelDentHeight.setText(translate("Arch", "Dent height"))
        self.labelBase.setText(translate("Arch", "Slab base"))
        self.labelHoleNumber.setText(translate("Arch", "Number of holes"))
        self.labelHoleMajor.setText(translate("Arch", "Major diameter of holes"))
        self.labelHoleMinor.setText(translate("Arch", "Minor diameter of holes"))
        self.labelHoleSpacing.setText(translate("Arch", "Spacing between holes"))
        self.labelGrooveNumber.setText(translate("Arch", "Number of grooves"))
        self.labelGrooveDepth.setText(translate("Arch", "Depth of grooves"))
        self.labelGrooveHeight.setText(translate("Arch", "Height of grooves"))
        self.labelGrooveSpacing.setText(translate("Arch", "Spacing between grooves"))
        self.labelRiserNumber.setText(translate("Arch", "Number of risers"))
        self.labelDownLength.setText(translate("Arch", "Length of down floor"))
        self.labelRiser.setText(translate("Arch", "Height of risers"))
        self.labelTread.setText(translate("Arch", "Depth of treads"))

    def setPreset(self, preset):
        self.preview.hide()
        if preset == "Beam":
            self.preview.load(":/ui/ParametersBeam.svg")
            self.labelSlabType.hide()
            self.valueSlabType.hide()
            self.labelChamfer.show()
            self.valueChamfer.show()
            self.labelDentLength.show()
            self.valueDentLength.show()
            self.labelDentWidth.hide()
            self.valueDentWidth.hide()
            self.labelDentHeight.show()
            self.valueDentHeight.show()
            self.labelBase.hide()
            self.valueBase.hide()
            self.labelHoleNumber.hide()
            self.valueHoleNumber.hide()
            self.labelHoleMajor.hide()
            self.valueHoleMajor.hide()
            self.labelHoleMinor.hide()
            self.valueHoleMinor.hide()
            self.labelHoleSpacing.hide()
            self.valueHoleSpacing.hide()
            self.labelGrooveNumber.hide()
            self.valueGrooveNumber.hide()
            self.labelGrooveDepth.hide()
            self.valueGrooveDepth.hide()
            self.labelGrooveHeight.hide()
            self.valueGrooveHeight.hide()
            self.labelGrooveSpacing.hide()
            self.valueGrooveSpacing.hide()
            self.valueHoleSpacing.hide()
            self.labelRiserNumber.hide()
            self.valueRiserNumber.hide()
            self.labelDownLength.hide()
            self.valueDownLength.hide()
            self.labelRiser.hide()
            self.valueRiser.hide()
            self.labelTread.hide()
            self.valueTread.hide()
        elif preset == "Pillar":
            self.preview.load(":/ui/ParametersPillar.svg")
            self.labelSlabType.hide()
            self.valueSlabType.hide()
            self.labelChamfer.show()
            self.valueChamfer.show()
            self.labelDentLength.hide()
            self.valueDentLength.hide()
            self.labelDentWidth.hide()
            self.valueDentWidth.hide()
            self.labelDentHeight.hide()
            self.valueDentHeight.hide()
            self.labelBase.hide()
            self.valueBase.hide()
            self.labelHoleNumber.hide()
            self.valueHoleNumber.hide()
            self.labelHoleMajor.hide()
            self.valueHoleMajor.hide()
            self.labelHoleMinor.hide()
            self.valueHoleMinor.hide()
            self.labelHoleSpacing.hide()
            self.valueHoleSpacing.hide()
            self.labelGrooveNumber.show()
            self.valueGrooveNumber.show()
            self.labelGrooveDepth.show()
            self.valueGrooveDepth.show()
            self.labelGrooveHeight.show()
            self.valueGrooveHeight.show()
            self.labelGrooveSpacing.show()
            self.valueGrooveSpacing.show()
            self.labelRiserNumber.hide()
            self.valueRiserNumber.hide()
            self.labelDownLength.hide()
            self.valueDownLength.hide()
            self.labelRiser.hide()
            self.valueRiser.hide()
            self.labelTread.hide()
            self.valueTread.hide()
        elif preset == "Panel":
            self.preview.load(":/ui/ParametersPanel.svg")
            self.labelSlabType.hide()
            self.valueSlabType.hide()
            self.labelChamfer.show()
            self.valueChamfer.show()
            self.labelDentLength.hide()
            self.valueDentLength.hide()
            self.labelDentWidth.show()
            self.valueDentWidth.show()
            self.labelDentHeight.show()
            self.valueDentHeight.show()
            self.labelBase.hide()
            self.valueBase.hide()
            self.labelHoleNumber.hide()
            self.valueHoleNumber.hide()
            self.labelHoleMajor.hide()
            self.valueHoleMajor.hide()
            self.labelHoleMinor.hide()
            self.valueHoleMinor.hide()
            self.labelHoleSpacing.hide()
            self.valueHoleSpacing.hide()
            self.labelGrooveNumber.hide()
            self.valueGrooveNumber.hide()
            self.labelGrooveDepth.hide()
            self.valueGrooveDepth.hide()
            self.labelGrooveHeight.hide()
            self.valueGrooveHeight.hide()
            self.labelGrooveSpacing.hide()
            self.valueGrooveSpacing.hide()
            self.labelRiserNumber.hide()
            self.valueRiserNumber.hide()
            self.labelDownLength.hide()
            self.valueDownLength.hide()
            self.labelRiser.hide()
            self.valueRiser.hide()
            self.labelTread.hide()
            self.valueTread.hide()
        elif preset == "Slab":
            self.preview.load(":/ui/ParametersSlab.svg")
            self.labelSlabType.show()
            self.valueSlabType.show()
            self.labelChamfer.hide()
            self.valueChamfer.hide()
            self.labelDentLength.hide()
            self.valueDentLength.hide()
            self.labelDentWidth.hide()
            self.valueDentWidth.hide()
            self.labelDentHeight.hide()
            self.valueDentHeight.hide()
            self.labelBase.show()
            self.valueBase.show()
            self.labelHoleNumber.show()
            self.valueHoleNumber.show()
            self.labelHoleMajor.show()
            self.valueHoleMajor.show()
            self.labelHoleMinor.show()
            self.valueHoleMinor.show()
            self.labelHoleSpacing.show()
            self.valueHoleSpacing.show()
            self.labelGrooveNumber.hide()
            self.valueGrooveNumber.hide()
            self.labelGrooveDepth.hide()
            self.valueGrooveDepth.hide()
            self.labelGrooveHeight.hide()
            self.valueGrooveHeight.hide()
            self.labelGrooveSpacing.hide()
            self.valueGrooveSpacing.hide()
            self.labelRiserNumber.hide()
            self.valueRiserNumber.hide()
            self.labelDownLength.hide()
            self.valueDownLength.hide()
            self.labelRiser.hide()
            self.valueRiser.hide()
            self.labelTread.hide()
            self.valueTread.hide()
        elif preset == "I-Beam":
            self.preview.load(":/ui/ParametersIbeam.svg")
            self.labelSlabType.hide()
            self.valueSlabType.hide()
            self.labelChamfer.show()
            self.valueChamfer.show()
            self.labelDentLength.hide()
            self.valueDentLength.hide()
            self.labelDentWidth.hide()
            self.valueDentWidth.hide()
            self.labelDentHeight.hide()
            self.valueDentHeight.hide()
            self.labelBase.show()
            self.valueBase.show()
            self.labelHoleNumber.hide()
            self.valueHoleNumber.hide()
            self.labelHoleMajor.hide()
            self.valueHoleMajor.hide()
            self.labelHoleMinor.hide()
            self.valueHoleMinor.hide()
            self.labelHoleSpacing.hide()
            self.valueHoleSpacing.hide()
            self.labelGrooveNumber.hide()
            self.valueGrooveNumber.hide()
            self.labelGrooveDepth.hide()
            self.valueGrooveDepth.hide()
            self.labelGrooveHeight.hide()
            self.valueGrooveHeight.hide()
            self.labelGrooveSpacing.hide()
            self.valueGrooveSpacing.hide()
            self.labelRiserNumber.hide()
            self.valueRiserNumber.hide()
            self.labelDownLength.hide()
            self.valueDownLength.hide()
            self.labelRiser.hide()
            self.valueRiser.hide()
            self.labelTread.hide()
            self.valueTread.hide()
        elif preset == "Stairs":
            self.preview.load(":/ui/ParametersStairs.svg")
            self.labelSlabType.hide()
            self.valueSlabType.hide()
            self.labelChamfer.hide()
            self.valueChamfer.hide()
            self.labelDentLength.hide()
            self.valueDentLength.hide()
            self.labelDentWidth.hide()
            self.valueDentWidth.hide()
            self.labelDentHeight.hide()
            self.valueDentHeight.hide()
            self.labelBase.hide()
            self.valueBase.hide()
            self.labelHoleNumber.hide()
            self.valueHoleNumber.hide()
            self.labelHoleMajor.hide()
            self.valueHoleMajor.hide()
            self.labelHoleMinor.hide()
            self.valueHoleMinor.hide()
            self.labelHoleSpacing.hide()
            self.valueHoleSpacing.hide()
            self.labelGrooveNumber.hide()
            self.valueGrooveNumber.hide()
            self.labelGrooveDepth.hide()
            self.valueGrooveDepth.hide()
            self.labelGrooveHeight.hide()
            self.valueGrooveHeight.hide()
            self.labelGrooveSpacing.hide()
            self.valueGrooveSpacing.hide()
            self.labelRiserNumber.show()
            self.valueRiserNumber.show()
            self.labelDownLength.show()
            self.valueDownLength.show()
            self.labelRiser.show()
            self.valueRiser.show()
            self.labelTread.show()
            self.valueTread.show()
        self.preview.show()


class _DentsTaskPanel:
    """The TaskPanel for dent creation"""

    def __init__(self):

        import FreeCADGui
        from PySide import QtCore, QtGui, QtSvgWidgets

        self.form = QtGui.QWidget()
        self.grid = QtGui.QGridLayout(self.form)
        self.Rotations = ["N", "S", "E", "O"]
        self.RotationAngles = [90, 270, 0, 180]

        # dents list
        self.labelDents = QtGui.QLabel()
        self.listDents = QtGui.QListWidget()
        self.grid.addWidget(self.labelDents, 0, 0, 1, 2)
        self.grid.addWidget(self.listDents, 1, 0, 1, 2)

        # buttons
        self.buttonAdd = QtGui.QPushButton()
        self.buttonRemove = QtGui.QPushButton()
        self.grid.addWidget(self.buttonAdd, 2, 0, 1, 1)
        self.grid.addWidget(self.buttonRemove, 2, 1, 1, 1)

        # image display
        self.preview = QtSvgWidgets.QSvgWidget(":/ui/ParametersDent.svg")
        self.preview.setMaximumWidth(200)
        self.preview.setMinimumHeight(120)
        self.grid.addWidget(self.preview, 3, 0, 1, 2)

        # parameters
        self.labelLength = QtGui.QLabel()
        self.valueLength = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelLength, 4, 0, 1, 1)
        self.grid.addWidget(self.valueLength, 4, 1, 1, 1)

        self.labelWidth = QtGui.QLabel()
        self.valueWidth = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelWidth, 5, 0, 1, 1)
        self.grid.addWidget(self.valueWidth, 5, 1, 1, 1)

        self.labelHeight = QtGui.QLabel()
        self.valueHeight = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelHeight, 6, 0, 1, 1)
        self.grid.addWidget(self.valueHeight, 6, 1, 1, 1)

        self.labelSlant = QtGui.QLabel()
        self.valueSlant = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelSlant, 7, 0, 1, 1)
        self.grid.addWidget(self.valueSlant, 7, 1, 1, 1)

        self.labelLevel = QtGui.QLabel()
        self.valueLevel = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelLevel, 8, 0, 1, 1)
        self.grid.addWidget(self.valueLevel, 8, 1, 1, 1)

        self.labelRotation = QtGui.QLabel()
        self.valueRotation = QtGui.QComboBox()
        self.valueRotation.addItems(self.Rotations)
        self.valueRotation.setCurrentIndex(0)
        self.grid.addWidget(self.labelRotation, 9, 0, 1, 1)
        self.grid.addWidget(self.valueRotation, 9, 1, 1, 1)

        self.labelOffset = QtGui.QLabel()
        self.valueOffset = FreeCADGui.UiLoader().createWidget("Gui::InputField")
        self.grid.addWidget(self.labelOffset, 10, 0, 1, 1)
        self.grid.addWidget(self.valueOffset, 10, 1, 1, 1)

        # signals/slots
        QtCore.QObject.connect(
            self.valueLength, QtCore.SIGNAL("valueChanged(double)"), self.setLength
        )
        QtCore.QObject.connect(
            self.valueWidth, QtCore.SIGNAL("valueChanged(double)"), self.setWidth
        )
        QtCore.QObject.connect(
            self.valueHeight, QtCore.SIGNAL("valueChanged(double)"), self.setHeight
        )
        QtCore.QObject.connect(
            self.valueSlant, QtCore.SIGNAL("valueChanged(double)"), self.setSlant
        )
        QtCore.QObject.connect(
            self.valueLevel, QtCore.SIGNAL("valueChanged(double)"), self.setLevel
        )
        QtCore.QObject.connect(
            self.valueRotation, QtCore.SIGNAL("currentIndexChanged(int)"), self.setDent
        )
        QtCore.QObject.connect(
            self.valueOffset, QtCore.SIGNAL("valueChanged(double)"), self.setOffset
        )
        QtCore.QObject.connect(self.buttonAdd, QtCore.SIGNAL("clicked()"), self.addDent)
        QtCore.QObject.connect(self.buttonRemove, QtCore.SIGNAL("clicked()"), self.removeDent)
        QtCore.QObject.connect(
            self.listDents, QtCore.SIGNAL("itemClicked(QListWidgetItem*)"), self.editDent
        )
        self.retranslateUi(self.form)
        self.form.hide()

    def setLength(self, value):
        self.Length = value
        self.setDent()

    def setWidth(self, value):
        self.Width = value
        self.setDent()

    def setHeight(self, value):
        self.Height = value
        self.setDent()

    def setSlant(self, value):
        self.Slant = value
        self.setDent()

    def setLevel(self, value):
        self.Level = value
        self.setDent()

    def setOffset(self, value):
        self.Offset = value
        self.setDent()

    def fillDents(self, dents):
        self.listDents.clear()
        i = 1
        for d in dents:
            s = "Dent " + str(i) + " :" + d
            self.listDents.addItem(s)
            i += 1

    def setDent(self, i=0):
        if self.listDents.currentItem():
            num = str(self.listDents.currentRow() + 1)
            rot = self.RotationAngles[self.valueRotation.currentIndex()]
            s = (
                "Dent "
                + num
                + " :"
                + str(self.Length)
                + ";"
                + str(self.Width)
                + ";"
                + str(self.Height)
                + ";"
                + str(self.Slant)
                + ";"
                + str(self.Level)
                + ";"
                + str(rot)
                + ";"
                + str(self.Offset)
            )
            self.listDents.currentItem().setText(s)

    def addDent(self):
        num = str(self.listDents.count() + 1)
        rot = self.RotationAngles[self.valueRotation.currentIndex()]
        s = (
            "Dent "
            + num
            + " :"
            + str(self.Length)
            + ";"
            + str(self.Width)
            + ";"
            + str(self.Height)
            + ";"
            + str(self.Slant)
            + ";"
            + str(self.Level)
            + ";"
            + str(rot)
            + ";"
            + str(self.Offset)
        )
        self.listDents.addItem(s)
        self.listDents.setCurrentRow(self.listDents.count() - 1)
        self.editDent()

    def removeDent(self):
        if self.listDents.currentItem():
            self.listDents.takeItem(self.listDents.currentRow())

    def editDent(self, item=None):
        if self.listDents.currentItem():
            s = self.listDents.currentItem().text()
            s = s.split(":")[1]
            s = s.split(";")
            self.valueLength.setText(
                FreeCAD.Units.Quantity(float(s[0]), FreeCAD.Units.Length).UserString
            )
            self.valueWidth.setText(
                FreeCAD.Units.Quantity(float(s[1]), FreeCAD.Units.Length).UserString
            )
            self.valueHeight.setText(
                FreeCAD.Units.Quantity(float(s[2]), FreeCAD.Units.Length).UserString
            )
            self.valueSlant.setText(
                FreeCAD.Units.Quantity(float(s[3]), FreeCAD.Units.Length).UserString
            )
            self.valueLevel.setText(
                FreeCAD.Units.Quantity(float(s[4]), FreeCAD.Units.Length).UserString
            )
            self.valueRotation.setCurrentIndex(self.RotationAngles.index(int(s[5])))
            self.valueOffset.setText(
                FreeCAD.Units.Quantity(float(s[6]), FreeCAD.Units.Length).UserString
            )

    def retranslateUi(self, dialog):
        from PySide import QtGui

        self.form.setWindowTitle(translate("Arch", "Precast options"))
        self.labelDents.setText(translate("Arch", "Dents list"))
        self.buttonAdd.setText(translate("Arch", "Add dent"))
        self.buttonRemove.setText(translate("Arch", "Remove dent"))
        self.labelLength.setText(translate("Arch", "Length"))
        self.labelWidth.setText(translate("Arch", "Width"))
        self.labelHeight.setText(translate("Arch", "Height"))
        self.labelSlant.setText(translate("Arch", "Slant"))
        self.labelLevel.setText(translate("Arch", "Level"))
        self.labelRotation.setText(translate("Arch", "Rotation"))
        self.labelOffset.setText(translate("Arch", "Offset"))

    def getValues(self):
        l = []
        for i in range(self.listDents.count()):
            s = self.listDents.item(i).text()
            l.append(s.split(":")[1])
        return l


def makePrecast(
    precasttype=None,
    length=0,
    width=0,
    height=0,
    slabtype="",
    chamfer=0,
    dentlength=0,
    dentwidth=0,
    dentheight=0,
    dents=[],
    base=0,
    holenumber=0,
    holemajor=0,
    holeminor=0,
    holespacing=0,
    groovenumber=0,
    groovedepth=0,
    grooveheight=0,
    groovespacing=0,
    risernumber=0,
    downlength=0,
    riser=0,
    tread=0,
):
    "Creates one of the precast objects in the current document"

    if precasttype == "Beam":
        obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Beam")
        _PrecastBeam(obj)
        obj.Length = length
        obj.Width = width
        obj.Height = height
        obj.Chamfer = chamfer
        obj.Dents = dents
        obj.DentLength = dentlength
        obj.DentHeight = dentheight
    elif precasttype == "Pillar":
        obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Pillar")
        _PrecastPillar(obj)
        obj.Length = length
        obj.Width = width
        obj.Height = height
        obj.Chamfer = chamfer
        obj.Dents = dents
        obj.GrooveNumber = groovenumber
        obj.GrooveDepth = groovedepth
        obj.GrooveHeight = grooveheight
        obj.GrooveSpacing = groovespacing
    elif precasttype == "Panel":
        obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Panel")
        _PrecastPanel(obj)
        obj.Length = length
        obj.Width = width
        obj.Height = height
        obj.Chamfer = chamfer
        obj.DentWidth = dentwidth
        obj.DentHeight = dentheight
    elif precasttype == "Slab":
        obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Slab")
        _PrecastSlab(obj)
        obj.SlabType = slabtype
        obj.Length = length
        obj.Width = width
        obj.Height = height
        obj.SlabBase = base
        obj.HoleNumber = holenumber
        obj.HoleMajor = holemajor
        obj.HoleMinor = holeminor
        obj.HoleSpacing = holespacing
    elif precasttype == "I-Beam":
        obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Beam")
        _PrecastIbeam(obj)
        obj.Length = length
        obj.Width = width
        obj.Height = height
        obj.Chamfer = chamfer
        obj.BeamBase = base
    elif precasttype == "Stairs":
        obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Stairs")
        _PrecastStairs(obj)
        obj.Length = length
        obj.Width = width
        obj.Height = height
        obj.RiserNumber = risernumber
        obj.DownLength = downlength
        obj.Riser = riser
        obj.Tread = tread
    else:
        obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "Precast")
        _Precast(obj)
    if FreeCAD.GuiUp:
        _ViewProviderPrecast(obj.ViewObject)
    return obj
