# -----------------------------------------------------------------------------
# Create Levels Above Level 2  -  Dynamo 3.x (CPython3 / PythonNet3)
#
# Adds "Level 3" at Level 2 + 10'-0" and "Level 4" at Level 3 + 10'-0",
# and creates a floor plan view for each (as Revit does when you draw a level).
#
# Safe to re-run: skips a level if one with the same name, or any level at the
# same elevation, already exists.
#
# HOW TO USE
#   Dynamo 3.x > Python Script node (CPython3 or PythonNet3) > paste > Run.
#   Ctrl+Z in Revit undoes the whole run.
# -----------------------------------------------------------------------------

import clr
clr.AddReference("RevitAPI")
clr.AddReference("RevitServices")

from Autodesk.Revit.DB import (
    Level, ViewPlan, ViewFamily, ViewFamilyType, FilteredElementCollector,
)
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument

# ---------------------------------------------------------------- settings ---
REFERENCE_LEVEL = "Level 2"
NEW_LEVELS = ["Level 3", "Level 4"]   # bottom -> top
SPACING = 10.0                        # feet between levels
CREATE_FLOOR_PLANS = True

TOL = 0.01

levels = list(FilteredElementCollector(doc).OfClass(Level))
by_name = {l.Name: l for l in levels}

if REFERENCE_LEVEL not in by_name:
    raise Exception("'{}' not found. Levels in project: {}".format(
        REFERENCE_LEVEL, ", ".join(sorted(by_name))))

plan_type = None
if CREATE_FLOOR_PLANS:
    for vft in FilteredElementCollector(doc).OfClass(ViewFamilyType):
        if vft.ViewFamily == ViewFamily.FloorPlan:
            plan_type = vft
            break

report = []
elevation = by_name[REFERENCE_LEVEL].Elevation

TransactionManager.Instance.EnsureInTransaction(doc)
try:
    for name in NEW_LEVELS:
        elevation += SPACING
        if name in by_name:
            report.append("Skipped {} - a level with that name already exists".format(name))
            continue
        clash = [l for l in levels if abs(l.Elevation - elevation) < TOL]
        if clash:
            report.append("Skipped {} - '{}' is already at that elevation".format(name, clash[0].Name))
            continue

        level = Level.Create(doc, elevation)
        level.Name = name
        levels.append(level)
        by_name[name] = level
        msg = "Created {} at {:.2f}'".format(name, elevation)

        if plan_type is not None:
            view = ViewPlan.Create(doc, plan_type.Id, level.Id)
            try:
                view.Name = name
            except Exception:
                pass  # name already taken by another view; keep Revit's default
            msg += " + floor plan '{}'".format(view.Name)
        report.append(msg)
finally:
    TransactionManager.Instance.TransactionTaskDone()

OUT = report
