# -*- 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.ไม่สามารถใส่หน้าต่างในผนังโค้งได้
_________________________________________________________________
วิธีการใช้ :
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 revit, forms
from Autodesk.Revit.DB import XYZ
import Autodesk.Revit.DB.Structure
from Autodesk.Revit.DB.Structure import *
from Autodesk.Revit.DB import Element
from Autodesk.Revit.DB import Document

# >>>>>>>>>> .NET IMPORTS
import clr
# from rpw.db import wall

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_window(sort_dict_window, self.cmbWindow)

        self.ShowDialog()

    def combobox_add_window(self, window_type, text):
        for i, j in window_type.items():
            item = ComboBoxItem()
            item.Content = i
            text.Items.Add(item)
            # if j == cover_Other_Face_default:
            #     item.IsSelected = True

    def get_selected_window(self, text):
        """Function to get selected item from self.UI_text_type."""
        for item in text.Items:
            if item.IsSelected:
                try:
                    window_type = sort_dict_window[item.Content]
                except:
                    window_type = None
                return window_type
    def get_selected_windowSize(self, text):
        """Function to get selected item from self.UI_text_type."""
        for item in text.Items:
            if item.IsSelected:
                try:
                    window_type = sort_dict_window_type[item.Content]
                except:
                    window_type = None
                return window_type

    def cmbWindow_SelectionChanged(self, sender, e):
        self.cmbWindowSize.Items.Clear()
        global window_selected
        global window_family_name
        window_selected = self.get_selected_window(self.cmbWindow)
        try:
            p1=[]
            for i,j in sort_dict_window.items():
                if j == window_selected:
                    door_family_name = i
                    dict_window_type = {(v.get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM).AsString()): v for v in
                                      all_window if v.get_Parameter(BuiltInParameter.SYMBOL_FAMILY_NAME_PARAM).AsString()==i}
                    global sort_dict_window_type
                    sort_dict_window_type = OrderedDict(sorted(dict_window_type.items()))


                    self.combobox_add_window(sort_dict_window_type, self.cmbWindowSize)

        except:
            pass


    def cmbWindowSize_SelectionChanged(self, sender, e):
        global windowSize_selected
        # global door_type_name
        windowSize_selected = self.get_selected_windowSize(self.cmbWindowSize)
        pass

    def fillWindow(self, sender, e):
        if self.cmbWindow.SelectedValue !=  None  and  self.cmbWindowSize.SelectedValue != None:
            global height_window
            height_window = convert_internal_units(float(self.tbHeight.Text), True, "mm")

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


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


if __name__ == '__main__':
    out = []
    levels_model = levels()
    # print("levels_model = {}".format(levels_model))
    all_window = FilteredElementCollector(doc).OfClass(FamilySymbol).OfCategory(BuiltInCategory.OST_Windows).ToElements()
    dict_window = {(i.get_Parameter(BuiltInParameter.SYMBOL_FAMILY_NAME_PARAM).AsString()): i for i in all_window}
    sort_dict_window = OrderedDict(sorted(dict_window.items()))
    dict_window_type = {(i.get_Parameter(BuiltInParameter.SYMBOL_NAME_PARAM).AsString()): i for i in all_window}
    sort_dict_window_type = OrderedDict(sorted(dict_window_type.items()))



    form = ModalForm('Fill_Data_Window.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


            # print("base_constraint_level = {}".format(base_constraint_level))
            # print("base_constraint_ele = {}".format(base_constraint_ele))
            # print("top_constraint_ele = {}".format(top_constraint_ele))

            # print("value1 = {}".format(value1))
            # print("value2 = {}".format(value2))
            # print("base_Offset = {}".format(base_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

            # print("Bottom_Level_name = {}".format(Bottom_Level_name))
            # print("Bottom_Level_value = {}".format(Bottom_Level_value))
            # print("Top_Level_name = {}".format(Top_Level_name))
            # print("Top_Level_value = {}".format(Top_Level_value))
            # print("nb = {}".format(nb))
            # print("nt = {}".format(nt))

            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
            window_bottom_level = set_bottom_ele+height_window
            h_topLevel_to_bottomWall = Match_Top_elev - window_bottom_level
            # print("h_bottomLevel_to_bottomWall = {}".format(h_bottomLevel_to_bottomWall))
            # print("h_topLevel_to_bottomWall = {}".format(h_topLevel_to_bottomWall))
            # print("set_bottom_level = {}".format(set_bottom_level))
            # print("window_bottom_level = {}".format(window_bottom_level))

            # ตรวจสอบหลังผนังต้องไม่สูงกว่าระดับ Level อ้างอิง
            if Match_Top_elev < window_bottom_level:
                # diff = (Bottom_Level_value + height_window) - Match_Top_elev
                # height_window_adj = Match_Bottom_elev + diff
                height_window_adj = -(Match_Top_elev-Match_Bottom_elev-height_window)
                # print("diff = {}".format(diff))
                # print("Match_Top_elev <= window_bottom_level")
                # forms.alert("ให้ใส่ค่าความสูงจากพื้นน้อยกว่า {}.".format(diff), exitscript=False, title="แก้ไขค่าใหม่.")
                # break
            else:
                # print("Match_Top_elev > window_bottom_level")
                height_window_adj = (Match_Bottom_elev-set_bottom_ele+height_window)
                # height_window_adj = height_window

            # print("height_window_adj = {}".format(height_window_adj))

                    # for i in levels_model:
            #     if Match_Bottom_elev < i[1] and i == levels_model[0] :
            #         Bottom_Level_name =i[0]
            #         Bottom_Level =i[2]
            #     elif Match_Bottom_elev >= i[1] :
            #         Bottom_Level_name = i[0]
            #         Bottom_Level_value =i[1]
            #         Bottom_Level =i[2]
            # for i in levels_model:
            #     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]
            #     elif Match_Top_elev >= i[1] :
            #         Top_Level_name =i[0]
            #         Top_Level_value =i[1]
            #         Top_Level =i[2]



            # h_bottomLevel_to_bottomWall = Match_Bottom_elev-Bottom_Level_value
            # # print("h_bottomLevel_to_bottomWall = {}".format(h_bottomLevel_to_bottomWall))
            #
            #
            # min_level = min([v[1] for v in levels_model])
            # # print("min_level = {}".format(min_level))
            #
            # # ตรวจสอบหลังผนังต้องสูงกว่าระดับ Level ที่ต่ำสุด
            # if Match_Top_elev <= Bottom_Level_value:
            #     diff = (Bottom_Level_value+height_window)-Match_Top_elev
            #     height_window_adj = Match_Bottom_elev+diff
            #     # forms.alert("ให้ใส่ค่าความสูงจากพื้นน้อยกว่า {}.".format(diff), exitscript=False, title="แก้ไขค่าใหม่.")
            #     # break
            # else:
            #     height_window_adj = height_window
            #     pass



            # ดึงระดับของผนังเพื่อใช้กับประตู
            wall_id = Match_wall.Id
            host_wall = doc.GetElement(wall_id)
            # print("host_wall = {}".format(host_wall))

            # กำหนดตำแหน่งของประตูในผนัง
            wall_location = Match_wall.Location
            if not isinstance(wall_location, LocationCurve):
                TaskDialog.Show("Error", "Wall does not have a valid location curve.")
                raise ValueError("Wall location curve is not valid.")

            # หาจุดกึ่งกลางของผนัง
            wall_curve = wall_location.Curve
            start_point = wall_curve.GetEndPoint(0)
            end_point = wall_curve.GetEndPoint(1)
            midpoint = wall_curve.Evaluate(0.5, True)  # คำนวณจุดกลางของเส้น Curve


            with Transaction(doc, "Create window") as t:
                try:
                    t.Start()
                    if not windowSize_selected.IsActive:
                        windowSize_selected.Activate()
                        doc.Regenerate()
                    if not windowSize_selected or not isinstance(windowSize_selected, FamilySymbol):
                        raise ValueError("Invalid window FamilySymbol selected.")


                    window = doc.Create.NewFamilyInstance(
                        midpoint,  # ตำแหน่งการวางหน้าต่าง
                        windowSize_selected,  # FamilySymbol ของหน้าต่าง
                        host_wall,  # ระดับของหน้าต่าง
                        StructuralType.NonStructural
                    )
                    # ตั้งค่าความสูงของเสา
                    window.get_Parameter(BuiltInParameter.FAMILY_LEVEL_PARAM).Set(set_bottom_level)
                    window.get_Parameter(BuiltInParameter.INSTANCE_SILL_HEIGHT_PARAM).Set(height_window_adj)

                    # # Join ประตูกับผนัง
                    # if not JoinGeometryUtils.AreElementsJoined(doc, host_wall, door):
                    #     JoinGeometryUtils.JoinGeometry(doc, host_wall, door)
                    #
                    # TaskDialog.Show("Success", "Door created and joined with wall successfully.")


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







    
