/* 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 3 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, see <http://www.gnu.org/licenses/>.
 *
 */

#ifndef QDENGINE_MINIGAMES_KARTINY_H
#define QDENGINE_MINIGAMES_KARTINY_H

#include "common/debug.h"

#include "qdengine/qd_fwd.h"
#include "qdengine/qdcore/qd_minigame_interface.h"

namespace QDEngine {

class qdKartinyMiniGame : public qdMiniGameInterface {
public:
	qdKartinyMiniGame() {}
	~qdKartinyMiniGame() {}

	bool init(const qdEngineInterface *engine_interface) {
		debugC(1, kDebugMinigames, "Kartiny::init()");

		_engine = engine_interface;
		_scene = engine_interface->current_scene_interface();
		if (!_scene)
			return 0;

		_bg_clickObj = _scene->object_interface(_scene->minigame_parameter("zad_click_flag_name"));
		_bg1_l2Obj   = _scene->object_interface(_scene->minigame_parameter("zad1_l2_object_name"));
		_bg2_l2Obj   = _scene->object_interface(_scene->minigame_parameter("zad2_l2_object_name"));
		_bg3_l2Obj   = _scene->object_interface(_scene->minigame_parameter("zad3_l2_object_name"));
		_bg4_l2Obj   = _scene->object_interface(_scene->minigame_parameter("zad4_l2_object_name"));
		_doneObj     = _scene->object_interface(_scene->minigame_parameter("done"));
		_startObj    = _scene->object_interface(_scene->minigame_parameter("start"));
		_activateObj = _scene->object_interface(_scene->minigame_parameter("activate"));
		_zFlagObj    = _scene->object_interface(_scene->minigame_parameter("z_flag"));
		_startObj2   = _scene->object_interface(_scene->minigame_parameter("start"));

		_wasInited = 0;
		_artDepth = -1.0;
		return true;
	}

	bool quant(float dt) {
		debugC(3, kDebugMinigames, "Kartiny::quant(%f)", dt);

		mgVect3f newPiecePos;
		mgVect2i piecePos;

		float depth1 = _scene->screen_depth(_bg1_l2Obj->R());
		float depth2 = _scene->screen_depth(_bg2_l2Obj->R());
		float depth3 = _scene->screen_depth(_bg3_l2Obj->R());
		float depth4 = _scene->screen_depth(_bg4_l2Obj->R());

		if (depth4 >= depth3 || depth3 >= depth2 || depth2 >= depth1)
			_zFlagObj->set_state("\xed\xe5\xf2");	// "нет"
		else
			_zFlagObj->set_state("\xe4\xe0");		// "да"

		if (!_wasInited) {
			if (_startObj->is_state_active("\xe7\xe0\xe4\xed\xe8\xea\xe8 \xee\xef\xf3\xf9\xe5\xed\xfb"))	// "задники опущены"
				_wasInited = 1;

			if (!_wasInited) {
				if (_startObj->is_state_active("\xed\xe5\xf2")) { // "нет"
					_bg1_l2Obj->set_R(_scene->screen2world_coords(mgVect2i(400, -300), 600.0));
					_bg2_l2Obj->set_R(_scene->screen2world_coords(mgVect2i(200, -300), 400.0));
					_bg3_l2Obj->set_R(_scene->screen2world_coords(mgVect2i(400, -300), 200.0));
					_bg4_l2Obj->set_R(_scene->screen2world_coords(mgVect2i(600, -300), 0.0));

					_stage = 4;
					_artDepth = -50.0;

					_activateObj->set_state("\xe7\xe0\xe4\xed\xe8\xea\x34"); // "задник4"
					_startObj->set_state("\xe4\xe0");	// "да"
				} else {
					if (_startObj->is_state_active("\xe4\xe0")) { // "да"
						if (_bg1_l2Obj->screen_R().y < 100) {
							piecePos.x = 400;
							piecePos.y = _bg1_l2Obj->screen_R().y + 3;
							_bg1_l2Obj->set_R(_scene->screen2world_coords(piecePos, 600.0));
						}

						if (_bg2_l2Obj->screen_R().y < 50) {
							piecePos.x = 200;
							piecePos.y = _bg2_l2Obj->screen_R().y + 2;
							_bg2_l2Obj->set_R(_scene->screen2world_coords(piecePos, 400.0));
						}

						if (_bg3_l2Obj->screen_R().y < 85) {
							piecePos.x = 400;
							piecePos.y = _bg3_l2Obj->screen_R().y + 2;
							_bg3_l2Obj->set_R(_scene->screen2world_coords(piecePos, 200.0));
						}

						if (_bg4_l2Obj->screen_R().y < 0) {
							piecePos.x = 600;
							piecePos.y = _bg4_l2Obj->screen_R().y + 2;
							_bg4_l2Obj->set_R(_scene->screen2world_coords(piecePos, 0.0));
						}

						if (_bg1_l2Obj->screen_R().y >= 100
								&& _bg2_l2Obj->screen_R().y >= 50
								&& _bg3_l2Obj->screen_R().y >= 85
								&& _bg4_l2Obj->screen_R().y >= 0) {
							_wasInited = 1;
							_startObj->set_state("\xe7\xe0\xe4\xed\xe8\xea\xe8 \xee\xef\xf3\xf9\xe5\xed\xfb");	// "задники опущены"
						}
					}

					if (_startObj->is_state_active("\xe7\xe0\xe4\xed\xe8\xea\xe8 \xee\xef\xf3\xf9\xe5\xed\xfb")	// "задники опущены"
							&& _artDepth == -1.0) {
						_artState[0].depth = _scene->screen_depth(_bg1_l2Obj->R());
						_artState[0].num = 1;
						_artState[1].depth = _scene->screen_depth(_bg2_l2Obj->R());
						_artState[1].num = 2;
						_artState[2].depth = _scene->screen_depth(_bg3_l2Obj->R());
						_artState[2].num = 3;
						_artState[3].depth = _scene->screen_depth(_bg4_l2Obj->R());
						_artState[3].num = 4;

						// Sort
						for (int i = 0; i < 3; i++) {
							while (_artState[i + 1].depth < _artState[i].depth) {
								int num = _artState[i].num;
								float depth = _artState[i].depth;

								_artState[i].depth = _artState[i + 1].depth;
								_artState[i].num = _artState[i + 1].num;
								_artState[i + 1].depth = depth;
								_artState[i + 1].num = num;

								i = 0;
							}
						}

						_wasInited = 1;

						_stage = _artState[0].num;
						_artDepth = _artState[0].depth;
					}
				}
			}
		}

		if (!checkSolution() && _wasInited) {
			_doneObj->set_state("false");

			if (_engine->is_key_pressed(VK_LEFT)
					|| _engine->is_key_pressed(VK_RIGHT)
					|| _engine->is_key_pressed(VK_UP)
					|| _engine->is_key_pressed(VK_DOWN)) {
				++_keyDownCounter;
			} else {
				_keyDownCounter = 0;
			}

			if (_engine->is_key_pressed(VK_LEFT)) {
				switch (_stage) {
				case 1:
					moveLeft(_bg1_l2Obj);
					break;
				case 2:
					moveLeft(_bg2_l2Obj);
					break;
				case 3:
					moveLeft(_bg3_l2Obj);
					break;
				case 4:
					moveLeft(_bg4_l2Obj);
					break;
				default:
					break;
				}
			}

			if (_engine->is_key_pressed(VK_RIGHT)) {
				switch (_stage) {
				case 1:
					moveRight(_bg1_l2Obj);
					break;
				case 2:
					moveRight(_bg2_l2Obj);
					break;
				case 3:
					moveRight(_bg3_l2Obj);
					break;
				case 4:
					moveRight(_bg4_l2Obj);
					break;
				default:
					break;
				}
			}

			if (_engine->is_key_pressed(VK_UP)) {
				switch (_stage) {
				case 1:
					moveUp(_bg1_l2Obj);
					break;
				case 2:
					moveUp(_bg2_l2Obj);
					break;
				case 3:
					moveUp(_bg3_l2Obj);
					break;
				case 4:
					moveUp(_bg4_l2Obj);
					break;
				default:
					break;
				}
			}

			if (_engine->is_key_pressed(VK_DOWN)) {
				switch (_stage) {
				case 1:
					moveDown(_bg1_l2Obj);
					break;
				case 2:
					moveDown(_bg2_l2Obj);
					break;
				case 3:
					moveDown(_bg3_l2Obj);
					break;
				case 4:
					moveDown(_bg4_l2Obj);
					break;
				default:
					break;
				}
			}

			if ((_bg_clickObj->is_state_active("zad1_level2")
					|| _activateObj->is_state_active("\xe7\xe0\xe4\xed\xe8\xea\x31")) && _stage != 1) { // "задник1"
				_stage = 1;
				_activateObj->set_state("\xe7\xe0\xe4\xed\xe8\xea\x31"); // "задник1"
				_artDepth -= 200.0;
				_bg1_l2Obj->set_R(_scene->screen2world_coords(_bg1_l2Obj->screen_R(), _artDepth));

				snapPieces();
			}

			if ((_bg_clickObj->is_state_active("zad2_level2")
					|| _activateObj->is_state_active("\xe7\xe0\xe4\xed\xe8\xea\x32")) && _stage != 2) { // "задник2"
				_stage = 2;
				_activateObj->set_state("\xe7\xe0\xe4\xed\xe8\xea\x32"); // "задник2"
				_artDepth -= 200.0;
				_bg2_l2Obj->set_R(_scene->screen2world_coords(_bg2_l2Obj->screen_R(), _artDepth));

				snapPieces();
			}

			if ((_bg_clickObj->is_state_active("zad3_level2")
					|| _activateObj->is_state_active("\xe7\xe0\xe4\xed\xe8\xea\x33")) && _stage != 3) { // "задник3"
				_stage = 3;
				_activateObj->set_state("\xe7\xe0\xe4\xed\xe8\xea\x33"); // "задник3"
				_artDepth -= 200.0;
				_bg3_l2Obj->set_R(_scene->screen2world_coords(_bg3_l2Obj->screen_R(), _artDepth));

				snapPieces();
			}

			if ((_bg_clickObj->is_state_active("zad4_level2")
					|| _activateObj->is_state_active("\xe7\xe0\xe4\xed\xe8\xea\x34")) && _stage != 4) { // "задник4"
				_stage = 4;
				_activateObj->set_state("\xe7\xe0\xe4\xed\xe8\xea\x34"); // "задник4"
				_artDepth -= 200.0;
				_bg4_l2Obj->set_R(_scene->screen2world_coords(_bg4_l2Obj->screen_R(), _artDepth));

				snapPieces();
			}
		}

		return true;
	}

	bool finit() {
		debugC(1, kDebugMinigames, "Kartiny::finit()");

		if (_scene)  {
			_engine->release_scene_interface(_scene);
			_scene = 0;
		}

 		return true;
	}

	bool new_game(const qdEngineInterface *engine_interface) {
		return true;
	}

	int save_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, char *buffer, int buffer_size) {
		return 0;
	}

	int load_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, const char *buffer, int buffer_size) {
		return 0;
	}

	enum { INTERFACE_VERSION = 99 };
	int version() const {
		return INTERFACE_VERSION;
	}

private:
	void snapPieces() {
		mgVect2i piecePos;
		mgVect3f newPiecePos;
		float depth;

		piecePos = _bg1_l2Obj->screen_R();
		depth = _scene->screen_depth(_bg1_l2Obj->R());

		if (ABS(399 - ABS(piecePos.x)) <= 10 && ABS(278 - ABS(piecePos.y)) <= 10) {
			piecePos.x = 399;
			piecePos.y = 278;

			newPiecePos = _scene->screen2world_coords(piecePos, depth);
			_bg1_l2Obj->set_R(newPiecePos);
		}

		piecePos = _bg2_l2Obj->screen_R();
		depth = _scene->screen_depth(_bg2_l2Obj->R());

		if (piecePos.x >= 387 && piecePos.x <= 440 && ABS(267 - ABS(piecePos.y)) <= 20) {
			piecePos.x = 408;
			piecePos.y = 267;

			newPiecePos = _scene->screen2world_coords(piecePos, depth);
			_bg2_l2Obj->set_R(newPiecePos);
		}

		piecePos = _bg3_l2Obj->screen_R();
		depth = _scene->screen_depth(_bg3_l2Obj->R());

		if (ABS(ABS(piecePos.x) - 413) < 25 && ABS(ABS(piecePos.y) - 43) < 40) {
			piecePos.x = 406;
			piecePos.y = -43;

			newPiecePos = _scene->screen2world_coords(piecePos, depth);
			_bg3_l2Obj->set_R(newPiecePos);
		}
	}

	void moveDown(qdMinigameObjectInterface *obj) {
		int speed = MAX(10, _keyDownCounter / 10 + 1);
		int maxCoords;

		if (obj == _bg1_l2Obj)
			maxCoords = 279;
		else if (obj == _bg2_l2Obj)
			maxCoords = 267;
		// FIXME: Remove this as covered by the default case?
		//else if (obj == _bg3_l2Obj)
		//	maxCoords = 258;
		else
			maxCoords = 258;

		mgVect2i objPos = obj->screen_R();

		if (objPos.y + speed < maxCoords)
			objPos.y += speed;

		obj->set_R(_scene->screen2world_coords(objPos, _artDepth));
	}

	void moveUp(qdMinigameObjectInterface *obj) {
		int speed = MAX(10, _keyDownCounter / 10 + 1);
		mgVect2i objPos = obj->screen_R();

		if (objPos.y > -100)
			objPos.y -= speed;

		obj->set_R(_scene->screen2world_coords(objPos, _artDepth));
	}

	void moveRight(qdMinigameObjectInterface *obj) {
		int speed = MAX(10, _keyDownCounter / 10 + 1);
		mgVect2i objPos = obj->screen_R();

		if (objPos.x < 900)
			objPos.x += speed;

		obj->set_R(_scene->screen2world_coords(objPos, _artDepth));
	}

	void moveLeft(qdMinigameObjectInterface *obj) {
		int speed = MAX(10, _keyDownCounter / 10 + 1);
		mgVect2i objPos = obj->screen_R();

		if (objPos.x > -100)
			objPos.x -= speed;

		obj->set_R(_scene->screen2world_coords(objPos, _artDepth));
	}

	bool checkSolution() {
		if (_scene->screen_depth(_bg1_l2Obj->R()) < _scene->screen_depth(_bg2_l2Obj->R()))
			return false;

		if (_scene->screen_depth(_bg2_l2Obj->R()) < _scene->screen_depth(_bg3_l2Obj->R()))
			return false;

		if (_scene->screen_depth(_bg3_l2Obj->R()) < _scene->screen_depth(_bg4_l2Obj->R()))
			return false;

		if (ABS(_bg1_l2Obj->screen_R().x - 399) > 5
				|| ABS(_bg1_l2Obj->screen_R().y - 278) > 5
				|| (ABS(_bg2_l2Obj->screen_R().x - 407) > 10
				&& ABS(_bg2_l2Obj->screen_R().x - 420) > 10)) // copy/paste error in the originaL?
			return false;

		if (ABS(_bg2_l2Obj->screen_R().y - 267) > 10)
			return false;

		if (_bg2_l2Obj->screen_R().x - _bg3_l2Obj->screen_R().x > 6)
			return false;

		if (_bg3_l2Obj->screen_R().x - _bg2_l2Obj->screen_R().x > 5)
			return false;

		if (ABS(_bg3_l2Obj->screen_R().y + 43) > 10)
			return false;

		if (_bg4_l2Obj->screen_R().x - _bg3_l2Obj->screen_R().x > 5)
			return false;

		if (_bg3_l2Obj->screen_R().x - _bg4_l2Obj->screen_R().x > 3)
			return false;

		if (ABS(_bg4_l2Obj->screen_R().y + 42) > 10)
			return false;

		if (ABS(_bg4_l2Obj->screen_R().y) - ABS(_bg3_l2Obj->screen_R().y) > 3)
			return false;


		_doneObj->set_state("true");

		return true;
	}

private:
	const qdEngineInterface *_engine = nullptr;
	qdMinigameSceneInterface *_scene = nullptr;

	qdMinigameObjectInterface *_bg_clickObj = nullptr;
	qdMinigameObjectInterface *_bg1_l2Obj = nullptr;
	qdMinigameObjectInterface *_bg2_l2Obj = nullptr;
	qdMinigameObjectInterface *_bg3_l2Obj = nullptr;
	qdMinigameObjectInterface *_bg4_l2Obj = nullptr;
	qdMinigameObjectInterface *_doneObj = nullptr;
	qdMinigameObjectInterface *_startObj = nullptr;
	qdMinigameObjectInterface *_activateObj = nullptr;
	qdMinigameObjectInterface *_zFlagObj = nullptr;
	qdMinigameObjectInterface *_startObj2 = nullptr;

	bool _wasInited = false;
	float _artDepth = -1.0;
	int _keyDownCounter = 0;

	int _stage = 0;

	struct {
		float depth = 0;
		int num = 0;
	} _artState[4];
};

} // namespace QDEngine

#endif // QDENGINE_MINIGAMES_KARTINY_H
