import FreeCAD
import FreeCADGui
import Part
from PySide import QtGui
import math

INCH_TO_MM = 25.4

def inch_to_mm(v):
    return float(v) * INCH_TO_MM


def clear_old_walls(doc):
    """
    Delete all geometry belonging to Wall1, Wall2, Wall3 from the document.
    Uses Name/Label prefixes to find everything.
    """
    to_delete = []
    prefixes = ("Wall1", "Wall2", "Wall3")

    for obj in doc.Objects:
        name = getattr(obj, "Name", "")
        label = getattr(obj, "Label", "")
        if name.startswith(prefixes) or label.startswith(prefixes):
            to_delete.append(obj)

    # Remove from document
    for obj in to_delete:
        doc.removeObject(obj.Name)


def build_wall_module_2x6(name, spacing_in, height_in, width_in, base_vec):
    """
    Build a 2x6 wall named `name` at a given base_vec (FreeCAD.Vector).
    Returns the wall width in mm.
    """

    doc = FreeCAD.ActiveDocument
    if doc is None:
        doc = FreeCAD.newDocument("WallModuleDoc")

    # convert to mm
    spacing = inch_to_mm(spacing_in)
    height  = inch_to_mm(height_in)
    width   = inch_to_mm(width_in)

    stud_t = inch_to_mm(1.5)      # 2x6 actual thickness (1.5")
    stud_d = inch_to_mm(5.5)      # wall thickness (5.5")
    osb_t  = inch_to_mm(0.4375)   # 7/16" OSB

    grp = doc.addObject("App::DocumentObjectGroup", name)

    # bottom plate
    bottom = Part.makeBox(width, stud_d, stud_t)
    bottom.translate(base_vec)
    b = doc.addObject("Part::Feature", f"{name}_BottomPlate")
    b.Shape = bottom
    grp.addObject(b)

    # top plate
    top = Part.makeBox(width, stud_d, stud_t)
    top.translate(base_vec + FreeCAD.Vector(0, 0, height - stud_t))
    t = doc.addObject("Part::Feature", f"{name}_TopPlate")
    t.Shape = top
    grp.addObject(t)

    # studs
    stud_len = height - 2.0 * stud_t
    positions = [0.0]

    n_max = int(math.floor(width_in / spacing_in))
    for n in range(1, n_max + 1):
        x = inch_to_mm(n * spacing_in)
        if x <= (width - stud_t):
            positions.append(x)

    right = width - stud_t
    if all(abs(right - p) > 1.0 for p in positions):
        positions.append(right)

    positions = sorted(positions)

    for i, x in enumerate(positions):
        s = Part.makeBox(stud_t, stud_d, stud_len)
        s.translate(base_vec + FreeCAD.Vector(x, 0, stud_t))
        obj = doc.addObject("Part::Feature", f"{name}_Stud_{i:02d}")
        obj.Shape = s
        grp.addObject(obj)

    # OSB
    osb = Part.makeBox(width, osb_t, height)
    osb.translate(base_vec + FreeCAD.Vector(0, stud_d, 0))
    o = doc.addObject("Part::Feature", f"{name}_OSB")
    o.Shape = osb
    grp.addObject(o)

    doc.recompute()
    return width


class ThreeWallDialog(QtGui.QDialog):
    """
    Live-update UI for up to 3 walls.
    Any parameter change:
      - deletes existing walls
      - rebuilds the current configuration
    Walls are placed side-by-side along +X.
    """

    def __init__(self, parent=None):
        super(ThreeWallDialog, self).__init__(parent)
        self.setWindowTitle("Three Wall Modules – Live (Delete & Redraw)")

        layout = QtGui.QFormLayout(self)

        # ---- Wall 1 ----
        layout.addRow(QtGui.QLabel("------ WALL 1 ------"))
        self.w1enable = QtGui.QCheckBox("Enable Wall 1"); self.w1enable.setChecked(True)
        layout.addRow(self.w1enable)

        self.w1spacing = QtGui.QComboBox()
        self.w1spacing.addItem("16 in", 16.0)
        self.w1spacing.addItem("24 in", 24.0)
        layout.addRow("Wall 1 Spacing", self.w1spacing)

        self.w1height = QtGui.QDoubleSpinBox()
        self.w1height.setRange(24.0, 168.0)
        self.w1height.setValue(96.0)   # default 96"
        self.w1height.setSuffix(" in")
        layout.addRow("Wall 1 Height", self.w1height)

        self.w1width = QtGui.QDoubleSpinBox()
        self.w1width.setRange(12.0, 600.0)
        self.w1width.setValue(48.0)    # default 48"
        self.w1width.setSuffix(" in")
        layout.addRow("Wall 1 Width", self.w1width)

        # ---- Wall 2 ----
        layout.addRow(QtGui.QLabel("------ WALL 2 ------"))
        self.w2enable = QtGui.QCheckBox("Enable Wall 2"); self.w2enable.setChecked(True)
        layout.addRow(self.w2enable)

        self.w2spacing = QtGui.QComboBox()
        self.w2spacing.addItem("16 in", 16.0)
        self.w2spacing.addItem("24 in", 24.0)
        layout.addRow("Wall 2 Spacing", self.w2spacing)

        self.w2height = QtGui.QDoubleSpinBox()
        self.w2height.setRange(24.0, 168.0)
        self.w2height.setValue(96.0)
        self.w2height.setSuffix(" in")
        layout.addRow("Wall 2 Height", self.w2height)

        self.w2width = QtGui.QDoubleSpinBox()
        self.w2width.setRange(12.0, 600.0)
        self.w2width.setValue(48.0)
        self.w2width.setSuffix(" in")
        layout.addRow("Wall 2 Width", self.w2width)

        # ---- Wall 3 ----
        layout.addRow(QtGui.QLabel("------ WALL 3 ------"))
        self.w3enable = QtGui.QCheckBox("Enable Wall 3"); self.w3enable.setChecked(True)
        layout.addRow(self.w3enable)

        self.w3spacing = QtGui.QComboBox()
        self.w3spacing.addItem("16 in", 16.0)
        self.w3spacing.addItem("24 in", 24.0)
        layout.addRow("Wall 3 Spacing", self.w3spacing)

        self.w3height = QtGui.QDoubleSpinBox()
        self.w3height.setRange(24.0, 168.0)
        self.w3height.setValue(96.0)
        self.w3height.setSuffix(" in")
        layout.addRow("Wall 3 Height", self.w3height)

        self.w3width = QtGui.QDoubleSpinBox()
        self.w3width.setRange(12.0, 600.0)
        self.w3width.setValue(48.0)
        self.w3width.setSuffix(" in")
        layout.addRow("Wall 3 Width", self.w3width)

        # Close button
        closebtn = QtGui.QPushButton("Close")
        closebtn.clicked.connect(self.close)
        layout.addRow(closebtn)

        # Wire up live updates
        self._connect_live()
        self.update_model()

    def _connect_live(self):
        controls = [
            self.w1enable, self.w1spacing, self.w1height, self.w1width,
            self.w2enable, self.w2spacing, self.w2height, self.w2width,
            self.w3enable, self.w3spacing, self.w3height, self.w3width,
        ]

        for c in controls:
            if hasattr(c, "stateChanged"):
                c.stateChanged.connect(self.update_model)
            elif hasattr(c, "currentIndexChanged"):
                c.currentIndexChanged.connect(self.update_model)
            elif hasattr(c, "valueChanged"):
                c.valueChanged.connect(self.update_model)

    def update_model(self, *args):
        doc = FreeCAD.ActiveDocument
        if doc is None:
            doc = FreeCAD.newDocument("WallModuleDoc")

        # Delete all existing wall geometry
        clear_old_walls(doc)

        current_x = 0.0

        def maybe_build(idx, enable, spacing, height, width):
            nonlocal current_x
            if not enable:
                return
            s = spacing.itemData(spacing.currentIndex())
            h = height.value()
            w = width.value()
            name = f"Wall{idx}"
            base = FreeCAD.Vector(current_x, 0, 0)
            width_mm = build_wall_module_2x6(name, s, h, w, base)
            current_x += width_mm

        maybe_build(1, self.w1enable.isChecked(), self.w1spacing, self.w1height, self.w1width)
        maybe_build(2, self.w2enable.isChecked(), self.w2spacing, self.w2height, self.w2width)
        maybe_build(3, self.w3enable.isChecked(), self.w3spacing, self.w3height, self.w3width)


def main():
    mw = FreeCADGui.getMainWindow()
    dlg = ThreeWallDialog(mw)
    dlg.show()

main()
