# -*- coding: UTF-8 -*-
__author__ = 'TUMCIVIL'
__version__ = '2.0.0'
__title__ = 'ใส่คาน\nในผนัง'
__doc__ = """Created by : TUMCIVIL TEAM
Version : 1.0.0 
Update : ววันที่ 03-03-2025
_________________________________________________________________
รายการ :
ใส่คานในผนัง(ใส่ทับหลัง)
_________________________________________________________________
ข้อจำกัดการใช้งาน :
1.ไม่สามารถใช้กับคานที่ Slope ได้
2.ไม่สามารถใช้กับคานที่สร้างจาก Model In-Place ได้
3.สามารถใส่คานในผนังโค้งได้
_________________________________________________________________
วิธีการใช้ :
1.เลือกประเภททับหลัง และ ขนาดทับหลัง
2.กำหนดความสูงท้องคานจากท้องผนัง กดปุ่มใส่คานในผนัง
3.เลือกผนังที่ต้องการใส่คาน
4.ต้องการเลิกทำรายการกด Esc

 """

import Autodesk
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *
import pyrevit
from pyrevit.forms import WPFWindow
from pyrevit import forms
from Autodesk.Revit.DB import XYZ
import Autodesk.Revit.DB.Structure
from Autodesk.Revit.DB.Structure import *
from Autodesk.Revit.DB.Structure import Rebar as rb
from Autodesk.Revit.DB.Structure import RebarConstraint as cr
from Autodesk.Revit.DB.Structure import RebarConstraintsManager, RebarConstrainedHandle
from Autodesk.Revit.DB.Structure import RebarCoverType

# >>>>>>>>>> .NET IMPORTS
import clr

clr.AddReference("System.Windows.Forms")
clr.AddReference("System")
import sys
from System.Collections.Generic import List
from System.Windows.Controls import ComboBoxItem
from System.Windows.Media.Imaging import BitmapImage
import os
# from System.IO import Path, Directory
from wpf import LoadComponent
import wpf
import re

from collections import OrderedDict

from System.Windows import Application, Window
from System.Windows.Media.Imaging import BitmapImage
from System import Uri


# >>>>>>>>>> CUSTOM IMPORTS
from Snippets._convert_units import convert_internal_units
from Selection._select_element import CustomISelectionFilter, pick_column,pick_wall
from Snippets._level import *
from Snippets._level import levels,get_levels_walls

# from images import *

doc = __revit__.ActiveUIDocument.Document
uidoc = __revit__.ActiveUIDocument
app = __revit__.Application
rvt_year = int(app.VersionNumber)

PATH_SCRIPT = os.path.dirname(__file__)+'\images'

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

class ModalForm(WPFWindow):
    def __init__(self, xaml_file_name):
        WPFWindow.__init__(self, xaml_file_name)
        self.combobox_add_lintel(sort_dict_lintel, self.cmbLintel)

        self.ShowDialog()

    def combobox_add_lintel(self, lintel_type, text):
        for i, j in lintel_type.items():
            item = ComboBoxItem()
            item.Content = i
            text.Items.Add(item)
            # if j == cover_Other_Face_default:
            #     item.IsSelected = True
    def get_selected_lintel(self, text):
        """Function to get selected item from self.UI_text_type."""
        for item in text.Items:
            if item.IsSelected:
                try:
                    lintel_type = sort_dict_lintel[item.Content]
                except:
                    lintel_type = None
                return lintel_type

    def get_selected_lintelSize(self, text):
        """Function to get selected item from self.UI_text_type."""
        for item in text.Items:
            if item.IsSelected:
                try:
                    lintel_type = sort_dict_lintel_type[item.Content]
                except:
                    lintel_type = None
                return lintel_type

    def cmbLintel_SelectionChanged(self, sender, e):
        self.cmbLintelSize.Items.Clear()
        global lintel_selected
        global lintel_family_name
        lintel_selected = self.get_selected_lintel(self.cmbLintel)
        try:
            p1 = []
            for i, j in sort_dict_lintel.items():
                if j == lintel_selected:
                    lintel_family_name = i
                    dict_lintel_type = {(v.get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM).AsString()): v for v in
                                      all_lintel if v.get_Parameter(BuiltInParameter.SYMBOL_FAMILY_NAME_PARAM).AsString() == i}
                    global sort_dict_lintel_type
                    sort_dict_lintel_type = OrderedDict(sorted(dict_lintel_type.items()))

                    self.combobox_add_lintel(sort_dict_lintel_type, self.cmbLintelSize)
        except:
            pass

    def cmbLintelSize_SelectionChanged(self, sender, e):
        global lintelSize_selected
        lintelSize_selected = self.get_selected_lintelSize(self.cmbLintelSize)
        pass

    def fillBeam(self, sender, e):

        if self.cmbLintel.SelectedValue != None and self.cmbLintelSize.SelectedValue != None:
            global height_lintel
            height_lintel = convert_internal_units(float(self.tbHeight.Text), True, "mm")

            # print("height_beam = {}".format(height_beam))
            self.Close()
        elif self.cmbLintel.SelectedValue == None:
            forms.alert("ประเภททับหลังไม่ได้ถูกเลือก.", exitscript=False, title="คำเตือน.")
            pass
        elif self.cmbLintelSize.SelectedValue == None:
            forms.alert("ขนาดทับหลังไม่ได้ถูกเลือก.", exitscript=False, title="คำเตือน.")
            pass

    def cancelBtn(self, sender, e):
        self.Close()
        sys.exit()


if __name__ == '__main__':
    out = []
    levels_model = levels()
    all_lintel = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_StructuralFraming).ToElements()
    dict_lintel = {(i.get_Parameter(BuiltInParameter.SYMBOL_FAMILY_NAME_PARAM).AsString()): i for i in all_lintel}
    sort_dict_lintel = OrderedDict(sorted(dict_lintel.items()))
    dict_lintel_type = {(i.get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM).AsString()): i for i in all_lintel}
    sort_dict_lintel_type = OrderedDict(sorted(dict_lintel_type.items()))


    form = ModalForm('Fill_Data.xaml')
    # >>>>>>>>>> SELECT Wall
    with forms.WarningBar(title="เลือกผนัง: (ออกกด Esc)", 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_elev = levels_wall[1]
            Match_Bottom_elev = levels_wall[0]
            # print("Match_Top_elev = {}".format(Match_Top_elev))
            # print("Match_Bottom_elev = {}".format(Match_Bottom_elev))
            base_Constraint = Match_wall.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT)
            value1 = checkParameter(base_Constraint).upper()
            base_Offset = Match_wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble()
            top_Constraint = Match_wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE)
            top_Offset = Match_wall.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).AsDouble()
            unconnected_height = Match_wall.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).AsDouble()

            if top_Constraint.AsElementId() == ElementId.InvalidElementId:
                value2 = -1
            else:
                value2 = checkParameter(top_Constraint).strip("Up to level:").upper()
            for i in levels_model:
                if value1 == i[0]:
                    base_constraint_level = i[2]
                    base_constraint_ele = i[1] + base_Offset
                if value2 == -1:
                    top_constraint_ele = i[1] + unconnected_height
                elif value2 == i[0]:
                    top_constraint_ele = i[1] + top_Offset

            n = 0
            for i in levels_model:
                n = n + 1
                if Match_Bottom_elev < i[1] and i == levels_model[0]:
                    Bottom_Level_name = i[0]
                    Bottom_Level_value = i[1]
                    Bottom_Level = i[2]
                    nb = n
                elif Match_Bottom_elev >= i[1]:
                    Bottom_Level_name = i[0]
                    Bottom_Level_value = i[1]
                    Bottom_Level = i[2]
                    nb = n
                if Match_Top_elev < i[1] and i == levels_model[0]:
                    Top_Level_name = i[0]
                    Top_Level_value = i[1]
                    Top_Level = i[2]
                    nt = n
                elif Match_Top_elev >= i[1]:
                    Top_Level_name = i[0]
                    Top_Level_value = i[1]
                    Top_Level = i[2]
                    nt = n

            min_level = min([v[1] for v in levels_model])

            if top_constraint_ele > base_constraint_ele:
                if base_Offset < 0:
                    set_bottom_level = base_constraint_level
                else:
                    set_bottom_level = Bottom_Level
            else:
                set_bottom_level = Bottom_Level
            for i in levels_model:
                if set_bottom_level == i[2]:
                    set_bottom_ele = i[1]
            h_bottomLevel_to_bottomWall = Match_Bottom_elev - set_bottom_ele
            lentel_bottom_level = set_bottom_ele + height_lintel
            h_topLevel_to_bottomWall = Match_Top_elev - lentel_bottom_level

            # ตรวจสอบหลังผนังต้องไม่สูงกว่าระดับ Level อ้างอิง
            if Match_Top_elev < lentel_bottom_level:
                height_lentel_adj = -(Match_Top_elev - Match_Bottom_elev - height_lintel)
            else:
                # print("Match_Top_elev > window_bottom_level")
                height_lentel_adj = (Match_Bottom_elev - set_bottom_ele + height_lintel)

            # ดึงเส้นแกนของผนัง
            wall_location = Match_wall.Location
            wall_curve = wall_location.Curve

            # if isinstance(wall_curve, Line):
            #     start_point = wall_curve.GetEndPoint(0)  # จุดเริ่มต้น
            #     end_point = wall_curve.GetEndPoint(1)  # จุดปลาย
            #     location_curve = Line.CreateBound(start_point, end_point)
            #
            #
            # elif isinstance(wall_curve, Arc):
            #     start_point = wall_curve.GetEndPoint(0)  # จุดเริ่มต้น
            #     end_point = wall_curve.GetEndPoint(1)  # จุดปลาย
            #     center = wall_curve.Center  # จุดศูนย์กลางของ Arc
            #     radius = wall_curve.Radius  # รัศมี
            #     # location_curve =



            # start_point = wall_curve.GetEndPoint(0)
            # end_point = wall_curve.GetEndPoint(1)
            # print("start_point = {}".format(start_point))
            # print("end_point = {}".format(end_point))

            # กำหนดระดับของคาน (ระดับเดียวกับผนัง)
            wall_level_id = Match_wall.LevelId
            wall_level = doc.GetElement(wall_level_id)
            # print("wall_level = {}".format(wall_level))
            strType_wall = Match_wall.get_Parameter(BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT).AsInteger()
            # print("strType_wall = {}".format(strType_wall))

            with Transaction(doc, "Create Beam") as t:
                try:
                    t.Start()
                    if not lintel_selected.IsActive:
                        lintel_selected.Activate()
                        doc.Regenerate()
                    if not lintelSize_selected.IsActive:
                        lintelSize_selected.Activate()
                        doc.Regenerate()
                    beam = doc.Create.NewFamilyInstance(
                        wall_curve,  # เส้นกำหนดตำแหน่งของคาน
                        lintelSize_selected,  # FamilySymbol ของคาน
                        # lintel_selected,  # FamilySymbol ของคาน
                        wall_level,  # ระดับของคาน
                        StructuralType.Beam  # กำหนดเป็นประเภท Beam
                    )
                    beam.get_Parameter(BuiltInParameter.Y_JUSTIFICATION).Set(2)
                    beam.get_Parameter(BuiltInParameter.Y_OFFSET_VALUE).Set(0)
                    beam.get_Parameter(BuiltInParameter.Z_JUSTIFICATION).Set(3)
                    beam.get_Parameter(BuiltInParameter.Z_OFFSET_VALUE).Set(height_lentel_adj)
                    # beam.get_Parameter(BuiltInParameter.Z_OFFSET_VALUE).Set(height_lintel)

                    strType_beam = beam.StructuralMaterialType
                    if strType_beam == StructuralMaterialType.Concrete:
                        # print("strType = {}".format(strType))
                        if strType_wall == 0:

                            # Join คานกับผนัง
                            if JoinGeometryUtils.AreElementsJoined(doc, Match_wall, beam):
                                TaskDialog.Show("Info", "Wall and Beam are already joined.")
                            else:
                                JoinGeometryUtils.JoinGeometry(doc, Match_wall, beam)
                                # TaskDialog.Show("Success", "Beam created and joined with wall successfully.")
                    # else:
                    #     print("strType = {}".format(strType))
            

                        t.Commit()
                except Exception as e:
                    t.RollBack()
                    TaskDialog.Show("Error", "An error occurred: {0}".format(str(e)))
                    sys.exit()








    
