Turn lift date and time strings into struct Time
[beifahrer] / src / adac-mitfahrclub.vala
index 2d080e0..516c9af 100644 (file)
@@ -49,8 +49,7 @@ public enum LiftFlags {
 public class Lift : Object {
        public string city_from;
        public string city_to;
-       public string date;
-       public string time;
+       public Time time;
        public int places;
        public string price;
        public LiftFlags flags;
@@ -65,37 +64,44 @@ public class Lift : Object {
        public string email;
        public string description;
        public string modified;
+
+       public Lift () {
+               time.hour = -1;
+       }
+}
+
+public class CallbackMessage : Soup.Message {
+       public SourceFunc callback;
+
+       public CallbackMessage (string url, SourceFunc? _callback) {
+               method = "GET";
+               callback = _callback;
+               set_uri (new Soup.URI (url));
+       }
 }
 
 public class AdacMitfahrclub {
        const string BASE_URI = "http://mitfahrclub.adac.de";
 
-       string response;
-       int size;
+       Soup.SessionAsync session;
+       Soup.Message message;
        List<City> city_list = null;
 
-       static size_t write_memory_cb (void* ptr, size_t size, size_t nmemb, void* data) {
-               unowned AdacMitfahrclub self = (AdacMitfahrclub) data;
-
-               self.response += ((string) ptr).ndup (size * nmemb);
-               self.size += (int) (size * nmemb);
-
-               return size * nmemb;
+       public AdacMitfahrclub () {
+               session = new Soup.SessionAsync ();
        }
 
-       private Html.Doc* get_html_document (string url) {
-               var handle = new Curl.EasyHandle ();
-
-               handle.setopt (Curl.Option.URL, url);
-               handle.setopt (Curl.Option.WRITEFUNCTION, write_memory_cb);
-               handle.setopt (Curl.Option.WRITEDATA, (void*) this);
+       private void message_finished (Soup.Session session, Soup.Message message) {
+               Idle.add (((CallbackMessage) message).callback);
+       }
 
-               this.response = "";
-               this.size = 0;
+       private async Html.Doc* get_html_document (string url) {
+               message = new CallbackMessage (url, get_html_document.callback);
+               session.queue_message (message, message_finished);
 
-               handle.perform ();
+               yield;
 
-               return Html.Doc.read_memory ((char[]) this.response, this.size,
+               return Html.Doc.read_memory ((char[]) message.response_body.data, (int) message.response_body.length,
                                             url, null, Html.ParserOption.NOERROR | Html.ParserOption.NOWARNING);
        }
 
@@ -156,24 +162,28 @@ public class AdacMitfahrclub {
                if (load_city_list ())
                        return city_list;
 
-               var doc = get_html_document (BASE_URI);
+               return null;
+       }
+
+       public async unowned List<City>? download_city_list () {
+               var doc = yield get_html_document (BASE_URI);
                if (doc == null) {
                        print ("Error: parsing failed");
-                       print ("%s\n", this.response);
+                       print ("%s\n", (string) message.response_body.data);
                        return null;
                }
 
                var form = search_tag_by_id (doc->children, "form", "search_national_form");
                if (form == null) {
                        print ("Error: does not contain search_national_form");
-                       print ("%s\n", this.response);
+                       print ("%s\n", (string) message.response_body.data);
                        return null;
                }
 
                var select = search_tag_by_name (form->children, "select", "city_from");
                if (select == null) {
                        print ("Error: does not contain city_from");
-                       print ("%s\n", this.response);
+                       print ("%s\n", (string) message.response_body.data);
                        return null;
                }
 
@@ -230,7 +240,7 @@ public class AdacMitfahrclub {
                return result;
        }
 
-       public List<Lift>? get_lift_list (string city_from, string city_to, Date date, int tolerance = 0) {
+       public async List<Lift>? get_lift_list (string city_from, string city_to, Date date, int tolerance = 0) {
                if (city_list == null)
                        get_city_list ();
 
@@ -263,17 +273,17 @@ public class AdacMitfahrclub {
                        tolerance
                );
 
-               var doc = get_html_document (url);
+               var doc = yield get_html_document (url);
                if (doc == null) {
                        print ("Error: parsing failed");
-                       print ("%s\n", this.response);
+                       print ("%s\n", (string) message.response_body.data);
                        return null;
                }
 
                var table = search_tag_by_class (doc->children, "table", "list p_15");
                if (table == null) {
                        print ("Error: does not contain list p_15 table");
-                       print ("%s\n", this.response);
+                       print ("%s\n", (string) message.response_body.data);
                        return null;
                }
 
@@ -322,10 +332,10 @@ public class AdacMitfahrclub {
                                                                        lift.city_to = n3->content;
                                                                        break;
                                                                case 2:
-                                                                       lift.date = n3->content;
+                                                                       parse_date (n3->content, out lift.time);
                                                                        break;
                                                                case 3:
-                                                                       lift.time = n3->content;
+                                                                       parse_time (n3->content.strip (), out lift.time);
                                                                        break;
                                                                case 4:
                                                                        lift.places = n3->content.to_int ();
@@ -361,33 +371,25 @@ public class AdacMitfahrclub {
                return lift;
        }
 
-       public Lift? get_lift_details (string lift_url) {
-               var lift = new Lift ();
-               lift.href = lift_url;
-               if (update_lift_details (lift))
-                       return lift;
-               else
-                       return null;
-       }
-
-       public bool update_lift_details (Lift lift) {
+       public async bool update_lift_details (Lift lift) {
                 string url = BASE_URI + lift.href;
 
-               var doc = get_html_document (url);
+               var doc = yield get_html_document (url);
                if (doc == null) {
                        print ("Error: parsing failed");
-                       print ("%s\n", this.response);
+                       print ("%s\n", (string) message.response_body.data);
                        return false;
                }
 
                var table = search_tag_by_class (doc->children, "table", "lift");
                if (table == null) {
                        print ("Error: does not contain lift table");
-                       print ("%s\n", this.response);
+                       print ("%s\n", (string) message.response_body.data);
                        return false;
                }
 
-               for (var n = table->children; n != null; n = n->next) {
+               Xml.Node* n;
+               for (n = table->children; n != null; n = n->next) {
                        if (n->name == "tr") {
                                var n2 = n->children;
                                if (n2 == null || n2->name != "td" ||
@@ -440,9 +442,7 @@ public class AdacMitfahrclub {
 
                                var text1 = n2->children->content.strip ();
 
-                               if (text == "Datum")
-                                       lift.date = text1;
-                               else if (text == "Freie Pl\xc3\xa4tze")
+                               if (text == "Freie Pl\xc3\xa4tze")
                                        lift.places = text1.to_int ();
                                else if (text == "Name")
                                        lift.name = text1;
@@ -491,9 +491,9 @@ public class AdacMitfahrclub {
                                else if (text1 == "nach")
                                        lift.city_to = text2;
                                else if (text1 == "Datum")
-                                       lift.date = text2;
+                                       parse_date (text2, out lift.time);
                                else if (text1 == "Uhrzeit")
-                                       lift.time = text2;
+                                       parse_time (text2, out lift.time);
                                else if (text1 == "Raucher")
                                        print ("Raucher: %s\n", text2);
                                else if (text1 == "Fahrpreis")
@@ -505,7 +505,7 @@ public class AdacMitfahrclub {
 
                // The paragraph after the table contains the date of last modification
                var p = table->next;
-               for (var n = p->children; n != null; n = n->next) {
+               for (n = p->children; n != null; n = n->next) {
                        if (n->name != "text")
                                continue;
 
@@ -541,4 +541,18 @@ public class AdacMitfahrclub {
        Xml.Node* search_tag_by_class (Xml.Node* node, string tag, string @class) requires (node != null) {
                return search_tag_by_property (node, tag, "class", @class);
        }
+
+       void parse_date (string date, out Time time) {
+               int year;
+               if (date.length == 11)
+                       date = date.offset (3);
+               if (date.length != 8)
+                       return;
+               var res = date.scanf ("%02d.%02d.%02d", out time.day, out time.month, out year);
+               time.year = year + 2000;
+       }
+
+       void parse_time (string time, out Time result) {
+               var res = time.scanf ("%d.%02d Uhr", out result.hour, out result.minute);
+       }
 }