#!/usr/bin/python

import json
import traceback
import numpy
from PIL import Image, ImageDraw
import gc

"""
# 166 to 164 with reference of 165
shrink
166
164
20
web\_img\canvas\place30\159.png
web\_img\canvas\place30\163_159.png

# 166 to 165 with reference of 166
shrink
166
165
20
web\_img\canvas\place30\159.png
web\_img\canvas\place30\164_159.png

# 164 to 165 with reference of 165
shrink
164
165
20
web\_img\canvas\place30\159.png
web\_img\canvas\place30\163_159.png

# 166 to 167 with reference of 167
expand
166
167
20
web\_img\canvas\place30\159.png
web\_img\canvas\place30\165_159.png
"""

class ScaleConfig:
	type = 'expand'
	source = ''
	destination = ''
	threshold = 20
	image1 = ''
	image2 = ''

def swap_source_dest(source, destination, image2):
	ScaleConfig.source = source
	ScaleConfig.destination = destination
	ScaleConfig.image2 = image2

def remove_white(entry: dict):

	canvas_ref = Image.new('RGBA', (2000,2000))

	with Image.open(ScaleConfig.image1).convert('RGBA') as image1:
		if ScaleConfig.image2:
			with Image.open(ScaleConfig.image2).convert('RGBA') as image2:
				canvas_ref.paste(image1, (0, 0), image1)
				canvas_ref.paste(image2, (0, 0), image2)
		else:
			canvas_ref.paste(image1, (0, 0), image1)

	# uncomment when you need to see the source canvas
	# canvas_ref.show()

	# print(entry['path'])

	for (period, polygonList) in entry['path'].items():

		if not f"-{ScaleConfig.source}" in period: continue

		# Get bounding rectangle and have a list of tuples for polygon

		polygon = []
		x_box = 2000
		y_box = 2000
		x_box2 = 0
		y_box2 = 0

		for point in polygonList:
			x_box = min(x_box, max(point[0] - 1.5, 0))
			y_box = min(y_box, max(point[1] - 1.5, 0))
			x_box2 = max(x_box2, min(point[0] + 1.5, 2000))
			y_box2 = max(y_box2, min(point[1] + 1.5, 2000))
			polygon.append(tuple(point))

		x_box = int(x_box)
		y_box = int(y_box)
		x_box2 = int(x_box2)
		y_box2 = int(y_box2)

		# Crop the image based on polygon
		# https://stackoverflow.com/questions/22588074/

		imArray = numpy.asarray(canvas_ref)

		with Image.new('L', (imArray.shape[1], imArray.shape[0]), 0) as maskIm:
			ImageDraw.Draw(maskIm).polygon(polygon, outline=1, fill=1)
			mask = numpy.array(maskIm)
		newImArray = numpy.empty(imArray.shape,dtype='uint8')


		newImArray[:,:,:3] = imArray[:,:,:3]
		newImArray[:,:,3] = mask*255

		imArray = newImArray[y_box:y_box2,x_box:x_box2,:]

		# points = numpy.array([polygon])
		# print(points)
		# print(cv2.boundingRect(points[0]))
		# print(1)
		# print(imArray)

		colored_pixel_count: int = 0
		all_pixel_count: int = 0

		# Read the area based on bounding box

		for x in imArray:
			for pixel in x:
				if pixel[3] == 0: continue
				all_pixel_count += 1
				if (pixel[0] == 255 and pixel[1] == 255 and pixel[2] == 255): continue
				colored_pixel_count += 1

		if all_pixel_count == 0: break

		colorness = (100 * colored_pixel_count)/all_pixel_count

		if (ScaleConfig.type == "shrink" and colorness < ScaleConfig.threshold) or (ScaleConfig.type == "expand" and colorness > ScaleConfig.threshold):
			print(f"[{entry['id']} {period}] {colored_pixel_count}/{all_pixel_count} ({colorness}%)")
			new_period = period.replace(f'-{ScaleConfig.source}', f'-{ScaleConfig.destination}')
			entry['path'][new_period] = entry['path'][period]
			del entry['path'][period]
			entry['center'][new_period] = entry['center'][period]
			del entry['center'][period]
			break
			# newIm = Image.fromarray(newImArray, "RGBA")
			# newIm.show()

		break

	return entry

def per_line_entries(entries: list):
	"""
	Returns a string of all the entries, with every entry in one line.
	"""
	out = "[\n"
	for entry in entries:
		if entry:
			out += json.dumps(entry, ensure_ascii=False) + ",\n"
	out = out[:-2] + "\n]"
	return out

def format_all(entry: dict, silent=False):
	def print_(*args, **kwargs):
		if not silent:
			print(*args, **kwargs)

	entry = remove_white(entry)
	print_("Completed!")
	return entry

def scale_back_entries(entries):
	for i in range(len(entries)):
		try:
			entry_formatted = format_all(entries[i], True)
			entries[i] = entry_formatted
		except Exception:
			print(f"Exception occured when formatting ID {entries[i]['id']}")
			print(traceback.format_exc())
		if not (i % 50):
			print(f"{i} checked.")
			gc.collect()

def go(path):

	print(f"Scaling whiteout for {path}...")

	with open(path, "r+", encoding='UTF-8') as f1:
		entries = json.loads(f1.read())

	scale_back_entries(entries)

	print(f"{len(entries)} checked. Writing...")

	with open(path, "w", encoding='utf-8', newline='\n') as f2:
		f2.write(per_line_entries(entries))

	print("Writing completed. All done.")

if __name__ == '__main__':

	ScaleConfig.type = input("Type (shrink/expand): ")
	ScaleConfig.source = input("Source: ")
	ScaleConfig.destination = input("Destination: ")
	ScaleConfig.threshold = int(input("Threshold (%): "))
	ScaleConfig.image1 = input("Reference canvas layer 1: ")
	ScaleConfig.image2 = input("Reference canvas layer 2: ")

	go("web/atlas.json")
