+using Gee;
+
+public Gee.HashMap <string, MovieSearch> searches;
+public DBus.Connection conn;
+
+[DBus (name = "org.maemo.cinaest.MovieSearch", signals="movies_found")]
+public class MovieSearch : Object {
+ public int id;
+ bool aborted;
+ string title;
+ GoogleParser parser;
+ GLib.List<GoogleMovie> results;
+ GoogleMovieService service;
+
+ // D-Bus API
+
+ public void abort () {
+ print ("aborting\n");
+ aborted = true;
+ }
+
+ public void start (string query) {
+ parser = new GoogleParser ();
+ title = query;
+
+ query_async.begin ();
+ }
+
+ public signal void movies_found (string[] movies, bool finished);
+
+ // Internal methods
+
+ internal MovieSearch (GoogleMovieService _service) {
+ service = _service;
+ }
+
+ private async void query_async () {
+ var gc = GConf.Client.get_default ();
+
+ results = new GLib.List<GoogleMovie> ();
+
+ string location = null;
+ try {
+ location = gc.get_string ("/apps/cinaest/location");
+ } catch (Error e) {
+ stdout.printf ("Error getting GConf option: %s\n", e.message);
+ }
+ if (location == null)
+ location = "";
+
+ int n = yield parser.query (title, location, receive_movie);
+
+ try {
+ var locations = ((SList<string>) gc.get_list ("/apps/cinaest/locations", GConf.ValueType.STRING)).copy ();
+ if (insert_location_sorted (parser.location, ref locations)) {
+ gc.set_list ("/apps/cinaest/locations", GConf.ValueType.STRING, locations);
+ }
+ if (location != parser.location) {
+ location = parser.location;
+ gc.set_string ("/apps/cinaest/location", location);
+ }
+ } catch (Error e2) {
+ stdout.printf ("GConf error: %s\n", e2.message);
+ }
+
+ print ("got %d movies\n", n);
+
+ var m = new string[results.length ()];
+ int i = 0;
+ for (unowned GLib.List<GoogleMovie> node = results.first (); node != null; node = node.next) {
+ m[i++] = "{\"title\":\"%s\",\"rating\":%f,\"showtimes\":\"%s\",\"cinema_name\":\"%s\",\"cinema_phone\":\"%s\"}".printf (node.data.title, node.data.rating, node.data.showtimes, node.data.cinema.name, node.data.cinema.phone);
+ }
+ movies_found (m, true);
+ service.timeout_quit ();
+ }
+
+ private bool insert_location_sorted (string? location, ref SList<string> locations) {
+ if (location == null)
+ return false;
+ if (locations != null) {
+ for (unowned SList<string> l = locations; l != null; l = l.next) {
+ if (l.data == location) {
+ return false;
+ }
+ if (l.data > location) {
+ l.insert (location, 0);
+ return true;
+ }
+ }
+ }
+ locations.append (location);
+ return true;
+ }
+
+ private void receive_movie (GoogleMovie movie) {
+ // print ("received %s\n", movie.title);
+ results.append (movie);
+ }
+}
+
+[DBus (name = "org.maemo.cinaest.MovieService")]
+public class GoogleMovieService : Object {
+ private MainLoop loop;
+ private uint source_id;
+
+ // D-Bus API
+
+ public string new_search (DBus.BusName sender) {
+ print ("new search requested by %s\n", sender);
+ var search = new MovieSearch (this);
+
+ search.id = searches.size;
+ string path = "/org/maemo/cinaest/googleshowtimes/search%d".printf (search.id);
+ conn.register_object (path, search);
+
+ searches.set (path, search);
+
+ return path;
+ }
+
+ public void unregister (string path) {
+
+ print ("unregistering %s\n", path);
+ searches.remove (path);
+ print ("%d\n", searches.size);
+ }
+
+ // Internal methods
+
+ internal GoogleMovieService () {
+ loop = new MainLoop (null);
+ }
+
+ internal void timeout_quit () {
+ // With every change we reset the timer to 3min
+ if (source_id != 0) {
+ Source.remove (source_id);
+ }
+ source_id = Timeout.add_seconds (180, quit);
+ }
+
+ private bool quit () {
+ loop.quit ();
+
+ // One-shot only
+ return false;
+ }
+
+ internal void run () {
+ loop.run ();
+ }
+}
+
+void on_client_lost (DBus.Object sender, string name, string prev, string newp) {
+ if (newp == "") {
+ // We lost a client
+ print ("lost a client: prev:%s\n", prev);
+ searches.remove (prev);
+ }
+}
+
+void main () {
+ var loop = new MainLoop (null, false);
+
+ try {
+ conn = DBus.Bus.get (DBus.BusType. SESSION);
+
+ searches = new Gee.HashMap <string, MovieSearch> ();
+
+ dynamic DBus.Object bus = conn.get_object ("org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus");
+
+ uint res = bus.request_name ("org.maemo.cinaest.GoogleShowtimes", (uint) 0);
+
+ if (res == DBus.RequestNameReply.PRIMARY_OWNER) {
+ var server = new GoogleMovieService ();
+
+ conn.register_object ("/org/maemo/cinaest/movies", server);
+
+ bus.NameOwnerChanged.connect (on_client_lost);
+
+ server.timeout_quit ();
+ server.run ();
+ }
+ } catch (Error e) {
+ stderr.printf ("Oops: %s\n", e.message);
+ }
+}