/* ScummVM - Scumm Interpreter
 * Copyright (C) 2004 Ivan Dubrov
 * Copyright (C) 2004-2006 The ScummVM project
 *
 * 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.
 *
 * $URL: https://svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-0-9-0/engines/gob/map_v2.cpp $
 * $Id: map_v2.cpp 23100 2006-06-13 19:15:07Z drmccoy $
 *
 */

#include "common/stdafx.h"
#include "common/endian.h"
#include "common/stream.h"

#include "gob/gob.h"
#include "gob/map.h"
#include "gob/dataio.h"
#include "gob/goblin.h"
#include "gob/sound.h"
#include "gob/inter.h"
#include "gob/game.h"
#include "gob/parse.h"
#include "gob/mult.h"
#include "gob/scenery.h"

namespace Gob {

Map_v2::Map_v2(GobEngine *vm) : Map_v1(vm) {
}

Map_v2::~Map_v2() {
	_passMap = 0;
}

void Map_v2::loadMapObjects(char *avjFile) {
	int i;
	int j;
	int k;
	uint8 wayPointsCount;
	int16 var;
	int16 id;
	int16 mapHeight;
	int16 mapWidth;
	int16 tmp;
	int16 numData;
	int16 statesCount;
	int16 state;
	char *variables;
	char *extData;
	uint32 dataPos1;
	uint32 dataPos2;
	int8 statesMask[102];
	Mult::Mult_GobState *statesPtr;

	var = _vm->_parse->parseVarIndex();
	variables = _vm->_global->_inter_variables + var;

	id = _vm->_inter->load16();

	if (id == -1) {
		_passMap = (int8 *)(_vm->_global->_inter_variables + var);
		return;
	}

	extData = _vm->_game->loadExtData(id, 0, 0);
	Common::MemoryReadStream mapData((byte *) extData, 4294967295U);

	if (mapData.readByte() == 3) {
		_screenWidth = 640;
		_passWidth = 65;
	} else {
		_screenWidth = 320;
		_passWidth = 40;
	}
	_wayPointsCount = mapData.readByte();
	_tilesWidth = mapData.readSint16LE();
	_tilesHeight = mapData.readSint16LE();

	_bigTiles = !(_tilesHeight & 0xFF00);
	_tilesHeight &= 0xFF;

	_mapWidth = _screenWidth / _tilesWidth;
	_mapHeight = 200 / _tilesHeight;

	dataPos2 = mapData.pos();
	mapData.seek(_mapWidth * _mapHeight, SEEK_CUR);

	if (*extData == 1)
		wayPointsCount = _wayPointsCount = 40;
	else
		wayPointsCount = _wayPointsCount == 0 ? 1 : _wayPointsCount;

	_wayPoints = new Point[wayPointsCount];
	for (i = 0; i < _wayPointsCount; i++) {
		_wayPoints[i].x = mapData.readSByte();
		_wayPoints[i].y = mapData.readSByte();
		_wayPoints[i].field_2 = mapData.readSByte();
	}

	// In the original asm, this writes byte-wise into the variables-array
	dataPos1 = mapData.pos();
	if (variables != _vm->_global->_inter_variables) {
		_passMap = (int8 *) variables;
		mapHeight = 200 / _tilesHeight;
		mapWidth = _screenWidth / _tilesWidth;
		for (i = 0; i < mapHeight; i++) {
			mapData.seek(dataPos2 + (mapWidth * i));
			for (j = 0; j < mapWidth; j++) {
				setPass(j, i, mapData.readSByte());
			}
		}
	}
	mapData.seek(dataPos1);

	tmp = mapData.readSint16LE();
	mapData.seek(tmp * 14, SEEK_CUR);
	tmp = mapData.readSint16LE();
	mapData.seek(tmp * 14 + 28, SEEK_CUR);
	tmp = mapData.readSint16LE();
	mapData.seek(tmp * 14, SEEK_CUR);

	_vm->_goblin->_gobsCount = tmp;
	for (i = 0; i < _vm->_goblin->_gobsCount; i++) {
		memset(statesMask, -1, 101);
		_vm->_mult->_objects[i].goblinStates = new Mult::Mult_GobState*[101];
		memset(_vm->_mult->_objects[i].goblinStates, 0, 101 * sizeof(Mult::Mult_GobState *));
		mapData.read(statesMask, 100);
		dataPos1 = mapData.pos();
		statesCount = 0;
		for (j = 0; j < 100; j++) {
			if (statesMask[j] != -1) {
				statesCount++;
				mapData.seek(4, SEEK_CUR);
				numData = mapData.readByte();
				statesCount += numData;
				mapData.seek(numData * 9, SEEK_CUR);
			}
		}
		statesPtr = new Mult::Mult_GobState[statesCount];
		_vm->_mult->_objects[i].goblinStates[0] = statesPtr;
		mapData.seek(dataPos1);
		for (j = 0; j < 100; j++) {
			state = statesMask[j];
			if (state != -1) {
				_vm->_mult->_objects[i].goblinStates[state] = statesPtr++;
				_vm->_mult->_objects[i].goblinStates[state][0].animation = mapData.readSint16LE();
				_vm->_mult->_objects[i].goblinStates[state][0].layer = mapData.readSint16LE();
				numData = mapData.readByte();
				_vm->_mult->_objects[i].goblinStates[state][0].dataCount = numData;
				for (k = 1; k <= numData; k++) {
					mapData.seek(1, SEEK_CUR);
					_vm->_mult->_objects[i].goblinStates[state][k].sndItem = mapData.readSByte();
					mapData.seek(1, SEEK_CUR);
					_vm->_mult->_objects[i].goblinStates[state][k].sndFrame = mapData.readByte();
					mapData.seek(1, SEEK_CUR);
					_vm->_mult->_objects[i].goblinStates[state][k].freq = mapData.readSint16LE();
					_vm->_mult->_objects[i].goblinStates[state][k].repCount = mapData.readSByte();
					_vm->_mult->_objects[i].goblinStates[state][k].speaker = mapData.readByte();
					statesPtr++;
				}
			}
		}
	}

	_vm->_goblin->_soundSlotsCount = _vm->_inter->load16();
	for (i = 0; i < _vm->_goblin->_soundSlotsCount; i++)
		_vm->_goblin->_soundSlots[i] = _vm->_inter->loadSound(1);
}

void Map_v2::findNearestToGob(Mult::Mult_Object *obj) {
	int16 wayPoint = findNearestWayPoint(obj->goblinX, obj->goblinY);

	if (wayPoint != -1)
		obj->nearestWayPoint = wayPoint;
}

void Map_v2::findNearestToDest(Mult::Mult_Object *obj) {
	int16 wayPoint = findNearestWayPoint(obj->destX, obj->destY);

	if (wayPoint != -1)
		obj->nearestDest = wayPoint;
}

void Map_v2::optimizePoints(Mult::Mult_Object *obj, int16 x, int16 y) {
	int i;
	int16 var_2;

	if (obj->nearestWayPoint < obj->nearestDest) {
		var_2 = obj->nearestWayPoint;
		for (i = obj->nearestWayPoint; i <= obj->nearestDest; i++) {
			if (checkDirectPath(obj, x, y, _wayPoints[i].x, _wayPoints[i].y) == 1)
				obj->nearestWayPoint = i;
		}
	} else {
		for (i = obj->nearestWayPoint; i >= obj->nearestDest && _wayPoints[i].field_2 != 1; i--) {
			if (checkDirectPath(obj, x, y, _wayPoints[i].x, _wayPoints[i].y) == 1)
				obj->nearestWayPoint = i;
		}
	}
}

} // End of namespace Gob
