var Login = require ('./login');
var Gui = require ('./gui');

/**
 * The main application object.
 */
module.exports = new Class
({
	Extends: Vn.Object,
	Properties:
	{
		/**
		 * The main connection object.
		 */
		conn:
		{
			type: Db.Connection
			,get: function ()
			{
				return this._conn;
			}
		}
		/**
		 * The main screen component.
		 */
		,gui:
		{
			type: Gui
			,get: function ()
			{
				return this._gui;
			}
		}
		/**
		 * The login component.
		 */
		,login:
		{
			type: Login
			,get: function ()
			{
				return this._login;
			}
		}
	}

	,initialize: function ()
	{
		window.onerror = this._onWindowError.bind (this);
		window.onunload = this._onWindowUnload.bind (this);
		this._hash = new Vn.Hash ({window: window});

		var conn = new Db.Connection ();
		this.link ({_conn: conn}, {'error': this._onConnError});

		this.initAutoLogin ();
	}
	
	,run: function ()
	{
		if (this.tryAutoLogin ())
			return;
	
		var login = this._login = new Login ({
			conn: this._conn,
			hash: this._hash
		});
		login.on ('login', this._onLogin, this);
		login.show ();
	}
	
	,_onLogin: function ()
	{
		this._freeLogin ();
		
		var gui = this._gui = new Gui ({
			conn: this._conn,
			hash: this._hash
		});
		gui.on ('logout', this._onLogout, this);
		gui.show ();
	}
	
	,_onLogout: function ()
	{
		this.clearAutoLogin ();
		this._freeGui ();
		this.run ();
	}
	
	,_onWindowUnload: function ()
	{
		this.unref ();
	}
	
	,_onWindowError: function (message, file, line)
	{
		var error = new Error (message);
		error.fileName = file;
		error.lineNumber = line;
		this._notifyError (error);
	}

	,_onConnError: function (conn, error)
	{
		if (error instanceof Vn.JsonException)
		switch (error.exception)
		{
			case 'BadLogin':
				Htk.Toast.showError (_('Invalid login'));
				this._logout ();
				break;
			case 'SessionExpired':
				Htk.Toast.showError (_('You\'ve been too idle'));
				this._logout ();
				break;
			case 'OutdatedVersion':
				this._newVersion ();
				break;
			default:
				Htk.Toast.showError (error.message);
		}
		else
		{
			console.error (error);
			this._notifyError (error);
		}
	}
	
	,_logout: function ()
	{
		if (this._gui)
			this._gui.logout ();
	}
	
	,_newVersion: function ()
	{
		if (this.ignoreVersion)
			return;

		this.ignoreVersion = true;

		var dialog = new Htk.Dialog ({
			 message: _('New version available')
			,buttons: Htk.Dialog.Button.ACCEPT
			,icon: 'warning'
		});
		dialog.on ('response', this._onNewVersionResponse, this);
		dialog.open ();
	}
	
	,_onNewVersionResponse: function ()
	{
		location.reload ();
	}
	
	,_notifyError: function (error)
	{
		Htk.Toast.showError (_('Something went wrong'));

		var params = {
			 'file': error.fileName
			,'line': error.lineNumber
			,'message': error.message
			,'stack': error.stack
		};
		this._conn.send ('core/log', params);
	}
	
	,_freeLogin: function ()
	{
		if (this._login)
		{
			this._login.disconnectByInstance (this);
			this._login.hide ();
			this._login.unref ();
			this._login = null;
		}
	}
	
	,_freeGui: function ()
	{
		if (this._gui)
		{
			this._gui.disconnectByInstance (this);
			this._gui.hide ();
			this._gui.unref ();
			this._gui = null;
		}
	}
	
	,_destroy: function ()
	{
		this._freeLogin ();
		this._freeGui ();
		this.deinitAutoLogin ();
		this._conn.unref ();
		this._hash.unref ();
	}
	
	// Auto login functionality
	
	,_firstLogin: true

	,initAutoLogin: function ()
	{
		var isGuest = new Vn.Param
		({
			lot: this._hash,
			type: Boolean,
			name: 'guest'
		});
		this.link ({_isGuest: isGuest}, {'changed': this._onGuestChange});

		var token = new Vn.Param
		({
			lot: this._hash,
			type: String,
			name: 'token'
		});
		this.link ({_token: token}, {'changed': this._onTokenChange});
	}
	
	,_onGuestChange: function ()
	{
		if (this._isGuest.value)
			setTimeout (this.tryAutoLogin.bind (this));
	}
	
	,_onTokenChange: function ()
	{
		if (this._token.value)
			setTimeout (this.tryAutoLogin.bind (this));
	}
	
	,deinitAutoLogin: function ()
	{
		this._isGuest.unref ();
		this._token.unref ();
	}

	,autoLogin: function ()
	{
		var guest = localStorage.getItem ('hederaGuest');

		if (this._isGuest.value || guest)
		{
			localStorage.setItem ('hederaGuest', true);
			return true;
		}

		if (this._token.value)
			this._conn.token = this._token.value;
		else
			this._conn.fetchToken ();
		
		if (this._conn.token)
			return true;

		return false;
	}
	
	,tryAutoLogin: function ()
	{
		var ok = this.autoLogin ();

		this._firstLogin = false;
		this._isGuest.value = undefined;
		this._token.value = undefined;

		if (!ok)
			return false;

		this._onLogin ();
		return true;
	}
	
	,clearAutoLogin: function ()
	{
		localStorage.removeItem ('hederaGuest');
	}
});