/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include "xeen/dialogs_automap.h"
#include "xeen/resources.h"
#include "xeen/xeen.h"

namespace Xeen {


void AutoMapDialog::show(XeenEngine *vm) {
	AutoMapDialog *dlg = new AutoMapDialog(vm);
	dlg->execute();
	delete dlg;
}

void AutoMapDialog::execute() {
	Screen &screen = *_vm->_screen;
	EventsManager &events = *_vm->_events;
	Interface &intf = *_vm->_interface;
	Map &map = *_vm->_map;
	Party &party = *_vm->_party;
	int frame2 = intf._overallFrame * 2;
	bool frameEndFlag = false;

	Common::Point pt = party._mazePosition;
	Common::Point arrowPt;
	SpriteResource globalSprites;
	globalSprites.load("global.icn");

	if (pt.x < 8 && map.mazeData()._surroundingMazes._west == 0) {
		arrowPt.x = pt.x * 10 + 4;
	} else if (pt.x > 23) {
		arrowPt.x = pt.x * 10 + 100;
		pt.x = 23;
	} else if (pt.x > 8 && map.mazeData()._surroundingMazes._east == 0) {
		arrowPt.x = pt.x * 10 + 4;
		pt.x = 7;
	} else {
		arrowPt.x = 74;
	}

	if (pt.y < 8 && map.mazeData()._surroundingMazes._south == 0) {
		arrowPt.y = ((15 - pt.y) << 3) + 13;
		pt.y = 8;
	} else if (pt.y > 24) {
		arrowPt.y = ((15 - (pt.y - 24)) << 3) + 13;
		pt.y = 24;
	} else if (pt.y >= 8 && map.mazeData()._surroundingMazes._north == 0) {
		arrowPt.y = ((15 - pt.y) << 3) + 13;
		pt.y = 8;
	} else {
		arrowPt.y = 69;
	}

	screen._windows[5].open();
//	MazeData &mazeData = map.mazeDataCurrent();
	bool drawFlag = true;
	int v;

	events.updateGameCounter();
	do {
		if (drawFlag)
			intf.draw3d(false);
		screen._windows[5].writeString("\n");

		if (map._isOutdoors) {
			// Draw outdoors map
			for (int yp = 38, yDiff = pt.y + 7; pt.y < 166; --yDiff, yp += 8) {
				for (int xp = 80, xDiff = pt.x - 7; xp < 240; xp += 10, ++xDiff) {
					v = map.mazeLookup(Common::Point(xDiff, yDiff), 0);

					if (map._currentSteppedOn) {
						map._tileSprites.draw(screen, map.mazeDataCurrent()._surfaceTypes[v],
							Common::Point(xp, yp));
					}
				}
			}

			for (int yp = 38, yDiff = pt.y + 7; yp < 166; --yDiff, yp += 8) {
				for (int xp = 80, xDiff = pt.x - 7; xp < 240; xp += 10, ++xDiff) {
					v = map.mazeLookup(Common::Point(xDiff, yDiff), 4);
					int wallType = map.mazeDataCurrent()._wallTypes[v];

					if (wallType && map._currentSteppedOn)
						map._tileSprites.draw(screen, wallType, Common::Point(xp, yp));
				}
			}


			for (int yp = 38, yDiff = pt.y + 7; yp < 166; yp += 8, --yDiff) {
				for (int xp = 80, xDiff = -7; xp < 240; xp += 10, ++xDiff) {
					v = map.mazeLookup(Common::Point(xDiff, yDiff), 8);

					if (v && map._currentSteppedOn)
						map._tileSprites.draw(screen, 1, Common::Point(xp, yp));
				}
			}
		} else {
			// Draw indoors map
			frame2 = (frame2 + 2) % 8;

			// Draw default ground for all the valid explored areas
			for (int yp = 38, yDiff = pt.y + 7; yp < 166; yp += 8, --yDiff) {
				for (int xp = 80, xDiff = pt.x - 7; xp < 240; xp += 10, ++xDiff) {
					v = map.mazeLookup(Common::Point(xDiff, yDiff), 0, 0xffff);

					if (v != INVALID_CELL && map._currentSteppedOn)
						map._tileSprites.draw(screen, 0, Common::Point(xp, yp));
				}
			}

			// Draw thinner ground tiles on the left edge of the map
			for (int yp = 43, yDiff = pt.y + 7; yp < 171; yp += 8, --yDiff) {
				v = map.mazeLookup(Common::Point(pt.x - 8, yDiff), 0, 0xffff);

				if (v != INVALID_CELL && map._currentSurfaceId != 0 && map._currentSteppedOn)
					map._tileSprites.draw(screen, 36 + map.mazeData()._surfaceTypes[
						map._currentSurfaceId], Common::Point(75, yp));
			}

			// Draw thin tile portion on top-left corner of map
			v = map.mazeLookup(Common::Point(pt.x - 8, pt.y + 8), 0, 0xffff);
			if (v != INVALID_CELL && map._currentSurfaceId != 0 && map._currentSteppedOn)
				map._tileSprites.draw(screen, 36 + map.mazeData()._surfaceTypes[
					map._currentSurfaceId], Common::Point(75, 35));

			// Draw any thin tiles at the very top of the map
			for (int xp = 85, xDiff = pt.x - 7; xp < 245; xp += 10, ++xDiff) {
				v = map.mazeLookup(Common::Point(xDiff, pt.y + 8), 0, 0xffff);

				if (v != INVALID_CELL && map._currentSurfaceId != 0 && map._currentSteppedOn)
					map._tileSprites.draw(screen, 36 + map.mazeData()._surfaceTypes[
						map._currentSurfaceId], Common::Point(xp, 35));
			}

			// Draw the default ground tiles
			for (int yp = 43, yDiff = pt.y + 7; yp < 171; yp += 8, --yDiff) {
				for (int xp = 85, xDiff = pt.x - 7; xp < 245; xp += 10, ++xDiff) {
					v = map.mazeLookup(Common::Point(xDiff, yDiff), 0, 0xffff);

					if (v != INVALID_CELL && map._currentSurfaceId && map._currentSteppedOn)
						map._tileSprites.draw(screen, map.mazeData()._surfaceTypes[
							map._currentSurfaceId], Common::Point(xp, yp));
				}
			}

			// Draw walls on left and top edges of map
			for (int xp = 80, yp = 158, xDiff = pt.x - 7, yDiff = pt.y - 8; xp < 250;
					xp += 10, yp -= 8, ++xDiff, ++yDiff) {
				// Draw walls on left edge of map
				v = map.mazeLookup(Common::Point(pt.x - 8, yDiff), 12);

				int frame;
				switch (v) {
				case SURFTYPE_DIRT:
					frame = 18;
					break;
				case SURFTYPE_SNOW:
					frame = 22;
					break;
				case SURFTYPE_SWAMP:
				case SURFTYPE_CLOUD:
					frame = 16;
					break;
				case SURFTYPE_LAVA:
				case SURFTYPE_DWATER:
					frame = 2;
					break;
				case SURFTYPE_DESERT:
					frame = 30;
					break;
				case SURFTYPE_ROAD:
					frame = 32;
					break;
				case SURFTYPE_TFLR:
					frame = 20;
					break;
				case SURFTYPE_SKY:
					frame = 28;
					break;
				case SURFTYPE_CROAD:
					frame = 14;
					break;
				case SURFTYPE_SEWER:
					frame = frame2 + 4;
					break;
				case SURFTYPE_SCORCH:
					frame = 24;
					break;
				case SURFTYPE_SPACE:
					frame = 26;
					break;
				default:
					frame = -1;
					break;
				}

				if (frame != -1 && map._currentSteppedOn)
					map._tileSprites.draw(screen, frame, Common::Point(70, yp));

				// Draw walls on top edge of map
				v = map.mazeLookup(Common::Point(xDiff, pt.y + 8), 0);

				switch (v) {
				case SURFTYPE_DIRT:
					frame = 19;
					break;
				case SURFTYPE_GRASS:
					frame = 35;
					break;
				case SURFTYPE_SNOW:
					frame = 23;
					break;
				case SURFTYPE_SWAMP:
				case SURFTYPE_CLOUD:
					frame = 17;
					break;
				case SURFTYPE_LAVA:
				case SURFTYPE_DWATER:
					frame = 3;
					break;
				case SURFTYPE_DESERT:
					frame = 31;
					break;
				case SURFTYPE_ROAD:
					frame = 33;
					break;
				case SURFTYPE_TFLR:
					frame = 21;
					break;
				case SURFTYPE_SKY:
					frame = 29;
					break;
				case SURFTYPE_CROAD:
					frame = 15;
					break;
				case SURFTYPE_SEWER:
					frame = frame2 + 5;
					break;
				case SURFTYPE_SCORCH:
					frame = 25;
					break;
				case SURFTYPE_SPACE:
					frame = 27;
					break;
				default:
					frame = -1;
					break;
				}

				if (frame != -1 && map._currentSteppedOn)
					map._tileSprites.draw(screen, frame, Common::Point(xp, 30));
			}

			// Draw any walls on the cells
			for (int yCtr = 0, yp = 38, yDiff = pt.y + 7; yCtr < 16; ++yCtr, yp += 8, --yDiff) {
				for (int xCtr = 0, xp = 80, xDiff = pt.x - 7; xCtr < 16; ++xCtr, xp += 10, ++xDiff) {
					// Draw the arrow if at the correct position
					if ((arrowPt.x / 10) == xCtr && (14 - (arrowPt.y / 10)) == yCtr && frameEndFlag) {
						globalSprites.draw(screen, party._mazeDirection + 1,
							Common::Point(arrowPt.x + 81, arrowPt.y + 29));
					}

					v = map.mazeLookup(Common::Point(xDiff, yDiff), 12);
					int frame;
					switch (v) {
					case SURFTYPE_DIRT:
						frame = 18;
						break;
					case SURFTYPE_GRASS:
						frame = 34;
						break;
					case SURFTYPE_SNOW:
						frame = 22;
						break;
					case SURFTYPE_SWAMP:
					case SURFTYPE_CLOUD:
						frame = 16;
						break;
					case SURFTYPE_LAVA:
					case SURFTYPE_DWATER:
						frame = 2;
						break;
					case SURFTYPE_DESERT:
						frame = 30;
						break;
					case SURFTYPE_ROAD:
						frame = 32;
						break;
					case SURFTYPE_TFLR:
						frame = 20;
						break;
					case SURFTYPE_SKY:
						frame = 28;
						break;
					case SURFTYPE_CROAD:
						frame = 14;
						break;
					case SURFTYPE_SEWER:
						frame = frame2 + 4;
						break;
					case SURFTYPE_SCORCH:
						frame = 24;
						break;
					case SURFTYPE_SPACE:
						frame = 26;
						break;
					default:
						frame = -1;
						break;
					}

					if (frame != -1 && map._currentSteppedOn)
						map._tileSprites.draw(screen, frame, Common::Point(xp, yp));

					v = map.mazeLookup(Common::Point(xDiff, yDiff), 0);
					switch (v) {
					case SURFTYPE_DIRT:
						frame = 19;
						break;
					case SURFTYPE_GRASS:
						frame = 35;
						break;
					case SURFTYPE_SNOW:
						frame = 23;
						break;
					case SURFTYPE_SWAMP:
					case SURFTYPE_CLOUD:
						frame = 17;
						break;
					case SURFTYPE_LAVA:
					case SURFTYPE_DWATER:
						frame = 3;
						break;
					case SURFTYPE_DESERT:
						frame = 31;
						break;
					case SURFTYPE_ROAD:
						frame = 33;
						break;
					case SURFTYPE_TFLR:
						frame = 21;
						break;
					case SURFTYPE_SKY:
						frame = 29;
						break;
					case SURFTYPE_CROAD:
						frame = 15;
						break;
					case SURFTYPE_SEWER:
						frame = frame2 + 5;
						break;
					case SURFTYPE_SCORCH:
						frame = 25;
						break;
					case SURFTYPE_SPACE:
						frame = 27;
						break;
					default:
						frame = -1;
						break;
					}

					if (frame != -1 && map._currentSteppedOn)
						map._tileSprites.draw(screen, frame, Common::Point(xp, yp));
				}
			}

			// Draw overlay on cells that haven't been stepped on yet
			for (int yDiff = pt.y + 7, yp = 38; yp < 166; --yDiff, yp += 8) {
				for (int xp = 80, xDiff = pt.x - 7; xp < 240; xp += 10, ++xDiff) {
					v = map.mazeLookup(Common::Point(xDiff, yDiff), 0, 0xffff);

					if (v == INVALID_CELL || !map._currentSteppedOn)
						map._tileSprites.draw(screen, 1, Common::Point(xp, yp));
				}
			}
		}

		screen._windows[5].frame();
		if (!map._isOutdoors) {
			map._tileSprites.draw(screen, 52, Common::Point(76, 30));
		} else if (frameEndFlag) {
			globalSprites.draw(screen, party._mazeDirection + 1,
				Common::Point(arrowPt.x + 76, arrowPt.y + 25));
		}

		if (events.timeElapsed() > 5) {
			// Set the flag to make the basic arrow blinking effect
			frameEndFlag = !frameEndFlag;
			events.updateGameCounter();
		}

		screen._windows[5].writeString(Common::String::format(Res.MAP_TEXT,
			map._mazeName.c_str(), party._mazePosition.x,
			party._mazePosition.y, Res.DIRECTION_TEXT[party._mazeDirection]));
		screen._windows[5].update();
		screen._windows[3].update();

		events.pollEvents();
		drawFlag = false;
	} while (!_vm->shouldQuit() && !events.isKeyMousePressed());

	events.clearEvents();
	screen._windows[5].close();
}

} // End of namespace Xeen