import math
from swmmio.graphics.constants import * #constants
from swmmio.graphics import config, options
from swmmio.graphics.utils import *
from PIL import Image, ImageDraw, ImageFont, ImageOps
from time import strftime
import os


# FUNCTIONS FOR COMPUTING THE VISUAL CHARACTERISTICS OF MODEL ELEMENTS
def node_draw_size(node):
	"""given a row of a nodes() dataframe, return the size it should be drawn"""

	if 'draw_size' in node.axes[0]:
		#if this value has already been calculated
		return node.draw_size

	radius = 0 #aka don't show this node by default
	if 'HoursFlooded' in node and node.HoursFlooded >= 0.083:
		radius = node.HoursFlooded*3
	return radius

def node_draw_color(node):
	"""given a row of a nodes() dataframe, return the color it should be drawn"""

	if 'draw_color' in node.axes[0]:
		#if this value has already been calculated
		return node.draw_color

	color = '#d2d2e6'#(210, 210, 230) #default color
	if 'HoursFlooded' in node and node.HoursFlooded >= 0.083:
		color = red
	return color

def conduit_draw_size(conduit):
	"""return the draw size of a conduit"""

	if 'draw_size' in conduit.axes[0]:
		#if this value has already been calculated
		return conduit.draw_size

	draw_size = 1
	if 'MaxQPerc' in conduit and conduit.MaxQPerc >= 1:
		capacity = conduit.MaxQ / conduit.MaxQPerc
		stress = conduit.MaxQ / capacity
		fill = gradient_grey_red(conduit.MaxQ*100, 0, capacity*300)
		draw_size = int(round(math.pow(stress*10, 0.8)))

	elif 'Geom1' in conduit:
		draw_size = conduit.Geom1

	return draw_size

def conduit_draw_color(conduit):
	"""return the draw color of a conduit"""

	if 'draw_color' in conduit.axes[0]:
		#if this value has already been calculated
		return conduit.draw_color

	fill = '#787882' #(120, 120, 130)
	if 'MaxQPerc' in conduit and conduit.MaxQPerc >= 1:
		capacity = conduit.MaxQ / conduit.MaxQPerc
		stress = conduit.MaxQ / capacity
		fill = gradient_grey_red(conduit.MaxQ*100, 0, capacity*300)
	return fill

def parcel_draw_color(parcel, style='risk'):
	if style == 'risk':
		fill = gradient_color_red(parcel.HoursFlooded + 0.5, 0, 3)
	if style == 'delta':
		fill = lightgrey #default
		if parcel.Category == 'increased_flooding':
			#parcel previously flooded, now floods more
			fill = red

		if parcel.Category == 'new_flooding':
			#parcel previously did not flood, now floods in proposed conditions
			fill = purple

		if parcel.Category == 'decreased_flooding':
			#parcel flooding problem decreased
			fill = lightblue #du.lightgrey

		if parcel.Category == 'eliminated_flooding':
			#parcel flooding problem eliminated
			fill = lightgreen

	return fill

# PIL DRAW METHODS APPLIED TO ImageDraw OBJECTS
def draw_node(node, draw):
	"""draw a node to the given PIL ImageDraw object"""
	color = node_draw_color(node)
	radius = node_draw_size(node)
	draw.ellipse(circle_bbox(node.draw_coords[0], radius), fill = color)

def draw_conduit(conduit, draw):
    #default fill and size
    fill = conduit_draw_color(conduit)
    draw_size = int(conduit_draw_size(conduit))
    xys = conduit.draw_coords

    #draw that thing
    draw.line(xys, fill = fill, width = draw_size)
    if length_bw_coords(xys[0], xys[-1]) > draw_size*0.75:
        #if length is long enough, add circles on the ends to smooth em out
        #this check avoids circles being drawn for tiny pipe segs
        draw.ellipse(circle_bbox(xys[0], draw_size*0.5), fill = fill)
        draw.ellipse(circle_bbox(xys[1], draw_size*0.5), fill = fill)

def draw_parcel_risk(parcel, draw):
	fill = gradient_color_red(parcel.HoursFlooded + 0.5, 0, 3)
	draw.polygon(parcel.draw_coords, fill=fill)

def draw_parcel_risk_delta(parcel, draw):
	if parcel.Category == 'increased_flooding':
		#parcel previously flooded, now floods more
		fill = red

	if parcel.Category == 'new_flooding':
		#parcel previously did not flood, now floods in proposed conditions
		fill = purple

	if parcel.Category == 'decreased_flooding':
		#parcel flooding problem decreased
		fill = lightblue #du.lightgrey

	if parcel.Category == 'eliminated_flooding':
		#parcel flooding problem eliminated
		fill = lightgreen

	draw.polygon(parcel.draw_coords, fill=fill)

def annotate_streets(df, img, text_col):

	#confirm font file location
	if not os.path.exists(config.font_file):
		print('Error loading defautl font. Check your config.font_file')
		return None

	unique_sts = df[text_col].unique()
	for street in unique_sts:
		draw_coords = df.loc[df.ST_NAME==street, 'draw_coords'].tolist()[0]
		coords = df.loc[df.ST_NAME==street, 'coords'].tolist()[0]
		font = ImageFont.truetype(config.font_file, int(25))
		imgTxt = Image.new('L', font.getsize(street))
		drawTxt = ImageDraw.Draw(imgTxt)
		drawTxt.text((0,0), street, font=font, fill=(10,10,12))
		angle = angle_bw_points(coords[0], coords[1])
		texrot = imgTxt.rotate(angle, expand=1)
		mpt = midpoint(draw_coords[0], draw_coords[1])
		img.paste(ImageOps.colorize(texrot, (0,0,0), (10,10,12)), mpt,  texrot)

def gradient_grey_red(x, xmin, xmax):

	range = xmax - xmin

	rMin = 100
	bgMax = 100
	rScale = (255 - rMin) / range
	bgScale = (bgMax) / range
	x = min(x, xmax) #limit any vals to the prescribed max


	#print "range = " + str(range)
	#print "scale = " + str(scale)
	r = int(round(x*rScale + rMin ))
	g = int(round(bgMax - x*bgScale))
	b = int(round(bgMax - x*bgScale))

	return (r, g, b)

def line_size(q, exp=1):
	return int(round(math.pow(q, exp)))

def gradient_color_red(x, xmin, xmax, startCol=lightgrey):

	range = xmax - xmin

	rMin = startCol[0]
	gMax = startCol[1]
	bMax = startCol[2]

	rScale = (255 - rMin) / range
	gScale = (gMax) / range
	bScale = (bMax) / range
	x = min(x, xmax) #limit any vals to the prescribed max


	#print "range = " + str(range)
	#print "scale = " + str(scale)
	r = int(round(x*rScale + rMin ))
	g = int(round(gMax - x*gScale))
	b = int(round(bMax - x*bScale))

	return (r, g, b)

def annotate_title(title, draw):
	size = (draw.im.getbbox()[2], draw.im.getbbox()[3])
	scale = 1 * size[0] / 2048
	fnt = ImageFont.truetype(config.font_file, int(40 *scale))
	draw.text((10, 15), title, fill=black, font=fnt)

def annotate_timestamp(draw):
	size = (draw.im.getbbox()[2], draw.im.getbbox()[3])
	scale = 1 * size[0] / 2048
	fnt = ImageFont.truetype(config.font_file, int(20 *scale))

	timestamp = strftime("%b-%d-%Y %H:%M:%S")
	txt_height = draw.textsize(timestamp, fnt)[1]
	txt_width = draw.textsize(timestamp, fnt)[0]
	xy = (size[0] - txt_width - 10, 15)
	draw.text(xy, timestamp, fill=grey, font=fnt)

def annotate_details(txt, draw):
	size = (draw.im.getbbox()[2], draw.im.getbbox()[3])
	scale = 1 * size[0] / 2048
	fnt = ImageFont.truetype(config.font_file, int(20 *scale))

	txt_height = draw.textsize(txt, fnt)[1]

	draw.text((10, size[1] - txt_height - 10),
				txt, fill=black, font=fnt)

#LEGACY CODE !!!!!!
def _annotateMap (canvas, model, model2=None, currentTstr = None, options=None, results={}):

	#unpack the options
	nodeSymb = 		options['nodeSymb']
	conduitSymb = 	options['conduitSymb']
	basemap = 		options['basemap']
	parcelSymb = 	options['parcelSymb']
	traceUpNodes =	options['traceUpNodes']
	traceDnNodes =	options['traceDnNodes']

	modelSize = (canvas.im.getbbox()[2], canvas.im.getbbox()[3])

	#define main fonts
	fScale = 1 * modelSize[0] / 2048
	titleFont = ImageFont.truetype(fontFile, int(40 * fScale))
	font = ImageFont.truetype(fontFile, int(20 * fScale))

	#Buid the title and files list (handle 1 or two input models)
	#this is hideous, or elegant?
	files = title = results_string = symbology_string = annotationTxt = ""
	files = '\n'.join([m.rpt.path for m in [_f for _f in [model, model2] if _f]])
	title = ' to '.join([m.inp.name for m in [_f for _f in [model, model2] if _f]])
	symbology_string = ', '.join([s['title'] for s in [_f for _f in [nodeSymb, conduitSymb, parcelSymb] if _f]])
	title += "\n" + symbology_string

	#collect results
	for result, value in results.items():
		results_string += '\n' + result + ": " + str(value)

	#compile the annotation text
	if results:
		annotationTxt = results_string + "\n"
	annotationTxt += files


	annoHeight = canvas.textsize(annotationTxt, font)[1]

	canvas.text((10, 15), title, fill=black, font=titleFont)
	canvas.text((10, modelSize[1] - annoHeight - 10), annotationTxt, fill=black, font=font)


	if currentTstr:
		#timestamp in lower right corner
		annoHeight = canvas.textsize(currentTstr, font)[1]
		annoWidth = canvas.textsize(currentTstr, font)[0]
		canvas.text((modelSize[0] - annoWidth - 10, modelSize[1] - annoHeight - 10), currentTstr, fill=black, font=font)

	#add postprocessing timestamp
	timestamp = strftime("%b-%d-%Y %H:%M:%S")
	annoHeight = canvas.textsize(timestamp, font)[1]
	annoWidth = canvas.textsize(timestamp, font)[0]
	canvas.text((modelSize[0] - annoWidth - 10, annoHeight - 5), timestamp, fill=du.grey, font=font)




#end
