/* hev-gabble-monitor.vala
 * Heiher <admin@heiher.info>
 */

using TelepathyGLib;

namespace Hev {

	namespace Gabble {

		private const string CONSOLE_IFACE = "org.freedesktop.Telepathy.Gabble.Plugin.Console";

		[DBus (name = "org.freedesktop.Telepathy.Connection.FUTURE")]
		public interface Future : GLib.Object {
			public abstract async void ensure_sidecar (string iface, out ObjectPath path,
						out HashTable<string, Variant> props) throws IOError;
		}

		[DBus (name ="org.freedesktop.Telepathy.Gabble.Plugin.Console")]
		public interface Console : GLib.Object {
			public abstract bool spew_stanzas { get; set; }

			public abstract async void send_i_q (string to, string body,
						out string reply_type, out string out_body) throws IOError;
			public abstract async void send_stanza (string stanza) throws IOError;

			public signal void stanza_sent (string stanza);
			public signal void stanza_received (string stanza);
		}

		public class Monitor : GLib.Object {

			private Console console = null;

			public Monitor (Connection conn) {
				debug ("Monitor");

				Bus.get_proxy.begin<Future> (BusType.SESSION, conn.bus_name,
							conn.get_object_path (), DBusProxyFlags.NONE, null, (obj, res) => {
						Future future = null;

						try {
							future = Bus.get_proxy.end (res);
						} catch (IOError e) {
							critical ("%s", e.message);
						}

						if (null != future) {
							future.ensure_sidecar.begin (CONSOLE_IFACE, (obj, res) => {
									ObjectPath p = null;
									HashTable<string, Variant> props = null;

									try {
										(obj as Future).ensure_sidecar.end (res, out p, out props);
									} catch (IOError e) {
										critical ("%s", e.message);
									}

									if (null != p) {
										Bus.get_proxy.begin<Console> (BusType.SESSION,
													conn.bus_name, p, DBusProxyFlags.NONE,
													null, (obj, res) => {
												try {
													this.console = Bus.get_proxy.end (res);
												} catch (IOError e) {
													critical ("%s", e.message);
												}

												if (null != this.console) {
													this.console.spew_stanzas = true;
													this.console.stanza_sent.connect ((s) => {
															print ("%s", s);
														});
													this.console.stanza_received.connect ((s) => {
															print ("%s", s);
														});
												}
											});
									}
								});
						}
					});
			}

			~Monitor () {
				debug ("~Monitor");
			}
		}

		public class Manager : GLib.Object {

			private MainLoop main_loop = null;
			private AccountManager am = null;
			private SList<Monitor> monitors = null;

			public Manager () {
				debug ("Manager");

				this.main_loop = new MainLoop ();
				this.monitors = new SList<Monitor> ();

				this.am = AccountManager.dup ();
				Quark[] features = {
					AccountManager.get_feature_quark_core () };
				this.am.prepare_async.begin (features, (obj, res) => {
						var succ = false;
						try {
							succ = (obj as AccountManager).prepare_async.end (res);
						} catch (GLib.Error e) {
							critical ("%s", e.message);
						}
						if (succ) {
							enumerate ();
						}
					});
			}

			~Manager () {
				debug ("~Manager");
			}

			public void run () {
				this.main_loop.run ();
			}

			public void quit () {
				this.main_loop.quit ();
			}

			private void enumerate () {
				foreach (var a in this.am.get_valid_accounts ()) {
					if ("gabble" == a.connection_manager) {
						if (null != a.connection) {
							var monitor = new Monitor (a.connection);
							this.monitors.append (monitor);
						}
					}
				}
			}

			public static int main (string[] args) {
				uint sigint_id = 0;
				uint sigterm_id = 0;
				var manager = new Manager ();
				SourceFunc signal_handler = () => {
						manager.quit ();
						return true;
					};

				sigint_id = Unix.signal_add (Posix.SIGINT,
							(owned) signal_handler);
				sigterm_id = Unix.signal_add (Posix.SIGTERM,
							(owned) signal_handler);

				manager.run ();

				Source.remove (sigint_id);
				Source.remove (sigterm_id);

				return 0;
			}
		}
	}
}

