import bpy
import random
from . import my_globals
# from . import icônes

'''class scenecity_importer_batiment_op(bpy.types.Operator):
	bl_idname = 'scene.scenecity_importer_batiment_op'
	bl_description = 'Import building'
	bl_label = 'Import building'
	bl_options = {'REGISTER', 'UNDO'}

	def execute(self, context):
		print('Hello new menu!')
		return {'FINISHED'}'''

class SC_PT_material(bpy.types.Panel):
	bl_region_type = 'WINDOW'
	bl_space_type = 'PROPERTIES'
	bl_context = 'material'
	bl_options = {'DEFAULT_CLOSED'}
	bl_label = 'SceneCity'
	
	@classmethod
	def poll(cls, context):
		return context.object and type(context.object.__data) is bpy.types.Mesh and context.object.active_material
		
	def draw_header(self, context):
		# global icônes
		self.layout.label(text='', icon_value=my_globals.icônes['logo'].icon_id)
		
	def draw(self, context):
		# global icônes
		'''mes_mat_slots = context.object.data.SceneCity_mesh.material_slots
		active_slot = context.object.material_slots[context.object.active_material_index]
		
		box = self.layout.box()
		
		if len(mes_mat_slots) != len(context.object.material_slots):
			row = box.row(); row.operator('material.scenecity_maj_material_slots_op', icon='ERROR')
		
		for slotnb, mat_slot in enumerate(mes_mat_slots):
			row = box.row(); row.label('Slot '+str(slotnb+1)+'\'s materials prefixes'); row.prop(mat_slot, 'préfixe_commun_matériaux_à_utiliser')
			
		row = box.row(); row.operator('material.scenecity_randomiser_materiaux_assignes_op')
			
		row = self.layout.row(); row.template_icon_view(context.window_manager, 'SceneCity_matériaux_previews')
		row = self.layout.row(); row.operator('scene.scenecity_importer_materiau_op')
		'''	
		
		row = self.layout.row(); row.prop(context.object.active_material.SceneCity, 'labels')

class SceneCity_PropertyGroup_Material(bpy.types.PropertyGroup):
	labels : bpy.props.StringProperty(
		name='Labels', 
		description='Separate with commas if you need to assign multiple labels to this material')

def avoir_dict_materiaux_par_label():
	dict_materiaux_par_label = {}
	for material in bpy.data.materials:
		if not material.SceneCity.labels: continue
		material_labels = material.SceneCity.labels.split(',')
		for material_label in material_labels:
			if material_label not in dict_materiaux_par_label:
				dict_materiaux_par_label[material_label] = set()
			dict_materiaux_par_label[material_label].add(material)
	return dict_materiaux_par_label
			
def avoir_materiau_hasard_meme_labels(dict_materiaux_par_label, labels_separes_par_virgule):
	try:
		materiaux_candidats = set()
		for label in labels_separes_par_virgule.split(','):
			try: 
				materiaux_candidats = materiaux_candidats.union(dict_materiaux_par_label[label])
			except: pass
		return random.choice(list(materiaux_candidats))
	except:
		return None

def appliquer_materiaux_aleatoires(objet, dict_materiaux_par_label):
	for material_slot in objet.material_slots:
		if not material_slot.material: continue
		matériaux_aléatoire = avoir_materiau_hasard_meme_labels(dict_materiaux_par_label, material_slot.material.SceneCity.labels)
		if not matériaux_aléatoire: continue
		material_slot.link = 'OBJECT'
		material_slot.material = matériaux_aléatoire
'''
class scenecity_importer_materiau_op(bpy.types.Operator):
	bl_idname = 'scene.scenecity_importer_materiau_op'
	bl_description = 'Import chosen material, from the preview'
	bl_label = 'Import material and assign to selected material slot'
	bl_options = {'REGISTER', 'UNDO'}

	def execute(self, context):
		nom_matériau = 'SceneCity '+context.window_manager.SceneCity_matériaux_previews
		bpy.ops.wm.link(filename = nom_matériau,
			directory = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'materials/materials.blend/Material/'), 
			link = False, relative_path = True
		)
		mat = bpy.data.materials[nom_matériau]
		mat.name = mat.name[10:]
		context.object.material_slots[context.object.active_material_index].material = mat
		return {'FINISHED'}

class scenecity_randomiser_materiaux_assignes_op(bpy.types.Operator):
	bl_idname = 'material.scenecity_randomiser_materiaux_assignes_op'
	bl_description = ''
	bl_label = 'Assign random materials to the material slots'
	bl_options = {'REGISTER', 'UNDO'}

	def execute(self, context):
		material_slots = context.object.data.SceneCity_mesh.material_slots
		for slotNb, slot in enumerate(material_slots):
			préfixes_communs = slot.préfixe_commun_matériaux_à_utiliser.split(',')
			matériaux_à_utiliser = []
			for préfixe_commun in préfixes_communs:
				for material in bpy.data.materials:
					if material.name.startswith(préfixe_commun): matériaux_à_utiliser.append(material)
			if len(matériaux_à_utiliser) > 0 and slotNb < len(context.object.material_slots):
				context.object.material_slots[slotNb].link = 'OBJECT'
				context.object.material_slots[slotNb].material = random.choice(matériaux_à_utiliser)
				
		return {'FINISHED'}

class scenecity_randomiser_materiau_op(bpy.types.Operator):
	bl_idname = 'material.scenecity_randomiser_materiau_op'
	bl_description = 'There must be random value nodes present in the shader node tree (add node menu -> input -> random value), or nothing will happen'
	bl_label = 'Randomize all random nodes'
	bl_options = {'REGISTER', 'UNDO'}

	def execute(self, context):
		material_slots = context.object.material_slots
		for slot in material_slots:
			
			if not slot.material: continue
			for node in slot.material.node_tree.nodes:
				if type(node) is not scenecity_node_valeur_aleatoire: continue
				node.randomiser()
		
		return {'FINISHED'}

class scenecity_maj_material_slots_op(bpy.types.Operator):
	bl_idname = 'material.scenecity_maj_material_slots_op'
	bl_description = 'Creates or removes the needed fields below to specify the material groups associated with each material slot'
	bl_label = 'Sync nb of fields below with nb of material slots'
	bl_options = {'REGISTER', 'UNDO'}

	def execute(self, context):
		mes_mat_slots = context.object.data.SceneCity_mesh.material_slots
		total_slots = len(context.object.material_slots)
		
		while len(mes_mat_slots) > total_slots:
			mes_mat_slots.remove(len(mes_mat_slots)-1)
			
		while len(mes_mat_slots) < total_slots:
			mes_mat_slots.add()
			
		return {'FINISHED'}

# charger les preview des matériaux	
def créer_enum_pour_previews_matériaux(self, context):
	global icônes
	
	if context is None: return []
	if icônes.matériaux: return icônes.matériaux

	icônes.matériaux = []
	for no_image, nom_complet_image in enumerate(glob.glob(os.path.join(os.path.dirname(__file__), 'materials', '*.jpg'))):
		nom_preview = os.path.basename(nom_complet_image)[0:-4]
		# print('Ajout de la preview nommée '+nom_preview+', pour l\'image '+nom_complet_image)
		preview = icônes.load(nom_preview, nom_complet_image, 'IMAGE')
		icônes.matériaux.append((nom_preview, nom_preview, '', preview.icon_id, no_image))

	return icônes.matériaux

#
# CUSTOM NODES
#

def avoir_nodes_et_links_de_larbre_en_cours(context):
	space = context.space_data
	tree = space.node_tree
	nodes = tree.nodes
	links = tree.links
	active = nodes.active
	context_active = context.active_node
	# check if we are working on regular node tree or node group is currently edited.
	# if group is edited - active node of space_tree is the group
	# if context.active_node != space active node - it means that the group is being edited.
	# in such case we set "nodes" to be nodes of this group, "links" to be links of this group
	# if context.active_node == space.active_node it means that we are not currently editing group
	is_main_tree = True
	if active:
		is_main_tree = context_active == active
	if not is_main_tree:  # if group is currently edited
		tree = active.node_tree
		nodes = tree.nodes
		links = tree.links

	return nodes, links	
	
def func_socket_float_update(self, context):
	self.node.update()
	
class scenecity_socket_float(bpy.types.NodeSocketFloat):
	# obligé de créer un nouveau type de socket, car ceux d'origine ne permettent plus de manipuler leur value_property
	bl_idname = 'scenecity_socket_float'
	
	# def __init__(self):
		# self.méthode_update = None

	def draw(self, context, layout, node, text):
		if self.is_output or self.is_linked:
			layout.label(text)
		else:
			layout.prop(self, 'default_value', text=text)

	# Socket color
	def draw_color(self, context, node):
		return (.63, .63, .63, 1)
		
		
	default_value = bpy.props.FloatProperty(name='default value', description='Default value', default=.5, min=0, max=2, update=func_socket_float_update)
	
def func_node_couleur_mode_update(self, context):
	self.update()
	
class scenecity_node_couleur(bpy.types.Node):
	bl_idname = 'scenecity_node_couleur'
	bl_label = 'RGBA / HSVA Color'
	
	SceneCity_couleur = bpy.props.FloatVectorProperty(  
		name='(read only)',
		subtype='COLOR',
		size=4,
		min=0.0, max=1.0,
		description='Output color from RGBA inputs'
	)
	SceneCity_mode = bpy.props.EnumProperty(  
		name='Mode',
		items=[
			('RGB','RGB','',1), 
			('HSV','HSV','',2), 
		],
		description='How the inputs are interpreted: RGB or HSV',
		update=func_node_couleur_mode_update,
	)
	
	def init(self, context):
		self.inputs.new('scenecity_socket_float', 'R/H')
		self.inputs.new('scenecity_socket_float', 'G/S')
		self.inputs.new('scenecity_socket_float', 'B/V')
		self.inputs.new('scenecity_socket_float', 'A')
		self.outputs.new('NodeSocketColor', 'Color')
		
		
	def draw_buttons(self, context, layout):
		layout.prop(self, 'SceneCity_couleur')
		layout.prop(self, 'SceneCity_mode')
		
	def _avoir_RGBA_ou_HSVA(self):
		R_input = self.inputs['R/H']
		R = R_input.default_value
		G_input = self.inputs['G/S']
		G = G_input.default_value
		B_input = self.inputs['B/V']
		B = B_input.default_value
		A_input = self.inputs['A']
		A = A_input.default_value
		
		if R_input.is_linked and R_input.links[0].is_valid:
			R = R_input.links[0].from_socket.default_value
		if G_input.is_linked and G_input.links[0].is_valid:
			G = G_input.links[0].from_socket.default_value
		if B_input.is_linked and B_input.links[0].is_valid:
			B = B_input.links[0].from_socket.default_value
		if A_input.is_linked and A_input.links[0].is_valid:
			A = A_input.links[0].from_socket.default_value
		
		return (R,G,B,A)
		
	def update(self):
		try:
			R,G,B,A = self._avoir_RGBA_ou_HSVA()
			if self.SceneCity_mode == 'HSV':
				R,G,B,A = colorsys.hsv_to_rgb(R,G,B) + (A,)
			self.SceneCity_couleur = R,G,B,A
			output = self.outputs['Color']
			if abs(output.default_value[0]-R)>=1e-6 or abs(output.default_value[1]-G)>=1e-6 or abs(output.default_value[2]-B)>=1e-6 or abs(output.default_value[3]-A)>=1e-6:
				output.default_value = (R,G,B,A)
		except:
			return
		if not output.is_linked: return
		for link in output.links:
			if not link.is_valid: continue
			# vérifier si besoin de faire le reste, pour éviter des updates en boucle dans BI
			link_default_value = link.to_socket.node.inputs[link.to_socket.name].default_value
			if link_default_value[0] != output.default_value[0] or link_default_value[1] != output.default_value[1] or link_default_value[2] != output.default_value[2] or link_default_value[3] != output.default_value[3]:
				link.to_socket.node.inputs[link.to_socket.name].default_value = output.default_value
				
class scenecity_node_valeur_aleatoire(bpy.types.Node):
	bl_idname = 'scenecity_node_valeur_aleatoire'
	bl_label = 'Random value'
	
	def init(self, context):
		self.valeurMin_input = self.inputs.new('NodeSocketFloat', 'Min')
		self.valeurMax_input = self.inputs.new('NodeSocketFloat', 'Max')
		self.valeurMax_input.default_value = 1
		self.output = self.outputs.new('NodeSocketFloat', 'Random value')
		
	def draw_buttons(self, context, layout):
		bouton = layout.operator('node.scenecity_operator_nodes_randomiser_valeur_aleatoire')
		bouton.nom_node = self.name
		min_value, max_value = self._avoirValeursMinEtMax()
		if min_value >= max_value:
			layout.label('Min must be less than max', icon='ERROR')
		layout.label('Output '+str(round(self.outputs['Random value'].default_value, 6)))
		
	def _avoirValeursMinEtMax(self):
		min_input = self.inputs['Min']
		min_value = min_input.default_value
		max_input = self.inputs['Max']
		max_value = max_input.default_value
		
		if min_input.is_linked and min_input.links[0].is_valid:
			min_value = min_input.links[0].from_socket.default_value
		if max_input.is_linked and max_input.links[0].is_valid:
			max_value = max_input.links[0].from_socket.default_value
		
		return min_value, max_value
		
	def randomiser(self):
		min_value, max_value = self._avoirValeursMinEtMax()
		if min_value >= max_value:
			return
		self.outputs['Random value'].default_value = random.uniform(min_value, max_value)
		self.update()
		
	def update(self):
		# print('scenecity_node_valeur_aleatoire update')
		try:
			output = self.outputs['Random value']
		except:
			return
		if not output.is_linked: return
		for link in output.links:
			if not link.is_valid: continue
			# vérifier si besoin de faire le reste, pour éviter des updates en boucle dans BI
			if link.to_socket.node.inputs[link.to_socket.name].default_value != output.default_value:
				link.to_socket.node.inputs[link.to_socket.name].default_value = output.default_value
				
class scenecity_operator_nodes_ajouter_valeur_aleatoire(bpy.types.Operator):
	bl_idname = 'node.scenecity_operator_nodes_ajouter_valeur_aleatoire'
	bl_description = ''
	bl_label = 'Random value'
	bl_options = {'REGISTER', 'UNDO'}

	def invoke(self, context, event):
		nodes, links = avoir_nodes_et_links_de_larbre_en_cours(context)
		node = nodes.new('scenecity_node_valeur_aleatoire')
		
		nodes, links = avoir_nodes_et_links_de_larbre_en_cours(context)
		for node in nodes: node.select = False
		nodes.active = node
		node.select = True
		context.space_data.cursor_location_from_region(event.mouse_region_x, event.mouse_region_y)
		node.location[0] = context.space_data.cursor_location[0]
		node.location[1] = context.space_data.cursor_location[1]
		bpy.ops.transform.translate('INVOKE_DEFAULT')
		
		return {'FINISHED'}
		
class scenecity_operator_nodes_ajouter_couleur(bpy.types.Operator):
	bl_idname = 'node.scenecity_operator_nodes_ajouter_couleur'
	bl_description = ''
	bl_label = 'RGBA / HSVA Color'
	bl_options = {'REGISTER', 'UNDO'}

	def invoke(self, context, event):
		nodes, links = avoir_nodes_et_links_de_larbre_en_cours(context)
		node = nodes.new('scenecity_node_couleur')
		
		nodes, links = avoir_nodes_et_links_de_larbre_en_cours(context)
		for node in nodes: node.select = False
		nodes.active = node
		node.select = True
		context.space_data.cursor_location_from_region(event.mouse_region_x, event.mouse_region_y)
		node.location[0] = context.space_data.cursor_location[0]
		node.location[1] = context.space_data.cursor_location[1]
		bpy.ops.transform.translate('INVOKE_DEFAULT')
		
		return {'FINISHED'}
		
class scenecity_operator_nodes_randomiser_valeur_aleatoire(bpy.types.Operator):
	bl_idname = 'node.scenecity_operator_nodes_randomiser_valeur_aleatoire'
	bl_description = ''
	bl_label = 'Randomize'
	bl_options = {'REGISTER', 'UNDO'}

	nom_node = bpy.props.StringProperty()
	
	def execute(self, context):
		nodes, links = avoir_nodes_et_links_de_larbre_en_cours(context)
		nodes[self.nom_node].randomiser()
		return {'FINISHED'}

def func_nodes_menu_input(self, context):
	global icônes
	self.layout.separator()
	self.layout.operator(scenecity_operator_nodes_ajouter_valeur_aleatoire.bl_idname, icon_value=icônes['logo'].icon_id)
	self.layout.operator('node.scenecity_operator_nodes_ajouter_couleur', icon_value=icônes['logo'].icon_id)
'''