/* 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 "bladerunner/ui/kia_section_crimes.h"

#include "bladerunner/actor_clues.h"
#include "bladerunner/audio_player.h"
#include "bladerunner/bladerunner.h"
#include "bladerunner/crimes_database.h"
#include "bladerunner/font.h"
#include "bladerunner/game_flags.h"
#include "bladerunner/game_info.h"
#include "bladerunner/shape.h"
#include "bladerunner/script/kia_script.h"
#include "bladerunner/suspects_database.h"
#include "bladerunner/text_resource.h"
#include "bladerunner/ui/kia.h"
#include "bladerunner/ui/kia_log.h"
#include "bladerunner/ui/kia_section_suspects.h"
#include "bladerunner/ui/kia_shapes.h"
#include "bladerunner/ui/ui_container.h"
#include "bladerunner/ui/ui_image_picker.h"
#include "bladerunner/ui/ui_scroll_box.h"

#include "graphics/surface.h"

namespace BladeRunner {

KIASectionCrimes::KIASectionCrimes(BladeRunnerEngine *vm, ActorClues *clues) : KIASectionBase(vm) {
	_uiContainer = new UIContainer(_vm);
	_isOpen = false;
	_clues = clues;

	_mouseX = 0;
	_mouseY = 0;

	_buttons = new UIImagePicker(_vm, 5);

	_cluesScrollBox = new UIScrollBox(_vm, scrollBoxCallback, this, 50, 1, false, Common::Rect(312, 172, 500, 376), Common::Rect(506, 160, 506, 394));
	_uiContainer->add(_cluesScrollBox);

	_acquiredClueCount = 0;
	for (int i = 0; i < kClueCount; ++i) {
		_acquiredClues[i].clueId  = -1;
		_acquiredClues[i].actorId = -1;
	}

	_crimeSelected = -1;
	_crimesFoundCount = 0;
	_crimesFound.resize(_vm->_gameInfo->getCrimeCount());

	_suspectSelected = -1;
	_suspectPhotoShapeId = -1;
	_suspectPhotoNotUsed = -1;
	_suspectPhotoShape = nullptr;
	_suspectsFoundCount = 0;
	_suspectsFound.resize(_vm->_gameInfo->getSuspectCount());
	_suspectsWithIdentity.resize(_vm->_gameInfo->getSuspectCount());
}

KIASectionCrimes::~KIASectionCrimes() {
	delete _suspectPhotoShape;

	_uiContainer->clear();

	delete _cluesScrollBox;
	delete _buttons;
	delete _uiContainer;
}

void KIASectionCrimes::reset() {
	_acquiredClueCount = 0;
    _crimesFoundCount = 0;
    _suspectsFoundCount = 0;
    _mouseX = 0;
    _mouseY = 0;
    _suspectSelected = -1;
    _crimeSelected = -1;
    _suspectPhotoShapeId = -1;
    _suspectPhotoNotUsed = -1;
}

void KIASectionCrimes::open() {
	_scheduledSwitch = false;

	_buttons->resetImages();
	_buttons->defineImage(0, Common::Rect(136, 326, 185, 342), nullptr, _vm->_kia->_shapes->get(32), _vm->_kia->_shapes->get(36), _vm->_textKIA->getText(32));
	_buttons->defineImage(1, Common::Rect(218, 326, 269, 342), nullptr, _vm->_kia->_shapes->get(33), _vm->_kia->_shapes->get(37), _vm->_textKIA->getText(33));
	_buttons->defineImage(2, Common::Rect(354, 128, 404, 144), nullptr, _vm->_kia->_shapes->get(30), _vm->_kia->_shapes->get(34), _vm->_textKIA->getText(34));
	_buttons->defineImage(3, Common::Rect(425, 128, 474, 144), nullptr, _vm->_kia->_shapes->get(31), _vm->_kia->_shapes->get(35), _vm->_textKIA->getText(35));
	_buttons->defineImage(4, Common::Rect(142, 150, 260, 297), nullptr, nullptr, nullptr, _vm->_textKIA->getText(36));
	_buttons->activate(nullptr, nullptr, nullptr, mouseUpCallback, this);

	_cluesScrollBox->show();

	populateAcquiredClues();
	populateCrimes();
	populateSuspects();
	populateVisibleClues();
	updateSuspectPhoto();

	_isOpen = true;
}

void KIASectionCrimes::close() {
	if (!_isOpen) {
		return;
	}
	_isOpen = false;
	_buttons->deactivate();
	_cluesScrollBox->hide();
	if (_suspectPhotoShapeId != -1) {
		delete _suspectPhotoShape;
		_suspectPhotoShape = nullptr;
		_suspectPhotoShapeId = -1;
	}
}

void KIASectionCrimes::draw(Graphics::Surface &surface) {
	const char *text = nullptr;
	if (_suspectPhotoShapeId != -1) {
		_suspectPhotoShape->draw(surface, 201 - _suspectPhotoShape->getWidth() / 2, 223 - _suspectPhotoShape->getHeight() / 2);
	}
	if (_suspectPhotoShapeId == 14 || _suspectPhotoShapeId == 13) {
		text = _vm->_textKIA->getText(49);
		_vm->_mainFont->drawColor(text, surface, 201 - _vm->_mainFont->getTextWidth(text) / 2, 218, 0x7FFF);
	}

	surface.fillRect(Common::Rect(120, 134, 250, 145), 0);
	surface.hLine(120, 133, 250, 0x18A5);
	surface.hLine(120, 146, 250, 0x2D4C);
	surface.vLine(119, 134, 145, 0x18A5);
	surface.vLine(251, 134, 145, 0x2D4C);
	surface.hLine(251, 146, 251, 0x2509);

	if (_crimeSelected == -1) {
		text = _vm->_textKIA->getText(49);
	} else {
		text = _vm->_textCrimes->getText(_crimeSelected);
	}

	_vm->_mainFont->drawColor(text, surface, 185 - _vm->_mainFont->getTextWidth(text) / 2, 136, 0x46BF);

	surface.fillRect(Common::Rect(136, 304, 266, 315), 0);
	surface.hLine(136, 303, 266, 0x18A5);
	surface.hLine(136, 316, 266, 0x2D4C);
	surface.vLine(135, 304, 315, 0x18A5);
	surface.vLine(267, 304, 315, 0x2D4C);
	surface.hLine(267, 316, 267, 0x2509);

	char generatedText[64];
	if (_suspectSelected == -1) {
		text = _vm->_textKIA->getText(22);
	} else {
		const char *suspectName = _vm->_suspectsDatabase->get(_suspectSelected)->getName();
		if (_suspectsWithIdentity[_suspectSelected]) {
			text = suspectName;
		} else if (_vm->_suspectsDatabase->get(_suspectSelected)->getSex()) {
			sprintf(generatedText, "%s %s", _vm->_textKIA->getText(20), KIASectionSuspects::scrambleSuspectsName(suspectName));
			text = generatedText;
		} else {
			sprintf(generatedText, "%s %s", _vm->_textKIA->getText(21), KIASectionSuspects::scrambleSuspectsName(suspectName));
			text = generatedText;
		}
	}
	_vm->_mainFont->drawColor(text, surface, 201 - _vm->_mainFont->getTextWidth(text) / 2, 306, 0x46BF);

	_uiContainer->draw(surface);
	_buttons->draw(surface);
	_buttons->drawTooltip(surface, _mouseX, _mouseY);
}

void KIASectionCrimes::handleMouseMove(int mouseX, int mouseY) {
	_mouseX = mouseX;
	_mouseY = mouseY;
	_buttons->handleMouseAction(mouseX, mouseY, false, false, false);
	_uiContainer->handleMouseMove(mouseX, mouseY);
}

void KIASectionCrimes::handleMouseDown(bool mainButton) {
	if (mainButton) {
		_buttons->handleMouseAction(_mouseX, _mouseY, true, false, false);
	}
	_uiContainer->handleMouseDown(!mainButton);
}

void KIASectionCrimes::handleMouseUp(bool mainButton) {
	if (mainButton) {
		_buttons->handleMouseAction(_mouseX, _mouseY, false, true, false);
	}
	_uiContainer->handleMouseUp(!mainButton);
}

void KIASectionCrimes::handleMouseScroll(int direction) {
	_uiContainer->handleMouseScroll(direction);
}

void KIASectionCrimes::saveToLog() {
	int data[] = { _crimeSelected, _suspectSelected };
	_vm->_kia->_log->add(2, sizeof(data), &data);
}

void KIASectionCrimes::loadFromLog() {
	const int *data = (const int*)_vm->_kia->_log->getCurrentData();
	_crimeSelected = data[0];
	_suspectSelected = data[1];
	populateSuspects();
	populateVisibleClues();
}

void KIASectionCrimes::selectCrime(int crimeId) {
	_crimeSelected = crimeId;
	populateSuspects();
	populateVisibleClues();
	updateSuspectPhoto();
}

void KIASectionCrimes::scrollBoxCallback(void *callbackData, void *source, int lineData, int mouseButton) {
	KIASectionCrimes *self = (KIASectionCrimes *)callbackData;

	if (source == self->_cluesScrollBox && lineData >= 0) {
		if (mouseButton) {
			if (self->_vm->_gameFlags->query(kFlagKIAPrivacyAddon)) {
				self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(511), 70, 0, 0, 50, 0);

				if (self->_clues->isPrivate(lineData)) {
					self->_clues->setPrivate(lineData, false);
					self->_cluesScrollBox->resetFlags(lineData, 0x08);
				} else {
					self->_clues->setPrivate(lineData, true);
					self->_cluesScrollBox->setFlags(lineData, 0x08);
				}
			}
		} else {
			self->_clues->setViewed(lineData, true);
			self->_cluesScrollBox->resetHighlight(lineData);
			self->_vm->_kia->_script->playClueAssetScript(0, lineData);
		}
	}
}

void KIASectionCrimes::mouseUpCallback(int buttonId, void *callbackData) {
	((KIASectionCrimes *)callbackData)->onButtonPressed(buttonId);
}

void KIASectionCrimes::onButtonPressed(int buttonId) {
	switch (buttonId) {
	case 0:
		prevSuspect();
		break;
	case 1:
		nextSuspect();
		break;
	case 2:
		prevCrime();
		break;
	case 3:
		nextCrime();
		break;
	case 4:
		if (_suspectSelected != -1) {
			_scheduledSwitch = true;
		}
		break;
	}
}

void KIASectionCrimes::populateAcquiredClues() {
	_acquiredClueCount = 0;
	for (int i = 0; i < kClueCount; ++i) {
		if (_clues->isAcquired(i)) {
			_acquiredClues[_acquiredClueCount].clueId = i;
			_acquiredClues[_acquiredClueCount].actorId = _clues->getFromActorId(i);
			++_acquiredClueCount;
		}
	}
	// sort clues by name, is it necessary?
}

void KIASectionCrimes::populateCrimes() {
	int firstCrime = -1;
	int crimeCount = _vm->_gameInfo->getCrimeCount();
	for (int i = 0; i < crimeCount; ++i) {
		_crimesFound[i] = false;
	}

	_crimesFoundCount = 0;

	if (!_acquiredClueCount) {
		return;
	}

	for (int i = 0; i < crimeCount; ++i) {
		for (int j = 0; j < _acquiredClueCount; ++j) {
			if (_vm->_crimesDatabase->getCrime(_acquiredClues[j].clueId) == i) {
				if (firstCrime == -1) {
					firstCrime = i;
				}
				_crimesFound[i] = true;
				++_crimesFoundCount;
			}
		}
	}

	if (_crimesFoundCount > 0 && _crimeSelected == -1) {
		_crimeSelected = firstCrime;
	}
}

void KIASectionCrimes::populateSuspects() {
	int firstSuspect = -1;
	int suspectCount = _vm->_gameInfo->getSuspectCount();

	for (int i = 0; i < suspectCount; ++i) {
		_suspectsFound[i] = false;
		_suspectsWithIdentity[i] = false;
	}

	_suspectsFoundCount = 0;

	if (!_acquiredClueCount || _crimeSelected == -1) {
		return;
	}

	for (int i = 0; i < suspectCount; ++i) {
		for (int j = 0; j < _acquiredClueCount; ++j) {
			if (_vm->_crimesDatabase->getCrime(_acquiredClues[j].clueId) == _crimeSelected
			 && _vm->_suspectsDatabase->get(i)->hasClue(_acquiredClues[j].clueId)
			) {
				if (firstSuspect == -1) {
					firstSuspect = i;
				}
				_suspectsFound[i] = true;
				++_suspectsFoundCount;
			}
		}

		if (_suspectsFound[i]) {
			for (int j = 0; j < _acquiredClueCount; ++j) {
				if (_vm->_suspectsDatabase->get(i)->hasIdentityClue(_acquiredClues[j].clueId)) {
					_suspectsWithIdentity[i] = true;
				}
			}
		}
	}

	if (_suspectsFoundCount) {
		if (_suspectSelected == -1 || !_suspectsFound[_suspectSelected]) {
			_suspectSelected = firstSuspect;
		}
	} else {
		_suspectSelected = -1;
	}
}

void KIASectionCrimes::populateVisibleClues() {
	_cluesScrollBox->clearLines();
	if (_crimeSelected != -1) {
		for (uint i = 0; i < _vm->_gameInfo->getClueCount(); ++i) {
			if (_vm->_crimesDatabase->getAssetType(i) != -1
			 && _vm->_crimesDatabase->getCrime(i) == _crimeSelected
			 && _clues->isAcquired(i)
			) {
				int flags = 0x30;
				if (_clues->isPrivate(i)) {
					flags = 0x08;
				} else if (_clues->isViewed(i)) {
					flags = 0x10;
				}
				_cluesScrollBox->addLine(_vm->_crimesDatabase->getClueText(i), i, flags);
			}
		}
		_cluesScrollBox->sortLines();
	}
}

void KIASectionCrimes::updateSuspectPhoto() {
	if (_suspectPhotoShapeId != -1) {
		delete _suspectPhotoShape;
		_suspectPhotoShape = nullptr;
	}

	if (_suspectSelected == -1) {
		_suspectPhotoShapeId = -1;
		return;
	}

	SuspectDatabaseEntry *suspect = _vm->_suspectsDatabase->get(_suspectSelected);

	_suspectPhotoShapeId = -1;
	_suspectPhotoNotUsed = -1;
	int photoCluesCount = suspect->getPhotoCount();
	if (photoCluesCount > 0) {
		for (int i = 0 ; i < photoCluesCount; i++) {
			//TODO: weird stuff going on here... original game is using internal clue index instead id
			if (_clues->isAcquired(suspect->getPhotoClueId(i))) {
				_suspectPhotoShapeId = suspect->getPhotoShapeId(i);
				_suspectPhotoNotUsed = suspect->getPhotoNotUsed(i);
				break;
			}
		}
	}

	if (_suspectPhotoShapeId == -1 && _suspectPhotoNotUsed == -1) {
		if (suspect->getSex()) {
			_suspectPhotoShapeId = 14;
		} else {
			_suspectPhotoShapeId = 13;
		}
	}

	if (_suspectPhotoShapeId != -1) {
		_suspectPhotoShape = new Shape(_vm);
		_suspectPhotoShape->open("photos.shp", _suspectPhotoShapeId);
	}
}

void KIASectionCrimes::nextCrime() {
	if (_crimesFoundCount >= 2) {
		while (true) {
			++_crimeSelected;
			if (_crimeSelected >= (int)_vm->_gameInfo->getCrimeCount()){
				_crimeSelected = 0;
			}

			if (_crimesFound[_crimeSelected]) {
				selectCrime(_crimeSelected);
				break;
			}
		}
	}
}

void KIASectionCrimes::prevCrime() {
	if (_crimesFoundCount >= 2) {
		while (true) {
			--_crimeSelected;
			if (_crimeSelected < 0) {
				_crimeSelected = _vm->_gameInfo->getCrimeCount() - 1;
			}

			if (_crimesFound[_crimeSelected]) {
				selectCrime(_crimeSelected);
				break;
			}
		}
	}
}

void KIASectionCrimes::nextSuspect() {
	if (_suspectsFoundCount >= 2) {
		while (true) {
			++_suspectSelected;
			if (_suspectSelected >= (int)_vm->_gameInfo->getSuspectCount()){
				_suspectSelected = 0;
			}

			if (_suspectsFound[_suspectSelected]) {
				updateSuspectPhoto();
				break;
			}
		}
	}
}

void KIASectionCrimes::prevSuspect() {
	if (_suspectsFoundCount >= 2) {
		while (true) {
			--_suspectSelected;
			if (_suspectSelected < 0){
				_suspectSelected = _vm->_gameInfo->getSuspectCount() - 1;
			}

			if (_suspectsFound[_suspectSelected]) {
				updateSuspectPhoto();
				break;
			}
		}
	}
}

} // End of namespace BladeRunner