"Fill in data concrete Beam in Model \n\n\n Updated : 01-05-2024 \n\n Shared by : TUMCIVIL"
__author__ = 'TUMCIVIL'
__version__ = '1.0.0'
__title__ = ' Add Data Beam'
# for timing -------------------------------------------------------------------
import pyrevit.coreutils as cor
from pyrevit.coreutils import Timer
timer = Timer()
# ------------------------------------------------------------------------------
import sys
import csv
import codecs
import os.path as op
from collections import defaultdict

from pyrevit import PyRevitException
from pyrevit import forms
from pyrevit import coreutils
from pyrevit import revit, DB, HOST_APP
from pyrevit import script
import Autodesk
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *
import Autodesk.Revit.DB as DB
from Autodesk.Revit.DB.Structure import *
import re

doc = __revit__.ActiveUIDocument.Document
uidoc = __revit__.ActiveUIDocument
logger = script.get_logger()

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

def read_csv_typed_data(csv_file):
    """Read Revit property data from the given CSV file."""
    # open file
    with codecs.open(csv_file, "rb", encoding="utf-8") as csvfile:
        # read lines
        csv_lines = list(csv.reader(csvfile, delimiter=",", quotechar='"'))
        # print("csv_lines = {}".format(csv_lines))
        # grab the first line, extract field names
        # if field definition include the type, grab the associated
        # DB.ParameterType as well
        # https://www.apidocs.co/apps/revit/2019/f38d847e-207f-b59a-3bd6-ebea80d5be63.htm
        # https://support.spatialkey.com/providing-data-types-in-csv-headers/
        field_defs = []
        for field_def in csv_lines[0]:
            parts = field_def.split("|")
            parts_count = len(parts)
            if HOST_APP.is_newer_than(2022, or_equal=True):
                if parts_count == 1:
                    if parts[0]:
                        field_defs.append((parts[0], DB.SpecTypeId.String))
                    # print("parts 1")
                elif parts_count == 2:
                    if hasattr(DB.SpecTypeId, parts[1]):
                        field_defs.append(
                            (
                                parts[0],
                                getattr(DB.SpecTypeId, parts[1]),
                            )
                        )
                    # print("parts 2")
            else:
                if parts_count == 1:
                    if parts[0]:
                        field_defs.append((parts[0], DB.ParameterType.Text))
                elif parts_count == 2:
                    field_defs.append(
                        (
                            parts[0],
                            coreutils.get_enum_value(
                                DB.ParameterType, parts[1]
                            ),
                        )
                    )
    return (field_defs, csv_lines[1:])

def remove_none_digit(s):
    t = ""
    for c in s:
        if c.isdigit() or c == "x" or c == "X":
            t += c
    return t

def digSoil(eleTop):
    if eleTop <= 0:
        if eleTop*-1 <= 1000:
            digSoil =  500
        elif eleTop*-1 > 1000 and eleTop*-1 <= 2000:
            digSoil =  750
        elif eleTop*-1 > 2000 and eleTop*-1 <= 3000:
            digSoil =  1000
        elif eleTop*-1 > 3000 and eleTop*-1 <= 4000:
            digSoil =  1500
        elif eleTop*-1 > 4000 and eleTop*-1 <= 5000:
            digSoil =  2000
        elif eleTop*-1 > 5000:
            digSoil =  3000
    else :
        digSoil =  500
    # print("digSoil = {}".format(digSoil))
    return digSoil

def beams():
    beams = DB.FilteredElementCollector(doc).OfCategory(DB.BuiltInCategory.OST_StructuralFraming) \
        .WhereElementIsNotElementType() \
        .ToElements()

    # print("Data = {}".format(param_data))
    out = []
    for e in beams:
        p2 = []
        for j in e.Parameters:
            if j.IsShared and j.Definition.Name == "Name Tags":
                nameTags = e.get_Parameter(j.GUID).AsString()
        typeName = e.get_Parameter(BuiltInParameter.ELEM_TYPE_PARAM)
        value = checkParameter(typeName)
        value2 = remove_none_digit(value)
        # value = value2.upper().replace(" ","")
        # print("value2 = {}".format(value2))
        try:
            checkGroundBeam = e.LookupParameter("Ground Beam (or not)").AsInteger()
        except:
            checkGroundBeam = 0

        if checkGroundBeam == 1:

            eleTop = e.get_Parameter(BuiltInParameter.STRUCTURAL_ELEVATION_AT_TOP).AsDouble()
            eleTopConvert = round(UnitUtils.ConvertFromInternalUnits(
                e.get_Parameter(BuiltInParameter.STRUCTURAL_ELEVATION_AT_TOP).AsDouble(),UnitTypeId.Millimeters),0)
            if eleTopConvert >= 0:
                eleTopCombine = "EL.+"+str(int(eleTopConvert))
            elif eleTopConvert < 0:
                eleTopCombine = "EL."+str(int(eleTopConvert))
            # print("eleTopCombine = {}".format(eleTopCombine))
            DigSoil = UnitUtils.ConvertToInternalUnits(digSoil(eleTopConvert),UnitTypeId.Millimeters)
            # print("DigSoil = {}".format(DigSoil))
            # print("value = {}".format(value))
            # w = [v for v in param_data if v[0] == nameTags]
            w = [v for v in param_data if v[0] == nameTags and remove_none_digit(v[1].lower()) == value2.lower()]
            # w = [v for v in param_data if v[0] == nameTags and v[1].lower().replace(" ","") == value.lower().replace(" ","")]
            # print("w = {}".format(w))
            # print("len(w) = {}".format(len(w)))

            if len(w)>1:
                p2.append(id)
                p2.append(nameTags)
                p2.append(value2.lower())

                out2.append(p2)
            elif len(w) == 1:
                for i in w:
                    q = UnitUtils.ConvertToInternalUnits(float(i[6]),UnitTypeId.Millimeters)
                    q2 = UnitUtils.ConvertToInternalUnits(float(i[7]),UnitTypeId.Millimeters)
                    q3 = UnitUtils.ConvertToInternalUnits(float(i[8]),UnitTypeId.Millimeters)
                    q4 = UnitUtils.ConvertToInternalUnits(float(i[9]),UnitTypeId.Millimeters)
                    q5 = remove_none_digit(i[1].lower())+" mm."
                    q6 = i[3]
                    q7 = i[2]
                    q8 = UnitUtils.ConvertToInternalUnits(int(i[4]),UnitTypeId.Millimeters)
                    q9 = i[5]

                    t = Transaction(doc, 'change parameter')
                    t.Start()
                    try:
                        e.LookupParameter("Elevation at Top Edge").Set(eleTop)
                        e.LookupParameter("Dig Soil from edge").Set(DigSoil)
                        e.LookupParameter("Lean Thickness").Set(q)
                        e.LookupParameter("Sand Thickness").Set(q2)
                        e.LookupParameter("Offset Lean").Set(q3)
                        e.LookupParameter("Offset Sand").Set(q4)
                        e.LookupParameter("Location").Set(eleTopCombine)
                        e.LookupParameter("Name Beam").Set(nameTags)
                        e.LookupParameter("Size").Set(q5)
                        e.LookupParameter("Group").Set(q6)
                        e.LookupParameter("Strength Concrete").Set(q7)
                        e.LookupParameter("3-HR Fireproofing (or not)").Set(q8)
                        e.LookupParameter("3-HR Fireproofing Name").Set(q9)


                    except:
                        # TaskDialog.Show('error', 'error message')
                        pass
                    t.Commit()
                    # print("DONE")
                # else:
                    # print("NO DONE")
        else:
            # for j in e.Parameters:
            #     if j.IsShared and j.Definition.Name == "Name Tags":
            #         nameTags = e.get_Parameter(j.GUID).AsString()
            eleTop = e.get_Parameter(BuiltInParameter.STRUCTURAL_ELEVATION_AT_TOP).AsDouble()
            eleTopConvert = round(UnitUtils.ConvertFromInternalUnits(
                e.get_Parameter(BuiltInParameter.STRUCTURAL_ELEVATION_AT_TOP).AsDouble(),UnitTypeId.Millimeters),0)
            if eleTopConvert >= 0:
                eleTopCombine = "EL.+"+str(int(eleTopConvert))
            elif eleTopConvert < 0:
                eleTopCombine = "EL."+str(int(eleTopConvert))
            # print("eleTopCombine = {}".format(eleTopCombine))
            w = [v for v in param_data if v[0] == nameTags and remove_none_digit(v[1].lower()) == value2.lower()]
            # w = [v for v in param_data if v[0] == nameTags and v[1].lower().replace(" ","") == value.lower().replace(" ","")]
            # print("w = {}".format(w))
            if len(w)>1:
                p2.append(id)
                p2.append(nameTags)
                p2.append(value2.lower())

                out2.append(p2)
            elif len(w) == 1:
                for i in w:
                    q5 = remove_none_digit(i[1].lower())+" mm."
                    q6 = i[3]
                    q7 = i[2]
                    q8 = UnitUtils.ConvertToInternalUnits(int(i[4]),UnitTypeId.Millimeters)
                    q9 = i[5]

                    t = Transaction(doc, 'change parameter')
                    t.Start()
                    try:
                        e.LookupParameter("Location").Set(eleTopCombine)
                        e.LookupParameter("Name Beam").Set(nameTags)
                        e.LookupParameter("Size").Set(q5)
                        e.LookupParameter("Group").Set(q6)
                        e.LookupParameter("Strength Concrete").Set(q7)
                        e.LookupParameter("3-HR Fireproofing (or not)").Set(q8)
                        e.LookupParameter("3-HR Fireproofing Name").Set(q9)

                    except:
                        # TaskDialog.Show('error', 'error message')
                        pass
                    t.Commit()

if __name__ == "__main__":
    # ask user for source CSV file
    source_file = forms.pick_file(file_ext="csv")
    # read the csv data
    param_defs, param_data = read_csv_typed_data(source_file)
    # print("Data = {}".format(param_data))
    out2=[]
    beams()
    # print("out2 = {}".format(out2))
    sort_out2 = (sorted(set([e[1] for e in out2])))
    # print("sort_out2 = {}".format(sort_out2))
    if len(sort_out2)>0:
    # if len(out2)>0:
        print("====" * 15)
        print("Name beams in Excel > 1")
        for i in sort_out2:
            print("Name beams = {}".format(i))

# for timing -------------------------------------------------------------------
print("====" * 15)
print("ADD DATA BEAMS COMPLETELY !")
print("====" * 15)
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("====" * 15)
# ------------------------------------------------------------------------------