"""system calc utils.
1. get connectors where model_id='@model_id' and belong_type='Equipment' and mep_system_type='@system_name'
2. get path start with connector,end with triple ,cross,equipment,end
"""

from systemrelation import revit_const
from functools import cmp_to_key
import vg
from systemrelation import graph_model


def path2edge(elements):
	"""
	Convert path to GraphtEdge
	:param elements:
	:return:
	"""
	pass


def graph_arrange(graph):
	"""
	Combine Vertex that connect to virtul Vertex
	:param graph:
	:return:
	"""
	pass


def connector_sort(connector1, connector2):
	"""Use Define Sort rule"""
	dic = {revit_const.EQUIPMENT: 0, revit_const.COMPONENT: 1, revit_const.OTHER: 2, revit_const.PIPE: 3,
		   revit_const.DUCT: 4}
	x = dic[connector1.belong_type]
	y = dic[connector2.belong_type]
	return 1 if x > y else -1


def sort_connectors(connectors):
	"""Sort Connector order by Equipment>EquipPart>Other>Pipe>Duct"""
	return sorted(connectors, key=cmp_to_key(lambda x, y: connector_sort(x, y)))


def is_break_condition(element):
	"""Path end Condition."""
	res = element.type in revit_const.FACILITY
	return res


def dic2obj(d):
	"""Convert Dict to Object.
	"""
	top = type('new', (object,), d)
	seqs = tuple, list, set, frozenset
	for i, j in d.items():
		if isinstance(j, dict):
			setattr(top, i, dic2obj(j))
		elif isinstance(j, seqs):
			setattr(top, i,
					type(j)(dic2obj(sj) if isinstance(sj, dict) else sj for sj in j))
		else:
			setattr(top, i, j)
	return top


def list_to_dict(lis):
	ids = [idx.id for idx in lis]
	dic = dict(zip(ids, lis))
	return dic


def add_attr_is_used(x):
	"""
	Add is_used attribute.
	:param x:
	:return:
	"""
	x.is_used = False
	return x


def is_xyz_equal(origin1, origin2):
	"""
	Judge the two origin are almost equal.
	:param origin1:
	:param origin2:
	:return:
	"""
	v1 = [origin1.X, origin1.Y, origin1.Z]
	v2 = [origin2.X, origin2.Y, origin2.Z]
	return vg.almost_equal(v1, v2, atol=1e-08)


def combine_systemgraph(floorgraphs):
	"""
	Consider the riser merger
	:param floorgraphs:
	:return:projectgraph
	"""
	# get all open vertical pipe
	open_vertical_pipes = []
	for floorgraph in floorgraphs:
		for systemgraph in floorgraph.system_graphs:
			open_vertical_pipes.extend(systemgraph.get_open_vertical_pipes())
	# group systemvertex
	projectgraph = graph_model.ProjectGraph()
	for i in range(len(open_vertical_pipes)):
		v1 = open_vertical_pipes[i]
		group_pipes = [v1]
		for j in range(i + 1, len(open_vertical_pipes)):
			v2 = open_vertical_pipes[j]
			if is_xyz_equal(v1.connector.origin, v2.connector.origin):
				group_pipes.append(v2)
			# combine systemgraph
			for k in range(len(group_pipes)):
				vertex = group_pipes[k]
				systemgraph = get_specify_type_parent(vertex,graph_model.SystemGraph)
				if not systemgraph:
					continue
				projectgraph.remove_groupedsystemgraphs(systemgraph)
				if (k == 0):
					temp_groupedsystemgraphs = graph_model.GroupedSystemGraph(systemgraph)
				else:
					prev_vertex = group_pipes[k - 1]
					temp_groupedsystemgraphs.add_system(systemgraph)
					temp_groupedsystemgraphs.add_edge(prev_vertex, vertex)
			if temp_groupedsystemgraphs:
				projectgraph.groupedsystemgraphs.append(temp_groupedsystemgraphs)
	return projectgraph

def get_specify_type_parent(vertex, type):
	parent = vertex
	try:
		while not isinstance(parent, type):
			parent = parent.parent
	except :
		parent=None

	return parent