/* 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 "modifiableboard.h"
#include "drawer.h"
#include "dialog.h"
#include <stdio.h>
#include <string>
#include "SDL.h"

std::string filename;
void parseArgs(int argc, char* argv[]);
void eventLoop();
void processEvent(SDL_Event& e);

ModifiableBoard board;
int xplace=0, yplace=0;
int pps=40;
bool dragging=0;
bool wallDragV=0, wallDragH=0;
int startDragV, startDragH;
int mouseX, mouseY;

int main(int argc, char* argv[])
{
	parseArgs(argc, argv);
	SDL_Init(SDL_INIT_VIDEO);
	startDialog("Vera.ttf", 24);
	initScreen(640, 480);
	board.load(filename.c_str());
	if (!board.loaded()) {
		printf("Creating new board\n");
		board.create(2, 2);
		board.setBlock(0, 0, START);
		board.setBlock(1, 1, END);
	}
	
	SDL_Event e;
	while(1) {
		if (!SDL_WaitEvent(&e)) {
			fprintf(stderr, "Error waiting for sdl events\n");
			break;
		}
		processEvent(e);
		if (wallDragV)
			vertDrag(startDragV, mouseX);
		if (wallDragH)
			horizDrag(startDragH, mouseY);
		draw(board, xplace, yplace, pps);
		endDraw();
	}

	endDialog();
	SDL_Quit();
}

void mouseDown(SDL_MouseButtonEvent& e)
{
	if (e.button == SDL_BUTTON_LEFT) {
		dragging = 1;
		mouseX = e.x;
		mouseY = e.y;
		return;
	} else if (e.button==SDL_BUTTON_RIGHT || e.button==SDL_BUTTON_MIDDLE) {
		int x = (e.x+xplace+pps/2)/pps;
		int y = (e.y+yplace+pps/2)/pps;
		
		if (x<0 || y<0 || x>board.getX() || y>board.getY())
			return;
		
		wallDragH = 1;
		startDragH = mouseY;
		wallDragV = 1;
		startDragV = mouseX;
	} else if (e.button == SDL_BUTTON_WHEELUP) {
		pps += 5;
	} else if (e.button == SDL_BUTTON_WHEELDOWN) {
		pps -= 5;
		if (pps < 5)
			pps = 5;
	}
}
void mouseUp(SDL_MouseButtonEvent& e)
{
	if (e.button == SDL_BUTTON_LEFT) {
		dragging = 0;
		return;
	} else if (e.button == SDL_BUTTON_MIDDLE || e.button == SDL_BUTTON_RIGHT) {
		if (wallDragV) {
			int start = (startDragV+pps/2+xplace)/pps;
			int end = (e.x+pps/2+xplace)/pps;
			if (start < end) {
				board.insertColumns(start, end-start);
			} else if (start > end) {
				board.deleteColumns(end, start-end);
			}
		}
		if (wallDragH) {
			int start = (startDragH+pps/2+yplace)/pps;
			int end = (e.y+pps/2+yplace)/pps;
			if (start < end) {
				board.insertRows(start, end-start);
			} else if (start > end) {
				board.deleteRows(end, start-end);
			}
		}
		wallDragV = wallDragH = 0;
		endWallDrag();
	}
}
void mouseMove(SDL_MouseMotionEvent& e)
{
	if (dragging) {
		xplace += mouseX-e.x;
		yplace += mouseY-e.y;
	}
	mouseX = e.x;
	mouseY = e.y;
}
inline void blockSet(int y, int x, BlockT block)
{
	if (y < 0 || x < 0 || y >= board.getY() || x >= board.getX())
		return;
	board.setBlock(y, x, block);
}
void keyDown(SDL_KeyboardEvent& e)
{
	int x = (mouseX+xplace)/pps;
	int y = (mouseY+yplace)/pps;
	switch(e.keysym.sym) {
		case '1':
			blockSet(y, x, EMPTY); break;
		case '2':
			blockSet(y, x, HOLE); break;
		case '3':
			blockSet(y, x, SHOLE); break;
		case '4':
			blockSet(y, x, END); break;
		case '5':
			blockSet(y, x, START); break;
		case 'w':
			if (y > 0)
				board.toggleWall(y-1, x, ModifiableBoard::DOWN);
			break;
		case 'a':
			if (x > 0)
				board.toggleWall(y, x-1, ModifiableBoard::LEFT);
			break;
		case 'd':
			if (x < board.getX()-1)
				board.toggleWall(y, x, ModifiableBoard::LEFT);
			break;
		case 's':
			if (e.keysym.mod & KMOD_CTRL) {
				if (!savePath(filename, board, xplace, yplace, pps))
					return;
				printf("Saving to %s\n", filename.c_str());
				board.save(filename.c_str());
			} else {
				if (y < board.getY()-1)
					board.toggleWall(y, x, ModifiableBoard::DOWN);
			}
			break;
		case 'q':
			if (e.keysym.mod & KMOD_CTRL) {
				SDL_Quit();
				exit(0);
			}
			board.toggleWall(y, x, ModifiableBoard::BSLASH);
			break;
		case 'e':
			board.toggleWall(y, x, ModifiableBoard::SLASH);
			break;
		case 't':
			board.setTime(askTime(board.getMinTime(), board, xplace, yplace, pps));
			break;
		default:
			break;
	}
}

void processEvent(SDL_Event& e)
{
	switch(e.type) {
		case SDL_QUIT:
			exit(0);
		case SDL_MOUSEBUTTONDOWN:
			mouseDown(e.button);
			break;
		case SDL_MOUSEBUTTONUP:
			mouseUp(e.button);
			break;
		case SDL_MOUSEMOTION:
			mouseMove(e.motion);
			break;
		case SDL_KEYDOWN:
			keyDown(e.key);
			break;
		case SDL_VIDEORESIZE:
			initScreen(e.resize.w, e.resize.h);
			break;
		default:
			break;
	}
}

void parseArgs(int argc, char* argv[])
{
	if (argc > 1)
		filename = argv[1];
}
