# -*- coding: utf-8 -*-
__author__ = 'TUMCIVIL'
__version__ = '2.0.0'
__title__ = 'เซ็ตระดับท้องผนัง\nชนหลังคาน'
__doc__ = """Created by : TUMCIVIL TEAM
Version : 2.0.0
Update : วันที่ 03-03-2025
_________________________________________________________________
รายการ :
เซ็ตระดับท้องผนังให้ชนหลังคาน
_________________________________________________________________
วิธีการใช้ :
1. เลือกคานหลัก
2. เลือกผนังที่ต้องการเช็ตระดับได้ไม่มีที่สิ้นสุด
3. ต้องการออกกด 'Esc'
 """
import sys
import re
import Autodesk
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *
import Autodesk.Revit.DB as DB
from Autodesk.Revit.DB.Structure import *
from Autodesk.Revit.DB.Structure import Rebar as rb
import pyrevit

import  os
from pyrevit import forms, revit
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB import (BuiltInParameter)
# from Autodesk.Revit.DB import RevitLinkInstance

#>>>>>>>>>> .NET IMPORTS
import clr
clr.AddReference("System.Windows.Forms")
clr.AddReference("System")
from System.Collections.Generic import List
from System.Windows.Controls import ComboBoxItem
import wpf
from Autodesk.Revit.UI.Selection    import ISelectionFilter, ObjectType, Selection

# >>>>>>>>>> CUSTOM IMPORTS
from Snippets._convert_units import convert_internal_units
from Snippets._level import levels,get_levels_walls
from Snippets._level import *
from Selection._select_element import CustomISelectionFilter, pick_column
from System.Collections.ObjectModel import ObservableCollection
from System.ComponentModel import INotifyPropertyChanged

doc   = __revit__.ActiveUIDocument.Document
uidoc = __revit__.ActiveUIDocument
app   = __revit__.Application

def checkParameter(parameter):
    storageType = parameter.StorageType
    if (storageType.ToString() == "ElementId"):
        value = parameter.AsValueString()
    return value

#>>>>>>>>> LIMIT SELECTION
class CustomISelectionFilter(ISelectionFilter):
    """Filter user selection to certain element."""
    def __init__(self, cats):
        self.cats = cats
    def AllowElement(self, e):
        if str(e.Category.Id) == str(self.cats):
        #if e.Category.Name == "Walls"
            return True
        return False

class ISelectionFilter_Classes(ISelectionFilter):
    def __init__(self, allowed_types):
        """ ISelectionFilter made to filter with types
        :param allowed_types: list of allowed Types"""
        self.allowed_types = allowed_types

    def AllowElement(self, element):
        if type(element) in self.allowed_types:
            return True
        # else:
        #     return False

#>>>>>>>>>> PICK COLUMN
def pick_beam(given_uidoc = uidoc,text = ""):
    """Function to promt user to select a column element in Revit UI."""
    # beam_ref = given_uidoc.Selection.PickObject(ObjectType.LinkedElement, CustomISelectionFilter("-2001325"), text)    # -2001320 <- Id of OST_StructuralFraming
    beam_ref = given_uidoc.Selection.PickObject(ObjectType.Element, CustomISelectionFilter("-2001320"), text)    # -2001320 <- Id of OST_StructuralFraming
    beam     = given_uidoc.Document.GetElement(beam_ref)
    # print("TYPE BEAM = {}".format(type(beam)))
    return beam
def pick_column(given_uidoc = uidoc,text = "เลือกเสา" ):
    """Function to promt user to select a column element in Revit UI."""
    # forms.WarningBar(title='Select Walls.')
    column_ref = given_uidoc.Selection.PickObject(ObjectType.Element, CustomISelectionFilter("-2001330"), text)    # -2001330 <- Id of OST_StructuralColumns
    column     = given_uidoc.Document.GetElement(column_ref)
    return column

def pick_wall(given_uidoc = uidoc):
    """Function to promt user to select a wall element in Revit UI."""
    wall_ref = given_uidoc.Selection.PickObject(ObjectType.Element, CustomISelectionFilter("-2000011"), "Select a Wall")    # -2000011 <- Id of OST_Walls
    wall     = given_uidoc.Document.GetElement(wall_ref)
    return wall


def get_selected_beams(uidoc, exitscript = True):
    """Function to Pick Beams. Currently selected beams will be pre-selected."""
    doc       = uidoc.Document
    selection = uidoc.Selection  # type: Selection

    selected_beams = []
    ISF_Rooms      = CustomISelectionFilter("-2001320")
    # print("ISF_Rooms = {}".format(ISF_Rooms))
    selected_elements = [doc.GetElement(e_id) for e_id in selection.GetElementIds()]
    selected_beams    = [e for e in selected_elements]
    # print("selected_walls = {}".format(selected_walls))

    ref_beams         = [Reference(r) for r in selected_beams]
    ref_preselection  = List[Reference](ref_beams)

    # Pick Beams (exterior walls are preselected)

    try:
        with forms.WarningBar(title='โปรดเลือกคานที่เชื่อมหัวเสาเสร็จแล้วกด Finish.'):
            ref_selected_beams = selection.PickObjects(ObjectType.Element,
                                                       ISF_Rooms,
                                                       'โปรดเลือกคานเสร็จแล้วกด Finish',
                                                       ref_preselection)

        selected_beams  = [doc.GetElement(ref) for ref in ref_selected_beams]
    except:
        pass

    if not selected_beams:
        error_msg = 'No Beams were selected.\nPlease Try Again'
        forms.alert(error_msg, title='Beams Selection has Failed.', exitscript=exitscript)

    return selected_beams

# def levels():
#     levels = DB.FilteredElementCollector(doc).OfCategory(DB.BuiltInCategory.OST_Levels) \
#         .WhereElementIsNotElementType() \
#         .ToElements()
#     # print("levels = {}".format(levels))
#     l = len(levels)
#     # print("l = {}".format(l))
#     # out3 = []
#     for e3 in levels:
#         p3 =[]
#         name = e3.get_Parameter(BuiltInParameter.DATUM_TEXT).AsString()
#         # name = e3.LookupParameter("Name").AsString()
#         eleLev = e3.get_Parameter(BuiltInParameter.LEVEL_ELEV).AsDouble()
#         # eleLev = e3.LookupParameter("Elevation").AsDouble()
#         id = e3.Id
#         p3.append(name)
#         p3.append(eleLev)
#         p3.append(id)
#         # print("levels = {} , {}".format(name,eleLev))
#
#         out3.append(p3)
    # for i in out3:
    # print("out3 = {}".format(out3))



def checkLevel(value):
    for i in out3:
        if i[0]==value:
            value1 = i[1]
            value2 = i[2]
            # print("i[0] = {}".format(i[0]))
            # print("i[2] = {}".format(i[2]))
    return value1,value2


if __name__ == '__main__':

    out = []
    out3 = []
    levels_model = levels()
    # levels()
    # level = levels()
    # print("levels = {}".format(out3))

    try:    
        # picked_object = uidoc.Selection.PickObject(ObjectType.LinkedElement, "Select beams in the Revit link")
        # Selected_beam = doc.GetElement(picked_object).GetLinkDocument().GetElement(picked_object.LinkedElementId)
        Selected_beam = pick_beam(uidoc,"เลือกคานตัวหลัก")
        # print("picked_object = {}".format(picked_object))
        # print("Selected_beam = {}".format(Selected_beam))

    except: forms.alert("Script is canceled.",exitscript=True,title="Script Canceled.")

    if Selected_beam.Category.Id.IntegerValue == int(BuiltInCategory.OST_StructuralFraming):
        # print("IsBeam = True")
        Main_Top_Constraint     = Selected_beam.get_Parameter(BuiltInParameter.STRUCTURAL_ELEVATION_AT_TOP).AsDouble()
        Main_Bottom_Constraint  = Selected_beam.get_Parameter(BuiltInParameter.STRUCTURAL_ELEVATION_AT_BOTTOM).AsDouble()
        # print("Main_Top_Constraint = {}".format(convert_internal_units(float(Main_Top_Constraint), False, units='mm')))
        # print("Main_Bottom_Constraint = {}".format(convert_internal_units(float(Main_Bottom_Constraint), False, units='mm')))
        with forms.WarningBar(title="Pick Wall to bottom Beam:", handle_esc=True):
            while True:

                #>>>>>>>>>> PICK WALL
                try:    Match_wall = pick_wall(uidoc)
                except: break
                if not Match_wall: break
                levels_wall = get_levels_walls(levels_model,Match_wall)
                Match_Top_Constraint = levels_wall[1]
                Match_Bottom_Constraint = levels_wall[0]
                wall_location = Match_wall.Location
                wall_curve = wall_location.Curve
                # print("Match_Top_Constraint = {}".format(Match_Top_Constraint))
                # print("Match_Top_Constraint2 = {}".format(round(convert_internal_units(float(Match_Top_Constraint), False, units='mm')),0))
                # print("Match_Bottom_Constraint = {}".format(round(convert_internal_units(float(Match_Bottom_Constraint), False, units='mm')),0))

                Main_Top_Constraint_Id  = Match_wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).AsElementId()
                # print("Main_Top_Constraint_Id = {}".format(Main_Top_Constraint_Id))
                #>>>>>>>>>> MATCH WALL PARAMETERS
                match_base_offset        = Match_wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble()
                match_unconnected_height = Match_wall.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).AsDouble()
                match_Z_Top              = Match_Top_Constraint-Main_Top_Constraint

                if isinstance(wall_curve, Line):
                    match_Z_Bottom           = (Main_Top_Constraint)-Match_wall.Location.Curve.Origin.Z
                elif isinstance(wall_curve, Arc):
                    match_Z_Bottom           = (Main_Top_Constraint)-Match_wall.Location.Curve.Center.Z



                # match_Z_Bottom           = (Main_Top_Constraint)-Match_wall.Location.Curve.Origin.Z
                # match_Z_Bottom         = Main_Top_Constraint-(Match_wall.Location.Curve.Origin.Z + match_base_offset)

                # convert_internal_units(float(match_Z_Bottom), False, units='mm')
                # print("Match_wall.Location.Curve.Origin.Z = {}".format(convert_internal_units(float(Match_wall.Location.Curve.Origin.Z), False, units='mm')))
                # print("match_base_offset = {}".format(convert_internal_units(float(match_base_offset), False, units='mm')))
                # print("match_unconnected_height = {}".format(convert_internal_units(float(match_unconnected_height), False, units='mm')))
                # print("match_Z_Top = {}".format(convert_internal_units(float(match_Z_Top), False, units='mm')))
                # print("match_Z_Bottom = {}".format(convert_internal_units(float(match_Z_Bottom), False, units='mm')))

                with Transaction(doc, "Reinforce") as t:
                    t.Start()
                    Match_wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(ElementId.InvalidElementId )
                    Match_wall.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).Set(match_Z_Top)
                    Match_wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).Set(match_Z_Bottom)

                    t.Commit()
    else:
        forms.alert("Beam isn't selected then exited.", exitscript=True, title="Script Canceled.")



