/* 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.
 *
 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-1-1-1/engines/sci/engine/state.cpp $
 * $Id: state.cpp 48119 2010-02-23 22:47:53Z fingolfin $
 *
 */

#include "common/system.h"

#include "sci/sci.h"	// for INCLUDE_OLDGFX
#include "sci/debug.h"	// for g_debug_sleeptime_factor
#include "sci/event.h"

#include "sci/engine/state.h"
#include "sci/engine/selector.h"
#include "sci/engine/vm.h"
#include "sci/engine/script.h"
#include "sci/engine/message.h"

namespace Sci {

EngineState::EngineState(Vocabulary *voc, SegManager *segMan)
: _voc(voc), _segMan(segMan), _dirseeker() {

#ifdef USE_OLD_MUSIC_FUNCTIONS
	sfx_init_flags = 0;
#endif

	restarting_flags = 0;

	last_wait_time = 0;

	_fileHandles.resize(5);

	execution_stack_base = 0;
	_executionStackPosChanged = false;

	r_acc = NULL_REG;
	restAdjust = 0;
	r_prev = NULL_REG;

	stack_base = 0;
	stack_top = 0;

	script_000 = 0;

	_activeBreakpointTypes = 0;
	sys_strings_segment = 0;
	sys_strings = 0;

	_gameObj = NULL_REG;

	gc_countdown = 0;

	successor = 0;

	_throttleCounter = 0;
	_throttleLastTime = 0;
	_throttleTrigger = false;

	_memorySegmentSize = 0;

	_soundCmd = 0;
}

EngineState::~EngineState() {
	delete _msgState;
}

void EngineState::wait(int16 ticks) {
	uint32 time;

	time = g_system->getMillis();
	r_acc = make_reg(0, ((long)time - (long)last_wait_time) * 60 / 1000);
	last_wait_time = time;

	ticks *= g_debug_sleeptime_factor;
	_event->sleep(ticks * 1000 / 60);
}

uint16 EngineState::currentRoomNumber() const {
	return script_000->_localsBlock->_locals[13].toUint16();
}

void EngineState::setRoomNumber(uint16 roomNumber) {
	script_000->_localsBlock->_locals[13] = make_reg(0, roomNumber);
}

static kLanguage charToLanguage(const char c) {
	switch (c) {
	case 'F':
		return K_LANG_FRENCH;
	case 'S':
		return K_LANG_SPANISH;
	case 'I':
		return K_LANG_ITALIAN;
	case 'G':
		return K_LANG_GERMAN;
	case 'J':
	case 'j':
		return K_LANG_JAPANESE;
	case 'P':
		return K_LANG_PORTUGUESE;
	default:
		return K_LANG_NONE;
	}
}

Common::String SciEngine::getSciLanguageString(const char *str, kLanguage lang) const {
	kLanguage secondLang = K_LANG_NONE;

	const char *seeker = str;
	while (*seeker) {
		if ((*seeker == '%') || (*seeker == '#')) {
			secondLang = charToLanguage(*(seeker + 1));

			if (secondLang != K_LANG_NONE)
				break;
		}

		seeker++;
	}

	if ((secondLang == K_LANG_JAPANESE) && (*(seeker + 1) == 'J')) {
		// FIXME: Add Kanji support
		lang = K_LANG_ENGLISH;
	}

	if (secondLang == lang)
		return Common::String(seeker + 2);

	if (seeker)
		return Common::String(str, seeker - str);
	else
		return Common::String(str);
}

kLanguage SciEngine::getSciLanguage() {
	kLanguage lang = (kLanguage)_resMan->getAudioLanguage();
	if (lang != K_LANG_NONE)
		return lang;

	lang = K_LANG_ENGLISH;

	if (_kernel->_selectorCache.printLang != -1) {
		lang = (kLanguage)GET_SEL32V(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(printLang));

		if ((getSciVersion() >= SCI_VERSION_1_1) || (lang == K_LANG_NONE)) {
			// If language is set to none, we use the language from the game detector.
			// SSCI reads this from resource.cfg (early games do not have a language
			// setting in resource.cfg, but instead have the secondary language number
			// hardcoded in the game script).
			// SCI1.1 games always use the language setting from the config file
			// (essentially disabling runtime language switching).
			// Note: only a limited number of multilanguage games have been tested
			// so far, so this information may not be 100% accurate.
			switch (getLanguage()) {
			case Common::FR_FRA:
				lang = K_LANG_FRENCH;
				break;
			case Common::ES_ESP:
				lang = K_LANG_SPANISH;
				break;
			case Common::IT_ITA:
				lang = K_LANG_ITALIAN;
				break;
			case Common::DE_DEU:
				lang = K_LANG_GERMAN;
				break;
			case Common::JA_JPN:
				lang = K_LANG_JAPANESE;
				break;
			case Common::PT_BRA:
				lang = K_LANG_PORTUGUESE;
				break;
			default:
				lang = K_LANG_ENGLISH;
			}

			// Store language in printLang selector
			PUT_SEL32V(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(printLang), lang);
		}
	}

	return lang;
}

Common::String SciEngine::strSplit(const char *str, const char *sep) {
	kLanguage lang = getSciLanguage();
	kLanguage subLang = K_LANG_NONE;

	if (_kernel->_selectorCache.subtitleLang != -1) {
		subLang = (kLanguage)GET_SEL32V(_gamestate->_segMan, _gamestate->_gameObj, SELECTOR(subtitleLang));
	}

	Common::String retval = getSciLanguageString(str, lang);

	if ((subLang != K_LANG_NONE) && (sep != NULL)) {
		retval += sep;
		retval += getSciLanguageString(str, subLang);
	}

	return retval;
}

} // End of namespace Sci
