import clr
import math
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

items = UnwrapElement(IN[0])

def GetCurvePoints(curve):
	return curve.GetEndPoint(0).ToPoint(), curve.GetEndPoint(1).ToPoint()

def GetLocation(item):
	# returns the following properties:
	# [0] point
	# [1] curve
	# [2] is point?
	# [3] is curve?
	# [4] has location?
	# [5] rotation angle
	# [6] has rotation?
	# [7] is curve loop?
	# [8] curve loop
	# default values
	point = None
	curveendpoints = None
	curve = None
	ispoint = False
	iscurve = False
	haslocation = False
	rotationangle = None
	hasrotation = False
	iscurveloop = False
	curveloop = None
	# template for return statements:
	# return point, curveendpoints, curve, ispoint, iscurve, haslocation, rotationangle, hasrotation, iscurveloop, curveloop
	# FabricationConfiguration objects will produce an error further down if we don't exit here
	if hasattr(item, "AncillaryExists"):
		return point, curveendpoints, curve, ispoint, iscurve, haslocation, rotationangle, hasrotation, iscurveloop, curveloop
	# points and text notes
	if hasattr(item, "Coord"): 
		return item.Coord.ToPoint(), curveendpoints, curve, True, iscurve, True, rotationangle, hasrotation, iscurveloop, curveloop
	# base points and reference points
	if hasattr(item, "Position"): 
		return item.Position.ToPoint(), curveendpoints, curve, True, iscurve, True, rotationangle, hasrotation, iscurveloop, curveloop
	# independent tags
	if hasattr(item, "TagHeadPosition") and hasattr(item, "IsMaterialTag"): 
		return item.TagHeadPosition.ToPoint(), curveendpoints, curve, True, iscurve, True, rotationangle, hasrotation, iscurveloop, curveloop
	# views
	if hasattr(item, "ViewType") and hasattr(item, "Origin"): 
		ori = item.Origin
		if ori: return ori.ToPoint(), curveendpoints, curve, True, iscurve, True, rotationangle, hasrotation, iscurveloop, curveloop
		else: return point, curveendpoints, curve, ispoint, iscurve, haslocation, rotationangle, hasrotation, iscurveloop, curveloop
	# stair runs and landings
	if hasattr(item, "GetFootprintBoundary"):
		footprint = [x.ToProtoType() for x in item.GetFootprintBoundary()]
		return point, curveendpoints, curve, ispoint, iscurve, True, rotationangle, hasrotation, True, footprint
	# grids, dimensions and boundary segments
	elif hasattr(item, "Curve"): 
		tempcurve = item.Curve
		if not tempcurve.IsBound: tempcurve.MakeBound(0,1) 
		return point, GetCurvePoints(tempcurve), tempcurve.ToProtoType(), ispoint, True, True, rotationangle, hasrotation, iscurveloop, curveloop 
	# curtain grid lines
	elif hasattr(item, "FullCurve"): 
		tempcurve = item.FullCurve
		if not tempcurve.IsBound: tempcurve.MakeBound(0,1) 
		return point, GetCurvePoints(tempcurve), tempcurve.ToProtoType(), ispoint, True, True, rotationangle, hasrotation, iscurveloop, curveloop
	# curves
	elif hasattr(item, "GetEndpoint"): 
		tempcurve = item
		if not tempcurve.IsBound: tempcurve.MakeBound(0,1) 
		return point, GetCurvePoints(tempcurve), tempcurve.ToProtoType(), ispoint, True, True, rotationangle, hasrotation, iscurveloop, curveloop
	# railings and top rails
	elif hasattr(item, "GetPath"):
		railpath = []
		for x in item.GetPath():
			try: railpath.append(x.ToProtoType())
			except: pass
		# paths with multiple segments
		if len(railpath) > 1: return point, curveendpoints, curve, ispoint, iscurve, True, rotationangle, hasrotation, True, railpath
		# paths with a single segment
		elif len(railpath) == 1: return point, GetCurvePoints(railpath[0].ToRevitType()), railpath[0], ispoint, True, True, rotationangle, hasrotation, iscurveloop, curveloop
		# paths without legible segments
		else: return point, curveendpoints, curve, ispoint, iscurve, haslocation, rotationangle, hasrotation, iscurveloop, curveloop
	# openings
	elif hasattr(item, "BoundaryCurves"):
		# rectangular openings
		if item.IsRectBoundary:
			zVals = [x.Z for x in item.BoundaryRect]
			p = []
			for o in item.BoundaryRect:
				for z in zVals: p.append(XYZ(o.X, o.Y, z).ToPoint())
			rectloop = Rectangle.ByCornerPoints(p[0], p[1], p[3], p[2]).Explode()
			return point, curveendpoints, curve, ispoint, iscurve, True, rotationangle, hasrotation, True, rectloop
		# none-rectangular openings
		else: 
			openingloop = [x.ToProtoType() for x in item.BoundaryCurves]
			return point, curveendpoints, curve, ispoint, iscurve, True, rotationangle, hasrotation, True, openingloop
	# extrusion roofs
	elif hasattr(item, "GetProfile"):
		sketchloop = [x.GeometryCurve.ToProtoType() for x in item.GetProfile()]
		return point, curveendpoints, curve, ispoint, iscurve, True, rotationangle, hasrotation, True, sketchloop
	# newer sketch-based elements (except walls)
	elif hasattr(item, "SketchId") and not hasattr(item, "WallType"):
		sketch = item.Document.GetElement(item.SketchId)
		if sketch:
			sketchloop = []
			for loop in sketch.Profile:
				sketchloop.append([x.ToProtoType() for x in loop])
			return point, curveendpoints, curve, ispoint, iscurve, True, rotationangle, hasrotation, True, sketchloop
		else: return point, curveendpoints, curve, ispoint, iscurve, haslocation, rotationangle, hasrotation, iscurveloop, curveloop
	# other elements
	elif hasattr(item, "Location"):
		loc = item.Location
		if loc:
			# line-based elements (e.g. walls)
			if loc.ToString() == 'Autodesk.Revit.DB.LocationCurve':
				tempcurve = loc.Curve
				if not tempcurve.IsBound: tempcurve.MakeBound(0,1) 
				try: return point, GetCurvePoints(tempcurve), tempcurve.ToProtoType(), ispoint, True, True, rotationangle, hasrotation, iscurveloop, curveloop
				# return super short curves as startpoint instead
				except: return GetCurvePoints(loc.Curve)[0], curveendpoints, curve, True, iscurve, True, rotationangle, hasrotation, iscurveloop, curveloop
			# point-based elements (e.g. most loadable families)
			elif loc.ToString() == 'Autodesk.Revit.DB.LocationPoint':
				try:
					if hasattr(loc, "Rotation"):
						rotationangle = math.degrees(loc.Rotation)
						hasrotation = True
				except: pass
				return loc.Point.ToPoint(), curveendpoints, curve, True, iscurve, True, rotationangle, hasrotation, iscurveloop, curveloop
			# some elements have a location property but don't return curves or points
			else:
				# earlier sketch-based elements (e.g. floor slabs)
				try:
					sketchloop = []
					for ref in HostObjectUtils.GetTopFaces(item):
						geomref = item.GetGeometryObjectFromReference(ref)
						if geomref: 
							boundaryloops = geomref.GetEdgesAsCurveLoops()
							for loop in boundaryloops:
								sketchloop.append([x.ToProtoType() for x in loop])
					return point, curveendpoints, curve, ispoint, iscurve, True, rotationangle, hasrotation, True, sketchloop
				# other elements we can't process
				# return defaults in these cases
				except:
					return point, curveendpoints, curve, ispoint, iscurve, haslocation, rotationangle, hasrotation, iscurveloop, curveloop
		# some elements (e.g.groups, curtain panels etc.)  have a location property which only returns a NoneType
		# return defaults in these cases
		else: return point, curveendpoints, curve, ispoint, iscurve, haslocation, rotationangle, hasrotation, iscurveloop, curveloop
	# in all other cases return defaults
	else: return point, curveendpoints, curve, ispoint, iscurve, haslocation, rotationangle, hasrotation, iscurveloop, curveloop

if isinstance(IN[0], list):
	locations = [GetLocation(x) for x in items]
	# Transpose and remove NoneTypes
	OUT = []
	for prop in map(list, zip(*locations)):
		OUT.append(filter(lambda x: x!=None, prop))
else: OUT = GetLocation(items)