# -*- 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.ไม่สามารถใช้กับคานที่ Slope ได้
2.ไม่สามารถใช้กับคานที่สร้างจาก Model In-Place ได้
_________________________________________________________________
วิธีการใช้ :
1.เลือกคานหลัก
2.เลือกคานที่ต้องการเช็ตระดับหลังคานเท่ากับคานหลัก
3.ต้องการเลิกทำรายการกด Esc

 """
# for timing -------------------------------------------------------------------
# import pyrevit.coreutils as cor
# from pyrevit.coreutils import Timer
# timer = Timer()
# ------------------------------------------------------------------------------
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)

#>>>>>>>>>> .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

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.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 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()
    # print("levels = {}".format(out3))

    try:    Selected_beam = pick_beam(uidoc,"เลือกคานตัวหลัก")
    except: forms.alert("Script is canceled.",exitscript=True,title="Script Canceled.")

    #>>>>>>>>>> TOP
    Main_Top_Constraint     = Selected_beam.get_Parameter(BuiltInParameter.STRUCTURAL_ELEVATION_AT_TOP).AsDouble()
    Beam_Top_Constraint = round(convert_internal_units(Main_Top_Constraint,False,"mm"),2)
    # Beam_Top_Constraint = round(UnitUtils.ConvertFromInternalUnits(Main_Top_Constraint,UnitTypeId.Millimeters),2)
    # print("Beam_Top_Constraint = {}".format(Beam_Top_Constraint))
    Manin_R = Selected_beam.get_Parameter(BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM)
    value = checkParameter(Manin_R)
    Mian_Referece_level =[]
    Mian_Referece_level = checkLevel(value)
    Mian_Start_Level_Offset = Selected_beam.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END0_ELEVATION).AsDouble()
    Beam_Start_Level_Offset = round(UnitUtils.ConvertFromInternalUnits(Mian_Start_Level_Offset,UnitTypeId.Millimeters),2)
    Mian_End_Level_Offset = Selected_beam.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END1_ELEVATION).AsDouble()
    Beam_End_Level_Offset = round(UnitUtils.ConvertFromInternalUnits(Mian_End_Level_Offset,UnitTypeId.Millimeters),2)
    Mian_ZJustifiction = Selected_beam.get_Parameter(BuiltInParameter.Z_JUSTIFICATION).AsInteger()
    Mian_Z_Offset_Value = Selected_beam.get_Parameter(BuiltInParameter.Z_OFFSET_VALUE).AsDouble()
    Beam_Z_Offset_Value = round(UnitUtils.ConvertFromInternalUnits(Mian_Z_Offset_Value,UnitTypeId.Millimeters),2)


    #>>>>>>>>>> LOOP: SELECT MATCH WALL
    with forms.WarningBar(title="เลือกคานที่ต้องการเช็ตค่า (ออกกด Esc):", handle_esc=True):
        while True:

            #>>>>>>>>>> PICK WALL
            try:    Match_beam = pick_beam(uidoc,"เลือกคานที่ต้องการเช็ตค่า (ออกกด Esc)")
            except: break
            if not Match_beam: break
            Match_Top_Constraint = Match_beam.get_Parameter(BuiltInParameter.STRUCTURAL_ELEVATION_AT_TOP).AsDouble()
            Match_Referece_level =[]
            Match_R = Match_beam.get_Parameter(BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM)
            value = checkParameter(Match_R)
            Match_Referece_level = checkLevel(value)

            if Mian_Referece_level[0] == Match_Referece_level[0]:
            #>>>>>>>>>> SET PARAMETERS
                t = Transaction(doc, 'change parameter')
                t.Start()
                Mian_Z_Offset_Value = (Main_Top_Constraint)-(Match_Top_Constraint)\
                                    +Match_beam.get_Parameter(BuiltInParameter.Z_OFFSET_VALUE).AsDouble()
                try:
                    Match_beam.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END0_ELEVATION).Set(Mian_Start_Level_Offset)
                    Match_beam.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END1_ELEVATION).Set(Mian_End_Level_Offset)
                    # Match_beam.get_Parameter(BuiltInParameter.Z_JUSTIFICATION).Set(Mian_ZJustifiction)
                    Match_beam.get_Parameter(BuiltInParameter.Z_OFFSET_VALUE).Set(Mian_Z_Offset_Value)
                except:
                    pass
                t.Commit()
            elif Mian_Referece_level[0] < Match_Referece_level[0]:
                Mian_Z_Offset_Value = (Main_Top_Constraint) - (Match_Top_Constraint)\
                                        + Match_beam.get_Parameter(BuiltInParameter.Z_OFFSET_VALUE).AsDouble()
                t = Transaction(doc, 'change parameter')
                t.Start()    

                try:
                    Match_beam.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END0_ELEVATION).Set(Mian_Start_Level_Offset)
                    Match_beam.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END1_ELEVATION).Set(Mian_End_Level_Offset)
                    # Match_beam.get_Parameter(BuiltInParameter.Z_JUSTIFICATION).Set(Mian_ZJustifiction)
                    Match_beam.get_Parameter(BuiltInParameter.Z_OFFSET_VALUE).Set(Mian_Z_Offset_Value)
                except:
                    pass
                t.Commit()
            elif Mian_Referece_level[0] > Match_Referece_level[0]:
                
                Mian_Z_Offset_Value = (Main_Top_Constraint)-(Match_Top_Constraint)\
                                        + Match_beam.get_Parameter(BuiltInParameter.Z_OFFSET_VALUE).AsDouble()
                t = Transaction(doc, 'change parameter')
                t.Start()    

                try:
                    Match_beam.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END0_ELEVATION).Set(Mian_Start_Level_Offset)
                    Match_beam.get_Parameter(BuiltInParameter.STRUCTURAL_BEAM_END1_ELEVATION).Set(Mian_End_Level_Offset)
                    # Match_beam.get_Parameter(BuiltInParameter.Z_JUSTIFICATION).Set(Mian_ZJustifiction)
                    Match_beam.get_Parameter(BuiltInParameter.Z_OFFSET_VALUE).Set(Mian_Z_Offset_Value)
                except:
                    pass
                t.Commit()



# for timing -------------------------------------------------------------------
# print("====" * 20)
# endtime = timer.get_time()
# print("Time been used = {} sec.".format(endtime))
# currentDate = cor.current_date()
# currentTime = cor.current_time()
# print ("Date : {} ; {}".format(currentDate,currentTime))
# print ("Credited by : {}".format(__author__))
# print("====" * 20)
# ------------------------------------------------------------------------------