//===============
// Auto Demo 
//===============

var demoRecordIdx, demoGoldIdx, demoBornIdx;
var	demoTickCount;
var demoRnd, demoIdx;

function initAutoDemoRnd()
{
	demoRnd = [];
	demoRnd[0] = new rangeRandom(0, demoData1.length-1, 0); //random range 0 .. demoData1.length-1
}

var demoRecord, demoGoldDrop, demoBornPos;
var demoLevel, demoData, demoCount, demoMaxCount;
function getAutoDemoLevel(initValue)
{
	if(initValue) {
		curScore = 0;	
		runnerLife = 1;
		demoLevel = 1;
		demoCount = 1;
		demoMaxCount = 3;
		demoData = demoData1;
		levelData = playVersionInfo[0].verData;
		demoIdx = 0;
	} else {
		demoLevel++;
		demoCount++;
	}
	var idx = demoRnd[demoIdx].get();
		
	demoRecord = demoData[idx].action;
	demoGoldDrop = demoData[idx].goldDrop;
	demoBornPos = demoData[idx].bornPos;
	curLevel = demoData[idx].level;
	
	curAiVersion = demoData[idx].ai; //07/04/2014
	if("godMode" in demoData[idx]) 
		godMode = demoData[idx].godMode; //07/09/2014
}

var demoCountTime = 0, demoCountEnable = 0;
function enableAutoDemoTimer()
{
	demoCountEnable = 1;
	demoCountTime = 0;
}

function disableAutoDemoTimer()
{
	demoCountEnable = 0;
}

function countAutoDemoTimer()
{
	if(demoCountEnable) {
		demoCountTime++;
		if(demoCountTime > MAX_DEMO_WAIT_COUNT) {
			disableAutoDemoTimer();
			gameState = GAME_WAITING;	
			showCoverPage();
		}
	}
}

//=====================================
// function for auto demo & demo mode
//=====================================

function initPlayDemo()
{
	demoRecordIdx = demoGoldIdx = demoBornIdx = 0;
	demoTickCount = 0;
	playTickTimer = 0; //modern mode time counter
	gameState = GAME_RUNNING;
	
	if(playMode == PLAY_DEMO_ONCE) {
		demoIconObj.disable(1);
		selectIconObj.disable(1);
	}
}

function playDemo()
{
	if(demoRecordIdx < demoRecord.length) {
		if(demoRecord[demoRecordIdx*2] == demoTickCount) {
			//loadingTxt.text = demoRecordIdx + " " + demoTickCount ; //for debug
			pressKey(keyCodeToEventCode(demoRecord[demoRecordIdx*2+1]));
			demoRecordIdx++;
		}
	}
	demoTickCount++;
}

function getDemoGold(guard)
{
	guard.hasGold = demoGoldDrop[demoGoldIdx++];
}

function getDemoBornPos()
{
	if(demoBornPos[0] == 2) {
		demoBornIdx += 2;
		return { x: demoBornPos[demoBornIdx-1], y: demoBornPos[demoBornIdx] };
	} else {
		return { x: demoBornPos[++demoBornIdx], y: 1 };
	}
}

//====================================
// for demo mode (User select level)
//====================================

var playerDemoData = [], wDemoData = [];
var demoPlayData = 0; //for syn demo data with current playData
var demoDataLoading = 0;

function initDemoData()
{
	demoPlayData = playData;
	playerDemoData = [];
	wDemoData = [];
	demoDataLoading = 1; 
	getDemoData(playData); //ajax 
}

function setDemoData(jsonTxt)
{
	if(jsonTxt.substring(0, 1) == "[" ) { 		
		wDemoData = JSON.parse(jsonTxt);
		for(var i = 0; i < wDemoData.length; i++) {
			playerDemoData[wDemoData[i].level-1] = wDemoData[i]; 
		}
	} else {
		error("Wrong Demo Data: " + jsonTxt);
	}
	demoDataLoading = 0; 
	if(playMode == PLAY_MODERN && gameState == GAME_START ) demoIconObj.enable();
}

function initDemoInfo()
{
	var idx = curLevel - 1;
	
	curScore = 0;	
	runnerLife = 1;
		
	demoRecord = demoData[idx].action;
	demoGoldDrop = demoData[idx].goldDrop;
	demoBornPos = demoData[idx].bornPos;
	assert(curLevel == demoData[idx].level, "curLevel != level of demoData");	
	
	curAiVersion = demoData[idx].ai; //07/04/2014
	if("godMode" in demoData[idx]) 
		godMode = demoData[idx].godMode; //07/09/2014
}

function getDemoOnceInfo() //for demo once
{
	//DEMO ONCE in Training mode, so curLevel & levelData are same as training mode 
	demoData = playerDemoData;
	initDemoInfo();	
}

function getDemoInfo()
{
	var infoJSON;

	if (playData >= 1 && playData <= maxPlayId) {
		infoJSON = getStorage(STORAGE_DEMO_INFO + playData); 
		levelData = getPlayVerData(playData);
		//demoData = playerDemoData[playData-1];
		demoData = playerDemoData;
	} else {
		error("design error, value =" + playData );
	}	

	if(infoJSON == null) {
		curLevel = 1;
	} else {
		var infoObj = JSON.parse(infoJSON);
		curLevel = infoObj.l;
	}
	getValidDemoLevel();
	initDemoInfo();	
}

function setDemoInfo()
{
	var infoObj = { l:curLevel};
	var infoJSON = JSON.stringify(infoObj);

	if (playData >= 1 && playData <= maxPlayId) {
		setStorage(STORAGE_DEMO_INFO + playData, infoJSON); 	
	} else {
		error("design error, value =" + playData );
	}	
}

function getValidDemoLevel()
{
	while(typeof demoData[curLevel-1] == "undefined") {
		if(++curLevel > levelData.length) curLevel = 1;
	}
}

function getNextDemoLevel()
{
	getValidDemoLevel();
	setDemoInfo();
	initDemoInfo();
}

function curDemoLevelIsValid()
{
	if(playData == PLAY_DATA_USERDEF) return 0;
	return (playerDemoData.length >= curLevel && typeof playerDemoData[curLevel-1] != "undefined");
}

function updatePlayerDemoData(playData, demoDataInfo)
{
	var level = demoDataInfo.level;
	
	playerDemoData[level-1] = { 
		level: demoDataInfo.level, 
		ai: demoDataInfo.ai, 
		time: demoDataInfo.time, 
		state: demoDataInfo.state,
		action: demoDataInfo.action,
		goldDrop: demoDataInfo.goldDrop,
		bornPos: demoDataInfo.bornPos,
		godMode: demoDataInfo.godMode,
		player: playerName,
		date:   getLocalTime(),
		location: "Unknown", //update by sendDemoData2Server() resp.
		cId: "Unknown",
		ip: "updating"
	};
}

//======================
// resp from server
//======================
function respUpdatePlayerDemoData(jsonTxt)
{
	var respObj, level;
	
	if(jsonTxt.substring(0, 1) == "{" ) { 		
		respObj = JSON.parse(jsonTxt);
		level = respObj.level;
		
		if(respObj.playData == playData && playerDemoData[level-1].ip == "updating") {
			playerDemoData[level-1].ip = respObj.ip;
			playerDemoData[level-1].location = respObj.location;
			playerDemoData[level-1].cId = respObj.cId;
		}
	} else {
		error("Wrong resp Data: " + jsonTxt);
	}
}

//==============================
// Record play action for demo
//==============================

var RECORD_NONE = 0, RECORD_KEY = 1, RECORD_PLAY = 2;
var recordMode = RECORD_KEY; 
//var recordMode = RECORD_NONE; 

var recordCount, recordKeyCode = 0, lastKeyCode = -1;
var playRecord, goldRecord, bornRecord;
var goldRecordIdx, bornRecordIdx;
var playRecordTime, recordState;

function initRecordVariable()
{
	recordCount = 0;
	goldRecordIdx = 0;
	bornRecordIdx = 0;
	playRecordTime = 0;

	switch(recordMode) {
	case RECORD_KEY:
		recordKeyCode = 0;
		lastKeyCode = -1;	
		playRecord = [];
		goldRecord = [];
		bornRecord = [];
		break;
	case RECORD_PLAY:		
		recordIdx = 0;
		gameState = GAME_RUNNING;
		break;
	}
}

var alwaysRecord = 0, keyPressed = 0;
function saveKeyCode(code, keyAction)
{
	//-----------------------------------------------------------------------------
	// Don't care repeat times, always record key when press dig-left or dig-right 
	// fixed by Simon 12/12/2014
	//-----------------------------------------------------------------------------
	alwaysRecord = 0;
	if(keyAction == ACT_DIG_LEFT || keyAction == ACT_DIG_RIGHT) alwaysRecord = 1;
		
	recordKeyCode = code;
	keyPressed = 1;
}

function recordModeDump(state)
{
	recordPlayTime(state);
	remapActionKey();
	convertBornPos();
	dumpRecord();
}


function recordModeToggle(state)
{
	if(recordMode == RECORD_KEY) {
		if(playMode != PLAY_AUTO && playMode != PLAY_DEMO && playMode != PLAY_DEMO_ONCE) recordMode = RECORD_PLAY;
		recordModeDump(state);
	} else recordMode = RECORD_KEY;
}

function processRecordKey()
{
	switch(recordMode) {
	case RECORD_KEY: //record the play key action
		recordKeyAction();
		break;
	case RECORD_PLAY: //play the record key 
		recordPlayDemo();
		break;
	}	
	recordCount++;
}

function recordKeyAction()
{
	if(repeatAction) recordKeyAction1();
	else recordKeyAction2()
}

//record key for "keyboard repeat on"	   
function recordKeyAction1()
{
	if(!keyPressed) return;
	if(recordKeyCode != lastKeyCode || alwaysRecord) {
		playRecord.push(recordCount);
		code=codeToEventKeyCode(recordKeyCode)
		playRecord.push(codeToEventKeyCode(recordKeyCode));
		lastKeyCode = recordKeyCode;
	}
	keyPressed = 0;
}

//record key for "keyboard repeat off"
// keyPressed= 1:pressed, 0:released, -1:floating (do nothing till pressed again)
function recordKeyAction2()
{
	switch(keyPressed) {
	case 1: //pressed
		if(recordKeyCode != lastKeyCode || alwaysRecord) {
			playRecord.push(recordCount);
			code=codeToEventKeyCode(recordKeyCode)
			playRecord.push(codeToEventKeyCode(recordKeyCode));
			lastKeyCode = recordKeyCode;
		}
		if(alwaysRecord) keyPressed = -1; //floating
		break;
	case 0:	//release	
		if(recordKeyCode != "Space") { 
			playRecord.push(recordCount);
			playRecord.push(codeToEventKeyCode("Space"));
			lastKeyCode = recordKeyCode = "Space";
			keyAction = ACT_STOP;
		}
		break;
	}
}

var recordIdx;

function recordPlayDemo()
{
	if(recordIdx < playRecord.length) {
		if(playRecord[recordIdx*2] == recordCount) {
			//loadingTxt.text = recordIdx;  //for debug
			code=playRecord[recordIdx*2+1];
			pressKey(keyCodeToEventCode(demoRecord[demoRecordIdx*2+1]));
			recordIdx++;
		}
	}
}

function processRecordGold(guard)
{
	switch(recordMode) {
	case RECORD_KEY: //record the play key action, save gold
		goldRecord.push(guard.hasGold);
		break;
	case RECORD_PLAY: //play the record key, get gold 
		guard.hasGold = goldRecord[goldRecordIdx++];
		break;
	}	

}

function saveRecordBornPos(x, y)
{
	bornRecord.push({ x:x, y:y });
}

function getRecordBornPos()
{
	if(bornRecord[0] == 2) {
		bornRecordIdx += 2;
		return { x: bornRecord[bornRecordIdx-1], y: bornRecord[bornRecordIdx] };
	} else {
		return { x: bornRecord[++bornRecordIdx], y: 1 };
	}
}

function recordPlayTime(state)
{
	playRecordTime = recordCount;
	recordState = (state == GAME_FINISH)?1:0; //finish or dead
}

//Remap action key to orignal "left, right, up down and Z, X"
//for backward compatible
function remapActionKey()
{
	for(var i = 0; i < playRecord.length; i+=2){
		for(var j = 0; j < actionKeyMapping.length; j++) {
			if(actionKeyMapping[j][0] == playRecord[i+1]) {
				playRecord[i+1] = actionKeyMapping[j][1];
				break;
			}
		}
	}
}

function codeToEventKeyCode(code)
{
	for (const [key, value] of Object.entries(MAPKEYCODE)) {
		if (value === code) {
			return Number(key);
		}
	}
	return 0;
}

function keyCodeToEventCode(keyCode)
{
 	return MAPKEYCODE[keyCode] || "";
}

function convertBornPos()
{
	var len, offset = 1;
	var tmpRecord = [];
	
	if((len = bornRecord.length) <= 0) return;
	
	for(var i = 0; i < len; i++) if(bornRecord[i].y != 1) offset = 2;
	
	tmpRecord[0] = offset;
	for(var i = 0; i < len; i++) {
		tmpRecord[i*offset+1] = bornRecord[i].x;
		if(offset == 2) tmpRecord[i*offset+2] = bornRecord[i].y;
	}
	bornRecord = tmpRecord;
}

var curDemoData = { ai: AI_VERSION, time: 0 }; //bug fixed: when press CTRL-C without demo data
function dumpRecord()
{
	var txtStr;	
	curDemoData = {};
	curDemoData.level = curLevel;
	curDemoData.ai = AI_VERSION;
	curDemoData.time = playRecordTime;
	curDemoData.state = recordState; //game finish or not
	curDemoData.action = [];
	curDemoData.goldDrop = [];
	curDemoData.bornPos = [];
	curDemoData.godMode = godModeKeyPressed; //07/09/2014

	for(var i = 0; i < playRecord.length; i++) {
		curDemoData.action[i] = playRecord[i];
	}
	
	for(var i = 0; i < goldRecord.length; i++) {
		curDemoData.goldDrop[i] = goldRecord[i];
	}
	
	for(var i = 0; i < bornRecord.length; i++) {
		curDemoData.bornPos[i] = bornRecord[i];
	}

	debug(curDemoData);
	
	debug("	{ level: " + curLevel + ","); 
	debug("		ai: " + AI_VERSION + ","); 
	debug("		time: " + playRecordTime + ",");
	debug("		state: " + recordState + ",");
	debug("		godMode: " + godModeKeyPressed + ","); //07/09/2014

	if(playRecord.length > 0) {
		txtStr = "		action: [ " + playRecord[0];
		for(var i = 1; i < playRecord.length; i++) {
			txtStr += ", " + playRecord[i];
		}
		debug(txtStr+ " ],");
	} else {
		debug("		action: [ ],");
	}
	
	if(goldRecord.length > 0) {
		txtStr = "		goldDrop: [ " + goldRecord[0];
		for(var i = 1; i < goldRecord.length; i++) {
			txtStr += ", " + goldRecord[i];
		}
		debug(txtStr+ " ],");
	} else {
		debug("		goldDrop: [ ],");
	}
	if( bornRecord.length > 0) {
		txtStr = "		bornPos: [ " + bornRecord[0];
		for(var i = 1; i < bornRecord.length; i++) {
			txtStr += ", " + bornRecord[i];
		}
		debug(txtStr+" ]");
	} else {
		debug("		bornPos: [ ]");
	}
	
	debug("	},");
}
