import os
import glob
from devil import *

ilInit()

class Image:
	def __init__(self, fileName):
		self.fileName = fileName
		self.image = ilGenImage()
		ilBindImage(self.image)
		self.isLoad = ilLoad(IL_TYPE_UNKNOWN, fileName)
		ilConvertImage(IL_BGRA, IL_UNSIGNED_BYTE)

		self.pos = (0, 0)
		if self.isLoad:
			self.data = ilGetData()
			self.size = (int(ilGetInteger(IL_IMAGE_WIDTH)), int(ilGetInteger(IL_IMAGE_HEIGHT)))
			self.extent = int(self.size[0] * self.size[1])
		else:
			self.size = (0, 0)
			self.extent = 0

	def __del__(self):
		ilDeleteImage(self.image)

	def Print(self):
		print "load(%s) %d" % (self.fileName, self.isLoad)

	def SetPos(self, pos):
		self.pos = pos

	def GetSize(self):
		return self.size

	def SetPixels(self):
		if not self.isLoad:
			return

		ilSetPixels(self.pos+(0,), self.size+(1,), IL_BGRA, IL_UNSIGNED_BYTE, self.data)

	def Less(left, right):
		extent_diff = right.extent - left.extent
		return extent_diff


class ImagePackBuilder:
	def Run(self, imgFileNameList, maxSize, outFileName):
		imgList = [Image(imgFileName) for imgFileName in imgFileNameList]

		imgList.sort(lambda left, right: left.Less(right))

		for img in imgList:
			print img.GetSize(), img.extent

		back_size = self.__FindBestAlign(imgList, maxSize)
		print "best: %d %d" % back_size

		self.__Save(imgList, back_size, outFileName)

	def __Save(self, imgList, back_size, outFileName):
		outImage = ilGenImage()
		ilBindImage(outImage)
		ilTexImage(back_size + (1,))
		for img in imgList:
			img.SetPixels()
		ilEnable(IL_FILE_OVERWRITE)
		ilSave(IL_TGA, outFileName)
		ilDeleteImage(outImage)


	def __FindBestAlign(self, imgList, maxSize):
		minSize = (32, 32)

		back_widthRange = self.__GetTextureSizeRange(minSize[0], maxSize[0])
		back_heightRange= self.__GetTextureSizeRange(minSize[1], maxSize[1])

		maxExtent 	= maxSize[0] * maxSize[1]

		
		for back_height in back_heightRange:
			for back_width in back_widthRange:
				try:
					self.__AlignImageList(imgList, back_width, back_height)
					return (back_width, back_height)
				except RuntimeError, msg:
					if str(msg)!="OVERFLOW_IMAGE_HEIGHT":
						raise

		raise "OVERFLOW_BACK_MAX_SIZE"

	def __AlignImageList(self, imgList, back_width, back_height):
		rightList=[0]*back_height

		for img in imgList:
			(height, left, top) = self.__TestPutImageInRestArea(img, rightList, back_width)

			img_width, img_height = img.GetSize()
			if height < img_height:
				raise RuntimeError, "OVERFLOW_IMAGE_HEIGHT"

	
			img.SetPos((left, top))

			rightList[top : (top + img_height)]=[(left + img_width)] * img_height

	def __TestPutImageInRestArea(self, img, rightList, rightMax):
		img_width, img_height = img.GetSize()
		img_base_x = 0
		img_base_y = 0
		img_last_y = 0
		line = 0
		for right in rightList:
			rest = rightMax - right
			if 0 == img_last_y:
				if rest >= img_width:
					img_base_x = right
					img_base_y = line
					img_last_y += 1
			else:
				if img_base_x >= right:
					img_last_y += 1
					if img_last_y >= img_height:
						break
				else:
					img_last_y = 0
					if rest >= img_width:
						img_base_x = right
						img_base_y = line
						img_last_y += 1


			line += 1

		return (img_last_y, img_base_x, img_base_y)
	
	def __GetTextureSizeRange(self, begin, end):
		cur = begin

		retList=[]
		while cur<=end:
			retList.append(cur)
			cur<<=1

		return retList

imagePackBuilder = ImagePackBuilder()
imagePackBuilder.Run(glob.glob("*/*.tga"), (512, 512), "test.tga")
