/*
	
	IRC-Bot "Kvasir"
    Copyright (C) 2016	Fenris Wolf (fenris@folksprak.org)
	
    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 3 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, see <http://www.gnu.org/licenses/>.
       
*/

type tipo_ero = {kromajxo : klaso_kromajxo; aktiva : boolean;};


/**
 * @author fenris
 */
abstract class klaso_kliento
{
	
	/**
	 * @author fenris
	 */
	protected kromajxoj : {[identigilo : string] : tipo_ero};
	
	
	/**
	 * @author fenris
	 */
	protected vico_eliga : klaso_vico<klaso_evento_eliga>;
	
	
	/**
	 * @author fenris
	 */
	protected prokrasto : int;
	
	
	/**
	 * @author fenris
	 */
	protected foo : any;
	
	
	/**
	 * @author fenris
	 */
	public constructor(prokrasto : int = null)
	{
		this.kromajxoj = {};
		this.vico_eliga = new klaso_vico<klaso_evento_eliga>();
		this.foo = null;
		this.prokrasto = prokrasto;
	}
	
	
	/**
	 * @author fenris
	 */
	public stirado_arangxi
	(
		permesuloj : Array<string> = []
	)
	{
		let that : klaso_kliento = this;
		this.kromajxo_aldoni
		(
			new klaso_kromajxo_stirado
			(
				permesuloj,
				{
					"anigxi": function (kanalo : string, modo : boolean = true) : tipo_plenumanto<Array<string>, Error>
					{
						return (
							(akcepti, rifuzi) =>
							{
								that.anigxi_rekte(kanalo, modo);
								akcepti([]);
							}
						)
					},
					"listigi": function () : tipo_plenumanto<Array<string>, Error>
					{
						return (
							(akcepti, rifuzi) =>
							{
								let enhavo : string = Object.keys(that.kromajxoj).map(identigilo => (that.kromajxoj[identigilo].aktiva ? "+" : "-") + identigilo).join(", ");
								akcepti([enhavo]);
							}
						);
					},
					"detaloj": function (identigilo : string) : tipo_plenumanto<Array<string>, Error>
					{
						return (
							(akcepti, rifuzi) =>
							{
								if (identigilo in that.kromajxoj)
								{
									let ero : tipo_ero = that.kromajxoj[identigilo];
									let linioj : Array<string> =
									[
										{"titolo": "nomo", "valoro": ero.kromajxo.nomo_legi()},
										{"titolo": "auxtoro", "valoro": ero.kromajxo.auxtoro_legi()},
										{"titolo": "priskribo", "valoro": ero.kromajxo.priskribo_legi()},
										{"titolo": "uzo", "valoro": ero.kromajxo.uzo_legi()},
										{"titolo": "aktiva", "valoro": (ero.aktiva ? "jes" : "ne")},
									].map(x => ("--" + " " + x.titolo + ": " + x.valoro));
									akcepti(linioj);
								}
								else
								{
									akcepti(["tia kromajxo ne ekzistas"]);
								}
							}
						);
					},
					"sxalti": function (identigilo : string, aktiva : boolean = null) : tipo_plenumanto<Array<string>, Error>
					{
						return (
							(akcepti, rifuzi) =>
							{
								if (identigilo in that.kromajxoj)
								{
									if (identigilo != "stirado")
									{
										let aktiva_ : boolean = (aktiva != null) ? aktiva : (! that.kromajxoj[identigilo].aktiva);
										that.kromajxoj[identigilo].aktiva = aktiva_;
										akcepti(["kromajxo '" + identigilo + "' " + (aktiva_ ? "aktivigita" : "malaktivigita") + ""]);
									}
									else
									{
										akcepti(["vi ne vere volas malsxalti la stirad-kromajxon ..."]);
									}
								}
								else
								{
									akcepti(["tia kromajxo ne ekzistas"]);
								}
							}
						);
					},
					"resxargi": function (identigilo : string) : tipo_plenumanto<Array<string>, Error>
					{
						return (
							(akcepti, rifuzi) =>
							{
								let ero : tipo_ero = that.kromajxoj[identigilo];
								if (ero.kromajxo instanceof klaso_kromajxo_ekstera)
								{
									let kromajxo : klaso_kromajxo_ekstera = <klaso_kromajxo_ekstera>(ero.kromajxo);
									kromajxo.resxargi
									(
										function (eraro : Error) : void
										{
											if (eraro != null)
											{
												console.warn(eraro);
												akcepti(["resxargado fiaskis; detaloj trovigxas je la konzolo"]);
											}
											else
											{
												akcepti(["kromajxo '" + identigilo + "' resxargita"]);
											}
										}
									);
								}
								else
								{
									akcepti(["nur eksteraj kromajxoj resxargeblas"]);
								}
							}
						);
					},
					"aldoni": function (nomo : string) : tipo_plenumanto<Array<string>, Error>
					{
						return (
							(akcepti, rifuzi) =>
							{
								if ((new RegExp("\\S")).test(nomo))
								{
									// let vojo : string = "kromajxoj/" + nomo + ".js";
									let vojo : string = nomo;
									klaso_kromajxo_ekstera.krei
									(
										vojo,
										function (eraro : Error, kromajxo : klaso_kromajxo_ekstera) : void
										{
											if (eraro != null)
											{
												console.warn(eraro);
												akcepti(["aldoni kromajxon fiaskis"]);
											}
											else
											{
												that.kromajxo_aldoni
												(
													kromajxo,
													undefined,
													undefined,
													function (eraro_ : Error) : void
													{
														if (eraro_ != null)
														{
															console.warn(eraro_);
															akcepti(["kromajx-aldonado fiaskis"]);
														}
														else
														{
															akcepti(["kromajxo sukcese aldonita"]);
														}
													}
												);
											}
										}
									);
								}
								else
								{
									akcepti(["nevalida"]);
								}
							}
						);
					},
					"elmontri_helpon": function () : tipo_plenumanto<Array<string>, Error>
					{
						return (
							(akcepti, rifuzi) =>
							{
								akcepti
								(
									[
										"'!kromajxo listigi': listigi la nomojn de cxiuj kromajxoj kaj elmontri cxu ili estas sxaltitaj",
										"'!kromajxo detaloj [nomo]': elmontri detalojn pri la kromajxo kun la nomo [nomo]",
									]
								);
							}
						);
					},
				}
			)
		);
	}
	
	
	/**
	 * @author fenris
	 */
	public kromajxo_aldoni(kromajxo : klaso_kromajxo, aktiva : boolean = true, anstatauxigi : boolean = false, finado : (eraro ?: Error)=>void = vokado_nenio) : void
	{
		let that : klaso_kliento = this;
		kromajxo.starigi
		(
			function (eraro : Error) : void
			{
				if (eraro != null)
				{
					finado(eraro);
				}
				else
				{
					let identigilo : string = kromajxo.identigilo_legi();
					if (identigilo in that.kromajxoj)
					{
						if (anstatauxigi && (identigilo != "stirado"))
						{
							let mesagxo : string = ("kromajxo '" + identigilo + "' jam registrita; gxi anstatauxigatos");
							console.warn(mesagxo);
							that.kromajxoj[identigilo] = {"kromajxo": kromajxo, "aktiva": aktiva};
							finado(null);
						}
						else
						{
							let mesagxo : string = ("kromajxo '" + identigilo + "' jam registrita; gxi NE anstatauxigatos");
							finado(new Error(mesagxo));
						}
					}
					else
					{
						that.kromajxoj[identigilo] = {"kromajxo": kromajxo, "aktiva": aktiva};
						finado(null);
					}
				}
			}
		);
	}
	
	
	/**
	 * @author fenris
	 */
	public abstract konekti(parametroj : Object, fino : ()=>void) : void;
	
	
	/**
	 * @author fenris
	 */
	public enigi(enigo : klaso_evento_eniga) : void
	{
		let that : klaso_kliento = this;
		Object.keys(this.kromajxoj).forEach
		(
			function (identigilo : string) : void
			{
				let ero : tipo_ero = that.kromajxoj[identigilo];
				{
					if (ero.aktiva)
					{
						ero.kromajxo.enigi
						(
							enigo,
							function (eligo : klaso_evento_eliga) : void
							{
// console.info("--", "eniga fonto estis '" + enigo["fonto"] + "'");
								try
								{
									if (! enigo["fonto"].startsWith("#"))
									{
// console.info("--", "..., kiuj sxajne ne estas kanalo; la eliga celo estis '" + eligo["celo"] + "' kaj estos '" + enigo["sendinto"] + "' nun");
										eligo["celo"] = enigo["sendinto"];
									}
								}
								catch (escepto)
								{
									console.warn(escepto);
								}
								that.eligi(eligo);
							}
						)
					}
				}
			}
		);
	}
	
	
	/**
	 * @author fenris
	 */
	protected abstract eligi_rekte(eligo : klaso_evento_eliga) : void;
	
	
	/**
	 * @author fenris
	 */
	protected abstract anigxi_rekte(kanalo : string, modo : boolean) : void;
	
	
	/**
	 * @author fenris
	 */
	protected eligi(eligo : klaso_evento_eliga) : void
	{
		let that : klaso_kliento = this;
		
		function fari() : void
		{
			if (that.vico_eliga.malplena())
			{
				clearInterval(that.foo);
				that.foo = null;
			}
			else
			{
				that.eligi_rekte(that.vico_eliga.preni());
			}
		}
		
		if (this.prokrasto == null)
		{
			that.eligi_rekte(eligo);
		}
		else
		{
			this.vico_eliga.doni(eligo);
			if (this.foo == null)
			{
				fari();
				this.foo = setInterval(fari, this.prokrasto);
			}
		}
	}
	
}