/* Copyright (C) 2007  Mikko Sysikaski <mikko.sysikaski@gmail.com>
 * This program is free software distributed under GNU General Public License
 * version 3 or (at your option) any later version.
 * No warranty of any kind is provided. See the accompanying file COPYING for details.
 */

#include "SDL.h"
#include "drawer.h"
#include <algorithm>

namespace {
SDL_Surface* screen;
int dragPlaceH=-1;
int dragPlaceV=-1;
int dragStartH=-1;
int dragStartV=-1;
};

using std::max;
using std::min;

void initScreen(int w, int h)
{
	screen = SDL_SetVideoMode(w, h, 0, SDL_SWSURFACE | SDL_RESIZABLE);
}

inline
int toBorder(int x, int start, int pps)
{
	return (x + pps/2 + start) / pps * pps - start;
}

inline Uint32 RGB(Uint8 r, Uint8 g, Uint8 b)
{
	return SDL_MapRGB(screen->format, r, g, b);
}

void draw(const Board& b, int xplace, int yplace, int pps)
{
	SDL_FillRect(screen, 0, RGB(0, 0xaa, 0));
	if (SDL_MUSTLOCK(screen))
		SDL_LockSurface(screen);
	
	// draw lines between squares
	for(int y=0; y<=b.getY(); ++y) {
		SDL_Rect rect;
		rect.w = pps*b.getX();
		rect.h = 1;
		rect.x = -xplace;
		rect.y = y*pps-yplace;
		SDL_FillRect(screen, &rect, 0);
	}
	for(int x=0; x<=b.getX(); ++x) {
		SDL_Rect rect;
		rect.w = 1;
		rect.h = pps*b.getY();
		rect.x = x*pps-xplace;
		rect.y = -yplace;
		SDL_FillRect(screen, &rect, 0);
	}
	
	// draw holes and starting point
	int size = pps*2/3;
	int offset = (pps-size)/2;
	for(int y=0; y<b.getY(); ++y) {
		for(int x=0; x<b.getX(); ++x) {
			SDL_Rect rect = {x*pps-xplace+offset, y*pps-yplace+offset, size, size};
			switch (b.getBlock(y,x)) {
				case HOLE:
					SDL_FillRect(screen, &rect, 0);
					break;
				case END:
					SDL_FillRect(screen, &rect, RGB(0x22, 0xff, 0x22));
					break;
				case START:
					SDL_FillRect(screen, &rect, RGB(0xff, 0xff, 0));
					break;
					case SHOLE: {
						SDL_Rect r = {x*pps-xplace, y*pps-yplace, pps, pps};
						SDL_FillRect(screen, &r, 0);
					} break;
				default:
					break;
			}
		}
	}

	const int DIAG_SPLIT = 10;
	int squareDiff = pps/DIAG_SPLIT;
	
	// draw blocks
	offset = pps/4/2;
	Uint32 wallColor = RGB(0xaa, 0xaa, 0);
	for(int y=0; y<b.getY(); ++y) {
		for(int x=0; x<b.getX(); ++x) {
			char tmp = b[y][x];
			if (tmp&1) {
				SDL_Rect horiz = {x*pps-xplace, (y+1)*pps-yplace-offset, pps, pps/4};
				SDL_FillRect(screen, &horiz, wallColor);
			}
			if (tmp&2) {
				SDL_Rect vert = {(x+1)*pps-xplace-offset, y*pps-yplace, pps/4, pps};
				SDL_FillRect(screen, &vert, wallColor);
			}
			if (tmp&4) {
				for(int i=0; i<DIAG_SPLIT; ++i) {
					SDL_Rect square = {x*pps-xplace+squareDiff*i, y*pps-yplace+squareDiff*i,
					                   squareDiff*2, squareDiff*2};
					SDL_FillRect(screen, &square, wallColor);
				}
			}
			if (tmp&8) {
				for(int i=0; i<DIAG_SPLIT; ++i) {
					SDL_Rect square = {(x+1)*pps-xplace-squareDiff*i, y*pps-yplace+squareDiff*i,
						squareDiff*2, squareDiff*2};
						SDL_FillRect(screen, &square, wallColor);
				}
			}
		}
	}
	// draw walls
	{
		SDL_Rect tmp;
		tmp.x=-xplace; tmp.y=-yplace-offset; tmp.w=b.getX()*pps; tmp.h=pps/4;
		SDL_FillRect(screen, &tmp, wallColor);
		tmp.x=-xplace-offset; tmp.y=-yplace; tmp.w=pps/4; tmp.h=b.getY()*pps;
		SDL_FillRect(screen, &tmp, wallColor);
		tmp.x=-xplace; tmp.y=b.getY()*pps-yplace-offset; tmp.w=b.getX()*pps; tmp.h=pps/4;
		SDL_FillRect(screen, &tmp, wallColor);
		tmp.x=b.getX()*pps-xplace-offset; tmp.y=-yplace; tmp.w=pps/4; tmp.h=b.getY()*pps;
		SDL_FillRect(screen, &tmp, wallColor);
	}
	
	// draw dragging planes
	Uint32 startColor = RGB(0xbb, 0, 0), endColor = RGB(0xff, 0, 0);
	if (dragPlaceH != -1) {
		dragPlaceH = toBorder(dragPlaceH, yplace, pps);
		dragStartH = toBorder(dragStartH, yplace, pps);
		
		SDL_Rect plane;// = {-xplace, dragPlaceH-1, b.getX()*pps, 3};
		plane.x = -xplace; plane.y = dragStartH-1; plane.w = b.getX()*pps; plane.h = 3;
		SDL_FillRect(screen, &plane, startColor);
		plane.x = -xplace; plane.y = dragPlaceH-1; plane.w = b.getX()*pps; plane.h = 3;
		SDL_FillRect(screen, &plane, endColor);
	}
	if (dragPlaceV != -1) {
		dragPlaceV = toBorder(dragPlaceV, xplace, pps);
		dragStartV = toBorder(dragStartV, xplace, pps);
		
		SDL_Rect plane;// = {dragPlaceV-1, -yplace, 3, b.getY()*pps};
		plane.x = dragStartV-1; plane.y = -yplace; plane.w = 3; plane.h = b.getY()*pps;
		SDL_FillRect(screen, &plane, startColor);
		plane.x = dragPlaceV-1; plane.y = -yplace; plane.w = 3; plane.h = b.getY()*pps;
		SDL_FillRect(screen, &plane, endColor);
	}
	
	if (SDL_MUSTLOCK(screen))
		SDL_UnlockSurface(screen);
}

void horizDrag(int start, int place)
{
	dragStartH = start;
	dragPlaceH = place;
}
void vertDrag(int start, int place)
{
	dragStartV = start;
	dragPlaceV = place;
}
void endWallDrag()
{
	dragPlaceH = dragPlaceV = -1;
}

SDL_Surface* getScreen()
{
	return screen;
}

void endDraw()
{
	SDL_Flip(screen);
}
