"Fill in data concrete Walls in Model \n\n\n Updated : 01-05-2024 \n\n Shared by : TUMCIVIL"
__author__ = 'TUMCIVIL'
__version__ = '1.0.0'
__title__ = ' Add Data Walls'
# 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))
                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
    # print("digSoil = {}".format(digSoil))
    return digSoil
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()
        p3.append(name)
        p3.append(eleLev)
        # print("levels = {} , {}".format(name,eleLev))

        out3.append(p3)
    # for i in out3:
    # print("out3 = {}".format(out3))

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


def walls():
    walls = DB.FilteredElementCollector(doc).OfCategory(DB.BuiltInCategory.OST_Walls) \
        .WhereElementIsNotElementType() \
        .ToElements()

    # print("Data = {}".format(param_data))
    out = []
    for e in walls:
        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 = remove_none_digit(checkParameter(typeName))
        # print("typeName = {} ".format(value))
        baseLev = e.get_Parameter(BuiltInParameter.WALL_BASE_CONSTRAINT)
        value1 = checkParameter(baseLev)
        baseOff = e.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).AsDouble()
        # print("baseLev = {} ,baseOff = {}".format(value1,baseOff))
        eleBase = [v[1]+baseOff for v in out3 if v[0].upper() == value1.strip("Up to level:").upper()]
        # print("eleBase = {}".format(eleBase))
        for i in eleBase:
            eleBaseConvert = UnitUtils.ConvertFromInternalUnits(i,UnitTypeId.Millimeters)
        # print("eleBaseConvert = {}".format(eleBaseConvert)) 
        if eleBaseConvert >= 0:
            eleBaseCombine = "+"+str(round(eleBaseConvert,0)).replace(".0","")
        elif eleBaseConvert < 0:
            eleBaseCombine = str(round(eleBaseConvert,0)).replace(".0","")
        # print("eleBaseCombine = {}".format(eleBaseCombine))

        topLev = e.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE)
        value2 = checkParameter(topLev)
        if value2 == "Unconnected":
            value2 = value1
            unconHeight = e.get_Parameter(BuiltInParameter.WALL_USER_HEIGHT_PARAM).AsDouble()
            eleTop = [v[1]+baseOff+unconHeight for v in out3 if v[0].upper() == value2.strip("Up to level:").upper()]
            for i in eleTop:
                eleTopConvert = UnitUtils.ConvertFromInternalUnits(i,UnitTypeId.Millimeters)
            # print("eleTopConvert = {}".format(eleTopConvert)) 
            if eleTopConvert >= 0:
                eleTopCombine = "+"+str(round(eleTopConvert,0)).replace(".0","")
            elif eleTopConvert < 0:
                eleTopCombine = str(round(eleTopConvert,0)).replace(".0","")
        else:
            topOff = e.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).AsDouble()
            eleTop = [v[1]+topOff for v in out3 if v[0].upper() == value2.strip("Up to level:").upper()]

            for i in eleTop:
                eleTopConvert = UnitUtils.ConvertFromInternalUnits(i,UnitTypeId.Millimeters)
            # print("eleTopConvert = {}".format(eleTopConvert)) 
            if eleTopConvert >= 0:
                eleTopCombine = "+"+str(round(eleTopConvert,0)).replace(".0","")
            elif eleTopConvert < 0:
                eleTopCombine = str(round(eleTopConvert,0)).replace(".0","")


        # topOff = e.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).AsDouble()
        # # print("topLevs = {} ,topOff = {}".format(value2,topOff))
        # eleTop = [v[1]+topOff for v in out3 if v[0].upper() == value2.strip("Up to level:").upper()]
        # # print("eleTop = {}".format(eleTop))
        # for i in eleTop:
        #     eleTopConvert = UnitUtils.ConvertFromInternalUnits(i,UnitTypeId.Millimeters)
        # # print("eleTopConvert = {}".format(eleTopConvert)) 
        # if eleTopConvert >= 0:
        #     eleTopCombine = "EL.+"+str(round(eleTopConvert,0)).replace(".0","")
        # elif eleTopConvert < 0:
        #     eleTopCombine = "EL."+str(round(eleTopConvert,0)).replace(".0","")

        loCombine = "[(EL."+eleBaseCombine+")"+"-(EL."+eleTopCombine+")]"
        # print("loCombine = {}".format(loCombine))

        w = [v for v in param_data if v[0] == nameTags and remove_none_digit(v[1]) == value]
        # print("w = {}".format(w))
        if len(w)>1:
            p2.append(id)
            p2.append(nameTags)
            out2.append(p2)
        elif len(w) == 1:
            for i in w:
                q5 = i[1]
                q6 = i[3]
                q7 = i[2]
                q8 = eleBaseCombine
                q9 = eleTopCombine

                t = Transaction(doc, 'change parameter')
                t.Start()
                try:
                    e.LookupParameter("Location").Set(loCombine)
                    e.LookupParameter("Name Core Wall").Set(nameTags)
                    e.LookupParameter("Size").Set(q5)
                    e.LookupParameter("Group").Set(q6)
                    e.LookupParameter("Strength Concrete").Set(q7)
                    e.LookupParameter("Bottom of Wall").Set(q8)
                    e.LookupParameter("Top of Wall").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 = []
    out3 = []
    levels()
    walls()
    sort_out2 = (sorted(set([e[1] for e in out2])))
    if len(sort_out2)>0:
        print("====" * 15)
        print("Name Walls in Excel > 1")
        for i in sort_out2:
            print("Name Walls = {}".format(i))

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