implementation module graphics


import	StdInt, StdBool, StdReal, StdChar, StdList, StdFunc, StdEnum, StdArray, StdTuple, StdMisc, StdOrdList
import	StdControl, StdPicture
import	board, language, systemsettings


rbBoardGrey			:== RGB {r=191,g=191,b=191}			// The background colour of the board
rbLighterGrey		:== RGB {r=224,g=224,b=224}
rbBoardRed3			:== RGB {r=255,g=127,b=127}
rbBoardRed2			:== RGB {r=191,g=160,b=160}
rbBoardBlue3		:== RGB {r=127,g=127,b=255}
rbBoardBlue2		:== RGB {r=159,g=159,b=191}
rbSquare			:== RGB {r=255,g=255,b=191}
rbDarkYellow		:== RGB {r=127,g=127,b=0  }

displaywidth		:==	2+250+2
displayheight		:==	2+130+2
boardwidth			:==	391
boardheight			:==	391
squarewidth			::	Int
squarewidth			=:	boardwidth/15
squareheight		::	Int
squareheight		=:	boardheight/15

alphabet			:==	"abcdefghijklmnopqrstuvwxyz"


/*	Mapping 'Amanda-space' to 'Scrabble-space' to 'Pixel-space':
	Amanda-space	: ((-1.0,1.0),(1.0,-1.0))
	Scrabble-space	: ((0.0,0.0), (14.0,14.0))
	Pixel-space		: ((0,0), (width,height))
*/

abs2rel :: !(!Int,!Int) -> (!Int,!Int)
abs2rel (x,y) = (x/squarewidth,y/squareheight)


/*	The drawing operations.	*/

/*	The look of the board.
	It is assumed that the background is set to rbBoardGrey.
*/
boardlook :: !Board Point2 !SelectState !UpdateState !*Picture -> *Picture
boardlook (hor,_) cstate select updState=:{newFrame} picture
	# picture	= setPenColour	White picture
	# picture	= seq [ drawAt {x=squarewidth*i+1,y=0}  {zero & vy=h} \\ i<-is ] picture
	# picture	= seq [ drawAt {x=0,y=squareheight*i+1} {zero & vx=w} \\ i<-is ] picture
	# picture	= setPenColour DarkGrey picture
	# picture	= seq [ drawAt {x=squarewidth*i,y=1}  {zero & vy=h-1} \\ i<-is ] picture
	# picture	= seq [ drawAt {x=1,y=squareheight*i} {zero & vx=w-1} \\ i<-is ] picture
	# picture	= seq (map (drawsquare rbBoardBlue2) doubleletterpositions) picture
	# picture	= seq (map (drawsquare rbBoardBlue3) tripleletterpositions) picture
	# picture	= seq (map (drawsquare rbBoardRed2)  doublewordpositions)   picture
	# picture	= seq (map (drawsquare rbBoardRed3)  triplewordpositions)   picture
	# picture	= drawcenter picture
	# picture	= seq [ drawletter l (i,j) \\ i<-[0..14], j<-[0..14], l<-[(hor!!j)!!i] ] picture
	| enabled select
		= drawfocus True cstate picture
	| otherwise
		= picture
where
	{w,h}		= rectangleSize newFrame
	is			= [0..15]
	
	drawcenter :: *Picture -> *Picture
	drawcenter picture
		# picture	= drawsquare rbBoardGrey (7,7) picture
		# picture	= setPenColour Grey picture
		# picture	= fillAt (absposition (7.5,7.5)) {polygon_shape=shape} picture
		= picture
	where
		h		= (squarewidth-1)/2
		v		= (squareheight-1)/2
		shape	= [{zero & vy=0-v},{vx=h,vy=v},{vx=0-h,vy=v},{vx=0-h,vy=0-v},{vx=h,vy=0-v}]
	
	//	absposition maps a position in 'Scrabble-space' to a position in 'Pixel-space'.
		absposition :: !(!Real,!Real) -> Point2
		absposition (col,row)
			= {x=toInt (col*toReal squarewidth),y=toInt (row*toReal squareheight)}
	
	drawsquare :: !Colour !(!Int,!Int) !*Picture -> *Picture
	drawsquare colour (col,row) picture
		# picture	= setPenColour colour picture
		# picture	= fill {corner1={x=l,y=t},corner2={x=r,y=b}} picture
		= picture
	where
		l =  col    * squarewidth+2
		t =  row    * squareheight+2
		r = (col+1) * squarewidth
		b = (row+1) * squareheight

drawfocus :: !Bool !Point2 !*Picture -> *Picture
drawfocus notErase {x,y} picture
	# picture	= setPenColour	lefttopcolour                picture
	# picture	= setPenPos		{x=l,y=b}                    picture
	# picture	= draw			{vx=0,vy=0-(squareheight-1)} picture
	# picture	= draw			{vx=squarewidth-1,vy=0}      picture
	# picture	= setPenColour  rightbotcolour               picture
	# picture	= draw			{vx=0,vy=squareheight-1}     picture
	# picture	= draw			{vx=0-(squarewidth-1),vy=0}  picture
	= picture
where
	(col,row)						= abs2rel (x,y)
	l								= col*squarewidth+1
	b								= (row+1)*squareheight
	(lefttopcolour,rightbotcolour)	= if notErase (DarkGrey, White)
												  (White, DarkGrey)


drawletter :: !Char !(!Int,!Int) !*Picture -> *Picture
drawletter ' ' _ picture
	= picture
drawletter l (i,j) picture
	# ((_,sfont),picture)	= openFont smallfont picture
	# ((_,lfont),picture)	= openFont letterfont picture
	# (plen,picture)		= getFontStringWidth sfont scoretext										picture
	# picture				= setPenColour	rbSquare													picture
	# picture				= fill	{corner1={x=x+2,y=y+2},corner2={x=x+squarewidth,y=y+squareheight}}	picture
	# picture				= setPenPos		{x=x+2,y=y+squareheight-1}									picture
	# picture				= setPenColour	White														picture
	# picture				= drawLineTo	{x=x+2,y=y+2}												picture
	# picture				= drawLineTo	{x=x+squarewidth-1,y=y+2}									picture
	# picture				= setPenColour	Yellow														picture
	# picture				= drawLineTo	{x=x+squarewidth-1,y=y+squareheight-1}						picture
	# picture				= drawLineTo	{x=x+2,y=y+squareheight-1}									picture
	# picture				= setPenPos		{x=x+squarewidth/4,y=y+h-h/3}								picture
	# picture				= setPenFont	lfont														picture
	# picture				= setPenColour	Black														picture
	# picture				= draw			(toUpper l)													picture
	# picture				= setPenFont	sfont														picture
	# picture				= setPenColour	rbDarkYellow												picture
	# picture				= drawAt		{x=x+squarewidth-2-plen,y=y+h-3} scoretext					picture
	= picture
where
	x						= i*squarewidth
	y						= j*squareheight
	h						= squareheight
	scoretext				= toString (lettervalue l)


redrawboard :: !Id !Board Point2 !(IOSt .l) -> IOSt .l
redrawboard boardId board pos iostate
	= setControlLook boardId True (True,boardlook board pos) iostate

/*	letterboxlook is the look of the set of remaining letters.
	It is assumed that it has the background colour rbBackground.
*/
letterboxlook :: ![Char] SelectState UpdateState !*Picture-> *Picture
letterboxlook letters _ {newFrame} picture
	# picture				= unfill newFrame picture
	# picture				= seq [ drawletter c (0,j) \\ (c,j)<-zip2 leftchars  js ] picture
	# picture				= seq [ drawletter c (2,j) \\ (c,j)<-zip2 rightchars js ] picture
	# ((_,lfont),picture)	= openFont letterfont picture
	# picture				= setPenFont   lfont  picture
	# picture				= setPenColour Black  picture
	# picture				= seq [ drawcount c (1,j) \\ (c,j)<-zip2 leftcounts  js ] picture
	# picture				= seq [ drawcount c (3,j) \\ (c,j)<-zip2 rightcounts js ] picture
	= picture
where
	js						= [0..14]
	counts					= countletters alphabet (sort letters)
	(left,right)			= splitAt 15 counts
	(leftchars, leftcounts)	= unzip left
	(rightchars,rightcounts)= unzip right
	
	drawcount :: !Int !(!Int,!Int) !*Picture -> *Picture
	drawcount count (i,j) picture
		= drawAt {x=x+squarewidth/4,y=y+h-h/3} (toString count) picture
	where
		x = i*squarewidth
		y = j*squareheight
		h = squareheight
	
	countletters :: !String ![Char] -> [(Char,Int)]
	countletters chars letters
		| chars==""
			= []
		| otherwise
			# c					= chars.[0]
			  (count,letters)	= countletter c letters
			= [(c,count):countletters (chars%(1,size chars-1)) letters]
	where
		countletter :: !Char ![Char] -> (Int,![Char])
		countletter c all_letters=:[letter:letters]
			| c<>letter
				= (0,all_letters)
			| otherwise
				# (count,letters)	= countletter c letters
				= (count+1,letters)
		countletter _ _
			= (0,[])

drawletterbox :: !Id ![Char] !(IOSt .l) -> IOSt .l
drawletterbox letterboxId letters iostate
	= setControlLook letterboxId True (True,letterboxlook letters) iostate

drawplayer1letters :: !Id ![Char] !(IOSt .l) -> IOSt .l
drawplayer1letters letters1Id letters iostate
	= setControlLook letters1Id True (True,playerletterslook letters) iostate

drawplayer2letters :: !Id ![Char] !(IOSt .l) -> IOSt .l
drawplayer2letters letters2Id letters iostate
	= setControlLook letters2Id True (True,playerletterslook letters) iostate

playerletterslook :: ![Char] SelectState UpdateState !*Picture -> *Picture
playerletterslook ws _ {newFrame} picture
	= seq [	drawletter c (i,0) \\ c<-ws & i<-[0..] ] (unfill newFrame picture)

drawplayer1score :: !Id !Int !(IOSt .l) -> IOSt .l
drawplayer1score player1scoreId s iostate
	= setControlText player1scoreId (toString s) iostate

drawplayer2score :: !Id !Int !(IOSt .l) -> IOSt .l
drawplayer2score player2scoreId s iostate
	= setControlText player2scoreId (toString s) iostate

drawcommunication :: !Id ![String] !(IOSt .l) -> IOSt .l
drawcommunication displayId text iostate
	= setControlLook displayId True (True,displaylook text) iostate

displaylook :: ![String] SelectState !UpdateState !*Picture -> *Picture		// displaylook assumes PictureDomain
																			// {{-2,-2},{w+2,h+2}}
displaylook text _ {newFrame} picture
	# picture				= unfill       newFrame     picture
	# picture				= drawdisplay  size			picture
	# ((_,font12),picture)	= openFont     (font 12)	picture
	# picture				= setPenFont   font12		picture
	# picture				= setPenColour Red			picture
	# picture				= seq [ drawAt {x=2+w/20,y=2+h*y/10} l \\ (y,l)<-zip2 [2,4..] text ] picture
	= picture
where
	size					= rectangleSize newFrame
	{w,h}					= size

drawprogress :: !Id !Player !Progress !Placing !(IOSt .l) -> IOSt .l
drawprogress displayId player progress placing iostate
	= setControlLook displayId True (True,progresslook player progress placing {w=displaywidth,h=displayheight}) iostate
where
	progresslook :: !Player !Progress !Placing !Size SelectState UpdateState !*Picture -> *Picture
	progresslook player (Letter letter _) placing size=:{w,h} _ {newFrame} picture
		# picture				= unfill newFrame									picture
        # ((_,thefont),picture)	= openFont (font 12)								picture
		# (foundlength,picture)	= getFontStringWidth thefont found_upto_now			picture
		# (at_poslength,picture)= getFontStringWidth thefont at_pos					picture
		# (scorelength,picture)	= getFontStringWidth thefont score_upto_now			picture
		  rtabstop				= tekstindent+foundlength
		  atpos					= rtabstop - at_poslength
          scorepos				= rtabstop - scorelength
		# picture				= drawdisplay	size								picture
		# picture				= setPenFont	thefont								picture
		# picture				= setPenColour	Grey								picture
		# picture				= drawAt		letterspos alphabet					picture
		# picture				= setPenColour	Green								picture
		# picture				= drawAt		letterspos alphabet_l_incl			picture
		# picture				= setPenColour	Red									picture
		# picture				= drawAt		letterspos alphabet_l_excl			picture
		# picture				= setPenColour	Green								picture
		# picture				= drawAt		{x=tekstindent,y=toInt (0.15*h`)} (toString player+++determines_new_word) picture
		# picture				= setPenPos		{x=foundpos,   y=toInt (0.60*h`)}	picture
		# picture				= draw			found_upto_now						picture
		# picture				= movePenPos	{vx=10,vy=0}						picture
		# picture				= draw			placing.word						picture
		# picture				= setPenPos		{x=atpos,      y=toInt (0.75*h`)}	picture
		# picture				= draw			at_pos								picture
		# picture				= movePenPos	{vx=10,vy=0}						picture
		# picture				= draw			placingtext							picture
		# picture				= setPenPos		{x=scorepos,   y=toInt (0.90*h`)}	picture
		# picture				= draw			score_upto_now						picture
		# picture				= movePenPos	{vx=10,vy=0}						picture
		# picture				= draw			(toString placing.score)			picture
		= picture
	where
		(x,y)					= placing.pos
		foundpos				= tekstindent
		
		w`						= toReal w
		h`						= toReal h
		letterspos				= {x=tekstindent,y=toInt (0.35*h`)}
		tekstindent				= toInt (0.05*w`)
		
		alphabet_l_excl			= if (letter=='a') "" (alphabet%(0,l_index-1))
		alphabet_l_incl			= alphabet%(0,l_index)
		l_index					= toInt letter-a_index
		a_index					= toInt 'a'
		
		placingtext				= toString (x,y)+++" "+++toString placing.dir
	progresslook player (Finish _) placing {w,h} _ _ picture
		# picture				= setPenColour	Grey								picture
		# picture				= fill			{corner1=zero,corner2={x=w,y=h}}	picture
		# ((_,font12),picture)	= openFont		(font 12)							picture
		# picture				= setPenFont	font12								picture
		# picture				= setPenColour	Red									picture
		# picture				= drawAt		{x=toInt (0.05*w`),y=toInt (0.95*h`)} (toString player+++determined_new_word) picture
		= picture
	where
		w`						= toReal w
		h`						= toReal h

/*	drawdisplay draws the display. Note that in the 0.8 version, the domain was assumed to be {{-2,-2},{w+2,h+2}}.
	For this reason, at all coordinates {2,2} must be added.
*/
drawdisplay :: !Size !*Picture -> *Picture
drawdisplay {w,h} picture
	# picture	= setPenColour	Grey			picture
	# picture	= setPenPos		{x=1,  y=h-3}	picture
	# picture	= drawLineTo	{x=1,  y=1}		picture
	# picture	= drawLineTo	{x=w-2,y=1}		picture
	# picture	= setPenPos		{x=0,  y=h-2}	picture
	# picture	= drawLineTo	zero			picture
	# picture	= drawLineTo	{x=w-1,y=0}		picture
	# picture	= setPenColour	White			picture
	# picture	= setPenPos		{x=1,  y=h-2}	picture
	# picture	= drawLineTo	{x=w-2,y=h-2}	picture
	# picture	= drawLineTo	{x=w-2,y=0}		picture
	# picture	= setPenColour	rbLighterGrey	picture
	# picture	= setPenPos		{x=0,  y=h-1}	picture
	# picture	= drawLineTo	{x=w-1,y=h-1}	picture
	# picture	= drawLineTo	{x=w-1,y=0}		picture
	= picture
