import bpy
import bmesh
import operator
import math
from mathutils import Vector
from collections import defaultdict

from . import utilities_color
from . import utilities_bake
from . import utilities_ui

material_prefix = "TT_atlas_"
gamma = 2.2

class op(bpy.types.Operator):
	bl_idname = "uv.textools_color_convert_to_texture"
	bl_label = "Pack Texture"
	bl_description = "Pack ID Colors into single texture and UVs"
	bl_options = {'REGISTER', 'UNDO'}
	

	@classmethod
	def poll(cls, context):
		if not bpy.context.active_object:
			return False

		if bpy.context.active_object not in bpy.context.selected_objects:
			return False

		if len(bpy.context.selected_objects) != 1:
			return False

		if bpy.context.active_object.type != 'MESH':
			return False

		#Only in UV editor mode
		if bpy.context.area.type != 'IMAGE_EDITOR':
			return False

		return True
	
	def execute(self, context):
		pack_texture(self, context)
		return {'FINISHED'}



def pack_texture(self, context):
	obj = bpy.context.active_object
	name = material_prefix+obj.name

	if obj.mode != 'OBJECT':
		bpy.ops.object.mode_set(mode='OBJECT')


	# Determine size
	size_pixel = 8
	size_square = math.ceil(math.sqrt( context.scene.texToolsSettings.color_ID_count ))
	size_image = size_square * size_pixel
	size_image_pow = int(math.pow(2, math.ceil(math.log(size_image, 2))))

	# Maximize pixel size
	size_pixel = math.floor(size_image_pow/size_square)

	print("{0} colors = {1} x {1} = ({2}pix)  {3} x {3}  | {4} x {4}".format(
		context.scene.texToolsSettings.color_ID_count, 
		size_square,
		size_pixel,
		size_image,
		size_image_pow
	))

	# Create image
	image = bpy.data.images.new(name, width=size_image_pow, height=size_image_pow)
	pixels = [None] * size_image_pow * size_image_pow

	# Black pixels
	for x in range(size_image_pow):
		for y in range(size_image_pow):
			pixels[(y * size_image_pow) + x] = [0, 0, 0, 1]

	# Pixels
	for c in range(context.scene.texToolsSettings.color_ID_count):
		x = c % size_square
		y = math.floor(c/size_square)
		color = utilities_color.get_color(c).copy()
		for i in range(3):
			color[i] = pow(color[i] , 1.0/gamma)

		for sx in range(size_pixel):
			for sy in range(size_pixel):
				_x = x*size_pixel + sx
				_y = y*size_pixel + sy
				pixels[(_y * size_image_pow) + _x] = [color[0], color[1], color[2], 1]


	# flatten list & assign pixels
	pixels = [chan for px in pixels for chan in px]
	image.pixels = pixels

	# Set background image
	for area in bpy.context.screen.areas:
		if area.type == 'IMAGE_EDITOR':
			area.spaces[0].image = image

	# Edit mesh
	bpy.ops.object.mode_set(mode='EDIT')
	bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE')
	bpy.ops.mesh.select_all(action='SELECT')
	# bpy.ops.uv.smart_project(angle_limit=1)
	bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=0.0078)


	bm = bmesh.from_edit_mesh(bpy.context.active_object.data)
	uv_layers = bm.loops.layers.uv.verify();

	for face in bm.faces:
		index = face.material_index

		# Get UV coordinates for index
		x = index%size_square
		y = math.floor(index/size_square)

		x*= (size_pixel / size_image_pow) 
		y*= (size_pixel / size_image_pow)
		x+= size_pixel/size_image_pow/2
		y+= size_pixel/size_image_pow/2

		for loop in face.loops:
			loop[uv_layers].uv = (x, y)

	# Remove Slots & add one
	bpy.ops.object.mode_set(mode='OBJECT')
	bpy.ops.uv.textools_color_clear()
	bpy.ops.object.material_slot_add()
	
	#Create material with image
	obj.material_slots[0].material = utilities_bake.get_image_material(image)

	#Display UVs
	bpy.ops.object.mode_set(mode='EDIT')

	# Switch textured shading
	for area in bpy.context.screen.areas:
		if area.type == 'VIEW_3D':
			for space in area.spaces:
				if space.type == 'VIEW_3D':
					space.shading.type = 'MATERIAL'

	bpy.ops.ui.textools_popup('INVOKE_DEFAULT', message="Packed texture with {} color IDs".format( context.scene.texToolsSettings.color_ID_count ))


bpy.utils.register_class(op)