/* 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.
 *
 */



#ifdef ENABLE_AGOS2

#include "agos/agos.h"
#include "agos/intern.h"
#include "agos/sound.h"

namespace AGOS {

void AGOSEngine_Feeble::setupVideoOpcodes(VgaOpcodeProc *op) {
	AGOSEngine_Simon2::setupVideoOpcodes(op);

	op[75] = &AGOSEngine::vc75_setScale;
	op[76] = &AGOSEngine::vc76_setScaleXOffs;
	op[77] = &AGOSEngine::vc77_setScaleYOffs;
	op[78] = &AGOSEngine::vc78_computeXY;
	op[79] = &AGOSEngine::vc79_computePosNum;
	op[80] = &AGOSEngine::vc80_setOverlayImage;
	op[81] = &AGOSEngine::vc81_setRandom;
	op[82] = &AGOSEngine::vc82_getPathValue;
	op[83] = &AGOSEngine::vc83_playSoundLoop;
	op[84] = &AGOSEngine::vc84_stopSoundLoop;
}

int AGOSEngine::getScale(int16 y, int16 x) {
	int16 z;

	if (y > _baseY) {
		return((int16)(x * (1 + ((y - _baseY) * _scale))));
	} else {
		if (x == 0)
			return(0);
		if (x < 0) {
			z = ((int16)((x * (1 - ((_baseY - y)* _scale))) - 0.5));
			if (z >- 2)
				return(-2);
			return(z);
		}

		z = ((int16)((x * (1 - ((_baseY - y) * _scale))) + 0.5));
		if (z < 2)
			return(2);

		return(z);
	}
}

void AGOSEngine_Feeble::vc36_setWindowImage() {
	_displayFlag = 0;
	vcReadNextWord();
	vcReadNextWord();
	fillBackGroundFromFront();
}

void AGOSEngine_Feeble::vc48_setPathFinder() {
	uint16 a = (uint16)_variableArrayPtr[12];
	const uint16 *p = _pathFindArray[a - 1];

	VgaSprite *vsp = findCurSprite();
	int16 x, y, ydiff;
	int16 x1, y1, x2, y2;
	uint pos = 0;

	x = vsp->x;
	while (x >= (int16)readUint16Wrapper(p + 2)) {
		p += 2;
		pos++;
	}

	x1 = readUint16Wrapper(p);
	y1 = readUint16Wrapper(p + 1);
	x2 = readUint16Wrapper(p + 2);
	y2 = readUint16Wrapper(p + 3);

	if (x2 != 9999) {
		ydiff = y2 - y1;
		if (ydiff < 0) {
			ydiff = -ydiff;
			x = vsp->x & 7;
			ydiff *= x;
			ydiff /= 8;
			ydiff = -ydiff;
		} else {
			x = vsp->x & 7;
			ydiff *= x;
			ydiff /= 8;
		}
		y1 += ydiff;
	}

	y = vsp->y;
	vsp->y = y1;
	checkScrollY(y1 - y, y1);

	_variableArrayPtr[11] = x1;
	_variableArrayPtr[13] = pos;
}

void AGOSEngine::vc75_setScale() {
	_baseY = vcReadNextWord();
	_scale = vcReadNextWord() / 1000000.0f;
}

void AGOSEngine::vc76_setScaleXOffs() {
	if (getGameType() == GType_PP && getBitFlag(120)) {
		VgaSprite *vsp1, *vsp2;
		uint16 old_file_1, tmp1, tmp2;

		old_file_1 = _vgaCurSpriteId;

		_vgaCurSpriteId = vcReadVar(vcReadNextWord());
		 vsp1 = findCurSprite();
		_vgaCurSpriteId = vcReadVar(vcReadNextWord());
		 vsp2 = findCurSprite();

		tmp1 = vsp1->x;
		tmp2 = vsp2->x;
		vsp1->x = tmp2;
		vsp2->x = tmp1;
		tmp1 = vsp1->y;
		tmp2 = vsp2->y;
		vsp1->y = tmp2;
		vsp2->y = tmp1;

		_vgaCurSpriteId = old_file_1;
		_vcPtr += 2;
	} else {
		VgaSprite *vsp = findCurSprite();

		vsp->image = vcReadNextWord();
		int16 x = vcReadNextWord();
		uint16 var = vcReadNextWord();

		vsp->x += getScale(vsp->y, x);
		_variableArrayPtr[var] = vsp->x;

		checkScrollX(x, vsp->x);

		vsp->flags = kDFScaled;
	}
}

void AGOSEngine::vc77_setScaleYOffs() {
	VgaSprite *vsp = findCurSprite();

	vsp->image = vcReadNextWord();
	int16 y = vcReadNextWord();
	uint16 var = vcReadNextWord();

	vsp->y += getScale(vsp->y, y);
	_variableArrayPtr[var] = vsp->y;

	if (y != 0)
		checkScrollY(y, vsp->y);

	vsp->flags = kDFScaled;
}

void AGOSEngine::vc78_computeXY() {
	VgaSprite *vsp = findCurSprite();

	uint16 a = (uint16)_variableArrayPtr[12];
	uint16 b = (uint16)_variableArrayPtr[13];

	const uint16 *p = _pathFindArray[a - 1];
	p += b * 2;

	uint16 posx = readUint16Wrapper(p);
	_variableArrayPtr[15] = posx;
	vsp->x = posx;

	uint16 posy = readUint16Wrapper(p + 1);
	_variableArrayPtr[16] = posy;
	vsp->y = posy;

	if (getGameType() == GType_FF) {
		setBitFlag(85, false);
		if (getBitFlag(74)) {
			centerScroll();
		}
	}
}

void AGOSEngine::vc79_computePosNum() {
	uint a = (uint16)_variableArrayPtr[12];
	const uint16 *p = _pathFindArray[a - 1];
	uint pos = 0;

	int16 y = _variableArrayPtr[16];
	while (y >= (int16)readUint16Wrapper(p + 1)) {
		p += 2;
		pos++;
	}

	_variableArrayPtr[13] = pos;
}

void AGOSEngine::vc80_setOverlayImage() {
	VgaSprite *vsp = findCurSprite();

	vsp->image = vcReadVarOrWord();

	vsp->x += vcReadNextWord();
	vsp->y += vcReadNextWord();
	vsp->flags = kDFOverlayed;

	_vgaSpriteChanged++;
}

void AGOSEngine::vc81_setRandom() {
	uint16 var = vcReadNextWord();
	uint16 value = vcReadNextWord();

	_variableArray[var] = _rnd.getRandomNumber(value - 1);
}

void AGOSEngine::vc82_getPathValue() {
	uint8 val;

	uint16 var = vcReadNextWord();

	if (getGameType() == GType_FF && getBitFlag(82)) {
		val = _pathValues1[_GPVCount1++];
	} else {
		val = _pathValues[_GPVCount++];
	}

	vcWriteVar(var, val);
}

void AGOSEngine::vc83_playSoundLoop() {
	uint16 sound = vcReadNextWord();
	int16 vol = vcReadNextWord();
	int16 pan = vcReadNextWord();

	loadSound(sound, pan, vol, Sound::TYPE_SFX5);
}

void AGOSEngine::vc84_stopSoundLoop() {
	_sound->stopSfx5();
}

// Scrolling functions for Feeble Files
void AGOSEngine::checkScrollX(int16 x, int16 xpos) {
	if (_scrollXMax == 0 || x == 0)
		return;

	if (getGameType() == GType_FF && (getBitFlag(80) || getBitFlag(82)))
		return;

	int16 tmp;
	if (x > 0) {
		if (_scrollCount != 0) {
			if (_scrollCount >= 0)
				return;
			_scrollCount = 0;
		} else {
			if (_scrollFlag != 0)
				return;
		}

		if (xpos - _scrollX >= 480) {
			_scrollCount = 320;
			tmp = _scrollXMax - _scrollX;
			if (tmp < 320)
				_scrollCount = tmp;
		}
	} else {
		if (_scrollCount != 0) {
			if (_scrollCount < 0)
				return;
			_scrollCount = 0;
		} else {
			if (_scrollFlag != 0)
				return;
		}

		if (xpos - _scrollX < 161) {
			_scrollCount = -320;
			if (_scrollX < 320)
				_scrollCount = -_scrollX;
		}
	}
}

void AGOSEngine::checkScrollY(int16 y, int16 ypos) {
	if (_scrollYMax == 0)
		return;

	if (getGameType() == GType_FF && getBitFlag(80))
		return;

	int16 tmp;
	if (y >= 0) {
		if (_scrollCount != 0) {
			if (_scrollCount >= 0)
				return;
		} else {
			if (_scrollFlag != 0)
				return;
		}

		if (ypos - _scrollY >= 440) {
			_scrollCount = 240;
			tmp = _scrollYMax - _scrollY;
			if (tmp < 240)
				_scrollCount = tmp;
		}
	} else {
		if (_scrollCount != 0) {
			if (_scrollCount < 0)
				return;
		} else {
			if (_scrollFlag != 0)
				return;
		}

		if (ypos - _scrollY < 100) {
			_scrollCount = -240;
			if (_scrollY < 240)
				_scrollCount = -_scrollY;
		}
	}
}

void AGOSEngine::centerScroll() {
	int16 x, y, tmp;

	if (_scrollXMax != 0) {
		_scrollCount = 0;
		x = _variableArray[15] - _scrollX;
		if (x < 17 || (getBitFlag(85) && x < 320)) {
			x -= 320;
			if (_scrollX < -x)
				x = -_scrollX;
			_scrollCount = x;
		} else if ((getBitFlag(85) && x >= 320) || x >= 624) {
			x -= 320;
			tmp = _scrollXMax - _scrollX;
			if (tmp < x)
				x = tmp;
			_scrollCount = x;
		}
	} else if (_scrollYMax != 0) {
		_scrollCount = 0;
		y = _variableArray[16] - _scrollY;
		if (y < 30) {
			y -= 240;
			if (_scrollY < -y)
				y = -_scrollY;
			_scrollCount = y;
		} else if (y >= 460) {
			y -= 240;
			tmp = _scrollYMax - _scrollY;
			if (tmp < y)
				y = tmp;
			_scrollCount = y;
		}
	}
}

// Puzzle Pack specific code

void AGOSEngine_PuzzlePack::vc3_loadSprite() {
	if (getGameId() != GID_DIMP && getBitFlag(100)) {
		startAnOverlayAnim();
		return;
	}

	AGOSEngine::vc3_loadSprite();
}

void AGOSEngine_PuzzlePack::vc63_fastFadeIn() {
	_fastFadeInFlag = 256;
	_fastFadeOutFlag = false;

	if (getGameId() == GID_DIMP)
		return;

	if (getBitFlag(100)) {
		startOverlayAnims();
	} else if (getBitFlag(103)) {
		debug("vc63_fastFadeIn: NameAndTime");
	} else if (getBitFlag(104)) {
		debug("vc63_fastFadeIn: HiScoreTable");
	}
}

void AGOSEngine_PuzzlePack::startOverlayAnims() {
	VgaSprite *vsp = _vgaSprites;
	uint16 zoneNum;
	int i;

	zoneNum = _variableArray[999];

	for (i = 0; i < 600; i++) {
		if (_variableArray[1000 + i] < 100)
			continue;

		while (vsp->id)
			vsp++;

		vsp->windowNum = 4;
		vsp->priority = 4;
		vsp->flags = 0;
		vsp->palette = 0;
		vsp->image = _variableArray[1000 + i];
		if (i >= 300) {
			vsp->y = ((i - 300) / 20) * 32;
			vsp->x = ((i - 300) % 20) * 32;
		} else {
			vsp->y = (i / 20) * 32;
			vsp->x = (i % 20) * 32;
		}
		vsp->id = 1000 + i;
		vsp->zoneNum = zoneNum;
	}
}

void AGOSEngine_PuzzlePack::startAnOverlayAnim() {
	VgaSprite *vsp = _vgaSprites;
	const byte *vcPtrOrg;
	uint16 a, sprite, file, tmp, zoneNum;
	int16 x;

	zoneNum = _variableArray[999];

	_vcPtr += 4;
	a = vcReadNextWord();
	_vcPtr += 6;

	while (vsp->id)
		vsp++;

	vsp->windowNum = 4;
	vsp->priority = 20;
	vsp->flags = 0;
	vsp->palette = 0;
	vsp->image = vcReadVar(vcReadVar(a));

	x = vcReadVar(a) - 1300;
	if (x < 0) {
		x += 300;
		vsp->priority = 10;
	}

	vsp->y = x / 20 * 32;
	vsp->x = x % 20 * 32;
	vsp->id = vcReadVar(a);
	vsp->zoneNum = zoneNum;

	sprite = _vgaCurSpriteId;
	file = _vgaCurZoneNum;

	_vgaCurZoneNum = vsp->zoneNum;
	_vgaCurSpriteId = vsp->id;

	tmp = to16Wrapper(vsp->priority);

	vcPtrOrg = _vcPtr;
	_vcPtr = (byte *)&tmp;
	vc23_setPriority();

	_vcPtr = vcPtrOrg;
	_vgaCurSpriteId = sprite;
	_vgaCurZoneNum = file;
}

} // End of namespace AGOS

#endif // ENABLE_AGOS2
