import { SmartFox, SFSEvent, EventParam, ClientDisconnectionReason } from 'sfs3-api';
import * as bootstrap from 'bootstrap';

import PreloadController from './controllers/preload-controller.js';
import LoginController from './controllers/login-controller.js';
import LobbyController from './controllers/lobby-controller.js';
import GameController from './controllers/game-controller.js';

document.addEventListener('DOMContentLoaded', () => {
	new Application();
});

//--------------------------------------------------------------------

class Application
{
	constructor()
	{
		this.currCtrl = null;
		this.controllers = new Map();

		// Get reference to views
		const preloadView = document.getElementById('preloadView');
		const loginView = document.getElementById('loginView');
		const lobbyView = document.getElementById('lobbyView');
		const gameView = document.getElementById('gameView');

		// Create controllers instances
		const preloadCtrl = new PreloadController(this, preloadView, 'preload');
		const loginCtrl = new LoginController(this, loginView, 'login');
		const lobbyCtrl = new LobbyController(this, lobbyView, 'lobby');
		const gameCtrl = new GameController(this, gameView, 'game');

		// Add to map
		this.controllers.set(preloadCtrl.name, preloadCtrl);
		this.controllers.set(loginCtrl.name, loginCtrl);
		this.controllers.set(lobbyCtrl.name, lobbyCtrl);
		this.controllers.set(gameCtrl.name, gameCtrl);

		// Create warning modal
		this.warningModal = new bootstrap.Modal(document.getElementById('warningModal'), {
			backdrop: true,
			focus: true,
			keyboard: true
		});

		// Go to initial view
		this.goToView('preload');
	}

	goToView(name)
	{
		if (this.currCtrl != null && this.currCtrl.name == name)
			return;

		// Hide all modals
		this.hideModals();

		// Destroy old controller (which also hides view)
		if (this.currCtrl != null)
			this.currCtrl.destroy();

		// Init new controller (which also shows view)
		if (this.controllers.has(name))
		{
			this.currCtrl = this.controllers.get(name);
			this.currCtrl.initialize();
		}
		else
			console.error(`Requested controller "${name}" not found`);
		
	}

	/**
	 * Return an existing SmartFox class instance, or creates a new one.
	 * The CONNECTION_LOST listener is also added.
	 */
	getSfsClient()
	{
		if (this.sfs == null)
		{
			this.sfs = new SmartFox();
			this.sfs.addEventListener(SFSEvent.CONNECTION_LOST, this.onConnectionLost, this);
		}

		return this.sfs;
	}

    trace(str)
    {
        console.log('%c' + str, 'color: #6FBFF9');
    }

	hideModals()
	{
		document.querySelectorAll('.modal').forEach(modal => {
			const modalInstance = bootstrap.Modal.getInstance(modal);
			if (modalInstance)
				modalInstance.hide();
		});
	}

	showWarningModal(msg)
	{
		document.getElementById('warningModal').querySelector('#errorMsg').innerText = msg;
		this.warningModal.show();
	}

	//----------------------------------------------------------
	// SmartFoxServer event listeners
	//----------------------------------------------------------

	onConnectionLost(evtParams)
	{
		this.sfs = null;

		// Get disconnection reason
		const reason = evtParams[EventParam.DisconnectionReason];

		this.trace(`Connection to SmartFoxServer lost; reason is: ${reason}`);

		// Switch to login view
		this.goToView('login');

		// Show disconnection reason
		if (reason != ClientDisconnectionReason.MANUAL)
		{
			// Save disconnection message, which can be retrieved by the LOGIN scene to display an error message
			let connLostMsg = 'An unexpected disconnection occurred.\n';

			switch (reason)
			{
				case ClientDisconnectionReason.IDLE:
					connLostMsg += 'It looks like you have been idle for too much time.';
					break;
				
				case ClientDisconnectionReason.KICKED:
					connLostMsg += 'You have been kicked by an administrator or moderator.';
					break;
				
				case ClientDisconnectionReason.BANNED:
					connLostMsg += 'You have been banned by an administrator or moderator.';
					break;
				
				default:
					connLostMsg += "The reason of the disconnection is unknown.";
			}

			// Show disconnection message
			this.currCtrl.showErrorMsg(connLostMsg);
		}
	}
}