# import bpy
# import time
# import random
# import math
# import datetime
# import mathutils
# from .. import CityNodeTreeNode, SC_Meshes_Getter_Node, DATA_Mesh, MapGetter, Map, str_last_job_done_time
#
#
# class SimpleLayoutNode(bpy.types.Node, CityNodeTreeNode, SC_Meshes_Getter_Node):
# 	bl_label = 'Simple buildings layout'
#
# 	last_operation_time = bpy.props.FloatProperty(
# 		name='',
# 		description='',
# 		default=0)
#
# 	total_buildings = bpy.props.IntProperty(
# 		name='Total buildings',
# 		description='Some may be skipped depending on the density map',
# 		default=10000)
#
# 	area_size_xy = bpy.props.IntVectorProperty(
# 		name='Area size XY',
# 		description='Unit is generic, depending on how you scale your buildings. Recommended 1 unit = 1 meter',
# 		size=2,
# 		min=10,
# 		default=(5000, 5000))
#
# 	buildings_size_xy_formula = bpy.props.StringProperty(
# 		name='Size XY formula',
# 		description='Use a Python formula. You can use the builtin, random and math modules. '
# 					'Use the size map at the building location with the sizeMap variable. '
# 					'The heightmap value with the heightMap variable. '
# 					'The building location with the x,y,z variables',
# 		default='random.gauss(25,50) * sizeMap ** 1.5')
#
# 	buildings_size_z_formula = bpy.props.StringProperty(
# 		name='Size Z formula',
# 		description='Use a Python formula. You can use the builtin, random and math modules. '
# 					'Use the size map at the building location with the sizeMap variable. '
# 					'The heightmap value with the heightMap variable. '
# 					'The building location with the x,y,z variables',
# 		default='random.gauss(50,100) * sizeMap ** 1.5')
#
# 	buildings_size_xy_values = bpy.props.FloatVectorProperty(
# 		name='XY size factor',
# 		description='Average size of the buildings and the variance, on X and Y. Variance means how much it can vary from the average',
# 		size=2,
# 		min=.0001,
# 		default=(25, 50))
#
# 	buildings_size_z_values = bpy.props.FloatVectorProperty(
# 		name='Z size factor',
# 		description='Average size of the buildings and the variance, on Z. Variance means how much it can vary from the average',
# 		size=2,
# 		min=.0001,
# 		default=(50, 100))
#
# 	buildings_size_xy_power = bpy.props.FloatProperty(
# 		name='XY size factor power',
# 		description='Horizontal size of the buildings will grow or shrink at the power of this value',
# 		default=1,
# 		min=.01, )
#
# 	buildings_size_z_power = bpy.props.FloatProperty(
# 		name='Z size factor power',
# 		description='Vertical size of the buildings will grow or shrink at the power of this value',
# 		default=2,
# 		min=.01, )
#
# 	buildings_ratio_xy = bpy.props.FloatProperty(
# 		name='XY size ratio',
# 		description='How many times larger / smaller a building can be on the X and Y axes, relatively to each other',
# 		default=3)
#
# 	buildings_ratio_z = bpy.props.FloatVectorProperty(
# 		name='Z size ratio',
# 		description='How many times smaller and larger a building can be on the Z axis, relatively to the smallest dimension on the X and Y axes',
# 		size=2,
# 		min=.0001,
# 		default=(.25, 10))
#
# 	buildings_xy_size_min_max = bpy.props.FloatVectorProperty(
# 		name='Size min',
# 		description='Min buildings size on the XY axes, and on the Z axis',
# 		size=2,
# 		min=.0001,
# 		default=(10, 3))
#
# 	buildings_z_size_min_max = bpy.props.FloatVectorProperty(
# 		name='Size max',
# 		description='Max buildings size on the XY axes, and on the Z axis',
# 		size=2,
# 		min=.0001,
# 		default=(200, 400))
#
# 	size_mode = bpy.props.EnumProperty(
# 		name='Buildings size mode',
# 		description='Control the size of the buildings with simple values using the builtin formulas, or set the formulas yourself',
# 		items=[
# 			('simple', 'Simple', '', 1),
# 			('advanced', 'Advanced', '', 2),
# 		])
#
# 	# buildings_params = bpy.props.StringProperty(
# 	# 	name='Buildings params',
# 	# 	description='Parameters to send to the buildings', )
#
# 	# asset_group_choice = bpy.props.StringProperty(
# 	# 	name='Asset tags to use',
# 	# 	description='Formula returning the tags to choose among the asset groups, depending on parameters of your choice', )
#
# 	# city_grid_input_limit = bpy.props.StringProperty(
# 	# 	name='City grid mask',
# 	# 	description='Boolean to choose what city grid cells can be used, and those that must be left untouched', )
#
# 	# city_grid_output = bpy.props.StringProperty(
# 	# 	name='City grid output',
# 	# 	description='Tags to store in the city grid cells affected by this layout', )
#
# 	random_seed = bpy.props.IntProperty(
# 		name='Seed',
# 		description='Random seed', )
#
# 	should_rotate_buildings = bpy.props.BoolProperty(
# 		name='Random rotation of buildings',
# 		description='',
# 		default=False)
#
# 	def get_sc_meshes(self, **kwargs):
# 		# get previous mesh data
# 		try:
# 			previous_mesh_data_node = self.inputs['Previous mesh data'].links[0].from_node  # type: SC_Meshes_Getter_Node
# 			sc_mesh = previous_mesh_data_node.get_sc_meshes()
# 		except:
# 			sc_mesh = DATA_Mesh()
#
# 		startTime = time.time()  # start counting time here, don't count previous work needed
# 		buildings_mesh_data_node = None
# 		try:
# 			buildings_mesh_data_node = self.inputs['Buildings mesh data'].links[0].from_node  # type: SC_Meshes_Getter_Node
# 		except:
# 			pass
#
# 		total_buildings = self.total_buildings
# 		area_side_length_meters_x = self.area_size_xy[0]
# 		area_side_length_meters_y = self.area_size_xy[1]
# 		random.seed(self.random_seed)
#
# 		try:
# 			requested_pos = kwargs['location']
# 		except:
# 			requested_pos = (0, 0, 0)
# 		try:
# 			buildings_size_map_node = self.inputs['Buildings size map'].links[0].from_node  # type: MapGetter
# 			buildings_size_map = buildings_size_map_node.get_map()  # type: Map
# 		except:
# 			buildings_size_map = None
#
# 		# random_pos_in_size_map = (random.uniform(-100, 100), random.uniform(-100, 100), random.uniform(-100, 100))
# 		last_progress_display_time = time.time()
# 		for buildingNb in range(total_buildings):
# 			building_pos_x = random.uniform(-area_side_length_meters_x / 2, area_side_length_meters_x / 2)
# 			building_pos_y = random.uniform(-area_side_length_meters_y / 2, area_side_length_meters_y / 2)
# 			building_pos_z = 0
#
# 			# afficher progress bar
# 			if time.time() > last_progress_display_time + .25:
# 				last_progress_display_time = time.time()
# 				self.afficher_barre_progression(buildingNb / total_buildings, time.time() - startTime)
#
# 			# building_pos_z = heightmap[
# 			# 	math.floor((building_pos_x + area_side_length_meters / 2) / area_side_length_meters * heightmap_resolution)][
# 			# 	math.floor((building_pos_y + area_side_length_meters / 2) / area_side_length_meters * heightmap_resolution)
# 			# ]
# 			# building_pos_z = heightmap[
# 			# 	math.floor(building_pos_x / area_side_length_meters * heightmap_resolution)][
# 			# 	math.floor(building_pos_y / area_side_length_meters * heightmap_resolution)
# 			# ]
#
# 			# ATTENTION à sampler les maps en avant la location demandée par le commanditaire
# 			if buildings_size_map:
# 				size_map_value = buildings_size_map.get_value(
# 					(building_pos_x + (area_side_length_meters_x / 2)) / area_side_length_meters_x,
# 					(building_pos_y + (area_side_length_meters_y / 2)) / area_side_length_meters_y)
# 			else:
# 				size_map_value = 1
#
# 			building_pos_x += requested_pos[0]
# 			building_pos_y += requested_pos[1]
# 			building_pos_z += requested_pos[2]
#
# 			building_pos = (building_pos_x, building_pos_y, building_pos_z)
#
# 			# size_map_value = mathutils.noise.fractal(
# 			# 	(random_pos_in_size_map[0] + building_pos[0] * fractal_size,
# 			# 	 random_pos_in_size_map[1] + building_pos[1] * fractal_size,
# 			# 	 random_pos_in_size_map[2]),
# 			# 	.5, 2, 4, mathutils.noise.types.CELLNOISE) * 2
# 			# size_map_value = 1
#
# 			# size_map_value = min(1, size_map_value)
# 			if size_map_value <= 0:
# 				continue
# 			# size_map_value = max(0.5, size_map_value)
#
# 			# initial random size
# 			size_x = random.gauss(self.buildings_size_xy_values[0], self.buildings_size_xy_values[1])
# 			size_y = random.gauss(self.buildings_size_xy_values[0], self.buildings_size_xy_values[1])
# 			size_z = random.gauss(self.buildings_size_z_values[0], self.buildings_size_z_values[1])
#
# 			# size map modifier
# 			size_x *= size_map_value ** self.buildings_size_xy_power
# 			size_y *= size_map_value ** self.buildings_size_xy_power
# 			size_z *= size_map_value ** self.buildings_size_z_power
#
# 			# max / min applied
# 			size_x = max(self.buildings_xy_size_min_max[0], min(self.buildings_z_size_min_max[0], size_x))
# 			size_y = max(self.buildings_xy_size_min_max[0], min(self.buildings_z_size_min_max[0], size_y))
# 			size_z = max(self.buildings_xy_size_min_max[1], min(self.buildings_z_size_min_max[1], size_z))
#
# 			# min / max ratios
# 			random_direction = random.choice(['x', 'y'])
# 			if random_direction == 'x':
# 				if size_y < size_x / self.buildings_ratio_xy:
# 					size_y = size_x / self.buildings_ratio_xy
# 				elif size_y > size_x * self.buildings_ratio_xy:
# 					size_y = size_x * self.buildings_ratio_xy
# 			else:
# 				if size_x < size_y / self.buildings_ratio_xy:
# 					size_x = size_y / self.buildings_ratio_xy
# 				elif size_x > size_y * self.buildings_ratio_xy:
# 					size_x = size_y * self.buildings_ratio_xy
# 			# if x is shorter side
# 			if size_x < size_y:
# 				# building cannot be shorter than the largest side of the building * min ratio
# 				if size_z < size_y * self.buildings_ratio_z[0]:
# 					size_z = size_y * self.buildings_ratio_z[0]
# 				# building cannot be taller than the smallest side of the building * max ratio
# 				elif size_z > size_x * self.buildings_ratio_z[1]:
# 					size_z = size_x * self.buildings_ratio_z[1]
# 			else:
# 				# building cannot be shorter than the largest side of the building * min ratio
# 				if size_z < size_x * self.buildings_ratio_z[0]:
# 					size_z = size_x * self.buildings_ratio_z[0]
# 				# building cannot be taller than the smallest side of the building * max ratio
# 				elif size_z > size_y * self.buildings_ratio_z[1]:
# 					size_z = size_y * self.buildings_ratio_z[1]
#
# 			building_size = (size_x, size_y, size_z)
#
# 			randomstate = random.getstate()
# 			current_building_mesh_is_dynamic = buildings_mesh_data_node.is_dynamic_mesh()
# 			current_building_mesh_data = buildings_mesh_data_node.get_sc_meshes(
# 				size=building_size,
# 				location=building_pos)
# 			if not buildings_mesh_data_node.is_mesh_param_supported('size'):
# 				current_building_mesh_data.scale(building_size)
# 			if self.should_rotate_buildings and not buildings_mesh_data_node.is_mesh_param_supported('rotation'):
# 				current_building_mesh_data.rotate_z(random.uniform(0, math.pi))
# 			if not buildings_mesh_data_node.is_mesh_param_supported('location'):
# 				current_building_mesh_data.translate(building_pos)
# 			sc_mesh += current_building_mesh_data
# 			random.setstate(randomstate)
#
# 		# sc_mesh.verts.extend(verts)
# 		# sc_mesh.faces.extend(faces)
# 		self.last_operation_time = time.time() - startTime
# 		self.afficher_barre_progression(1, self.last_operation_time)
# 		return sc_mesh
#
# 	def init(self, context):
# 		self.width = 400
# 		# self.outputs.new('AssetInstancesSocket', 'Asset instances')
# 		self.outputs.new('SOCKET_Meshes', 'DATA_Mesh data')
# 		# self.outputs.new('MapSocket', 'Buildings mask map')
#
# 		# self.inputs.new('MapSocket', 'Buildings density map')
# 		self.inputs.new('SOCKET_Meshes', 'Buildings mesh data')
# 		self.inputs.new('MapSocket', 'Buildings size map')
# 		# self.inputs.new('MapSocket', 'Terrain height map')
# 		self.inputs.new('SOCKET_Meshes', 'Previous mesh data')
#
# 		# self.outputs.new('CityDefSocket', 'City def')
# 		self.random_seed = random.randint(0, 9e5)
#
# 	def draw_buttons(self, context, layout):
# 		if len(self.inputs['Buildings mesh data'].links) <= 0:
# 			layout.label(text="Buildings mesh data is needed", icon="ERROR")
#
# 		layout.label(text='Last job done in: ' + str_last_job_done_time(self.last_operation_time))
#
# 		layout.prop(self, 'total_buildings')
# 		layout.prop(self, 'area_size_xy')
# 		layout.prop(self, 'should_rotate_buildings')
# 		row = layout.row()
# 		row.prop(self, 'random_seed')
# 		op = row.operator('node.randomize_seed_operator')
# 		op.source_node_path = 'bpy.data.node_groups["' + self.id_data.name + '"].' + self.path_from_id()
#
# 		# layout.label(text='')
# 		# layout.prop(self, 'size_mode')
# 		if self.size_mode == 'simple':
# 			layout.prop(self, 'buildings_size_xy_values')
# 			layout.prop(self, 'buildings_size_z_values')
# 			layout.prop(self, 'buildings_size_xy_power')
# 			layout.prop(self, 'buildings_size_z_power')
# 		else:
# 			layout.prop(self, 'buildings_size_xy_formula')
# 			layout.prop(self, 'buildings_size_z_formula')
#
# 		# layout.label(text='')
# 		# real_layout = layout
# 		# layout = layout.box()
# 		layout.prop(self, 'buildings_xy_size_min_max')
# 		layout.prop(self, 'buildings_z_size_min_max')
#
# 		# layout.label(text='')
# 		layout.prop(self, 'buildings_ratio_xy')
# 		layout.prop(self, 'buildings_ratio_z')
