"Fill in data concrete footing in Model \n\n\n Updated : 01-05-2024 \n\n Shared by : TUMCIVIL"
__author__ = 'TUMCIVIL'
__version__ = '1.0.0'
__title__ = ' Add Data Footing'
# 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)
            # added support for Revit 2022+ parameter types
            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))
                elif parts_count == 2:
                    if hasattr(DB.SpecTypeId, parts[1]):
                        field_defs.append(
                            (
                                parts[0],
                                getattr(DB.SpecTypeId, parts[1]),
                            )
                        )
            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 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
    return digSoil

def footing():
    foundations = DB.FilteredElementCollector(doc).OfCategory(DB.BuiltInCategory.OST_StructuralFoundation) \
        .WhereElementIsNotElementType() \
        .ToElements()

    out = []
    for e in foundations:
        p = []
        p2 = []
        id = e.Id
        name = e.Name
        family = e.get_Parameter(BuiltInParameter.ELEM_FAMILY_PARAM)
        value = checkParameter(family)
        if value != "Wall Foundation" and value != "Foundation Slab" and bool(re.match("Pile", name)) == False:
            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))
            DigSoil = UnitUtils.ConvertToInternalUnits(digSoil(eleTopConvert),UnitTypeId.Millimeters)
            w = [v for v in param_data if v[0] == nameTags]
            if len(w)>1:
                # TaskDialog.Show('error', 'Lean > 1 ;Please fix it ')
                p2.append(id)
                p2.append(nameTags)
                out2.append(p2)
            else:
                for i in param_data:
                    if i[0] == nameTags:
                        q = UnitUtils.ConvertToInternalUnits(float(i[4]),UnitTypeId.Millimeters)
                        q2 = UnitUtils.ConvertToInternalUnits(float(i[5]),UnitTypeId.Millimeters)
                        q3 = UnitUtils.ConvertToInternalUnits(float(i[6]),UnitTypeId.Millimeters)
                        q4 = UnitUtils.ConvertToInternalUnits(float(i[7]),UnitTypeId.Millimeters)
                        q5 = i[1]
                        q6 = i[2]
                        q7 = i[3]
                        q8 = UnitUtils.ConvertToInternalUnits(float(i[8]),UnitTypeId.Millimeters)
                        q9 = UnitUtils.ConvertToInternalUnits(float(i[9]),UnitTypeId.Millimeters)

                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 Footing").Set(nameTags)
                    e.LookupParameter("Name Pile").Set(q6)
                    e.LookupParameter("Size").Set(q5)
                    e.LookupParameter("Strength Concrete").Set(q7)
                    e.LookupParameter("Pile Length").Set(q8)
                    e.LookupParameter("Pile Cutoff").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=[]
    footing()
    sort_out2 = (sorted(set([e[1] for e in out2])))
    if len(sort_out2)>0:
        print("Name Footing in Excel > 1")
        print("====" * 20)
        for i in sort_out2:
            print("Name Footing = {}".format(i))

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