using GLib;
using GUPnP;

/*
 * TODO:
 *  * call setlocale
 *  * SIGTERM handler?
 */

public class Test.IntrospectionTest : Object {
    private static bool async = false;

    private const OptionEntry[] entries = {
        { "async",
          'a',
          0,
          OptionArg.NONE,
          ref async,
          "Create introspection object asynchronously",
          null },
        { null }
    };

    public static int main (string[] args) {
        IntrospectionTest test = new IntrospectionTest();
        return test.run (args);
    }

    private int run (string[] args) {
        Context ctxt;

        /* handle command line options */
        try {
            OptionContext options = new OptionContext
                ("- GUPnP introspection test program (Vala version)");
            options.add_main_entries (entries, null);
            options.parse (ref args);
        } catch (OptionError err) {
            error ("Error while parsing commandline arguments: %s",
                    err.message);
        }

        try {
            ctxt = new Context (null, null, 0);
        } catch (Error err) {
            critical (err.message);
            return 1;
        }

        /* We're interested in everything */
        ControlPoint cp = new ControlPoint (ctxt, "ssdp:all");
        cp.service_proxy_available.connect (on_service_proxy_available);
        cp.active = true;

        MainLoop loop = new MainLoop (null, false);
        loop.run();

        return 0;
    }

    private void on_service_proxy_available (ControlPoint cp,
                                             ServiceProxy proxy) {
        if (async) {
            /* this will result in C compiler warning because
             * there's no way to make the callback signature have
             * "const GError" argument in Vala */
            proxy.get_introspection_async (on_get_introspection);
        } else {
            try {
                print ("service: %s\nlocation: %s\n",
                        proxy.udn, proxy.location);

                ServiceIntrospection introspection =
                    proxy.get_introspection ();
                print_state_variables (introspection);
                print_actions (introspection);
            } catch (Error err) {
                warning ("Failed to create introspection for '%s': %s",
                        proxy.udn, err.message);
            }
        }
    }

    private void on_get_introspection (ServiceInfo          info,
                                       ServiceIntrospection introspection,
                                       Error                err) {
        print ("service: %s\nlocation: %s\n",
                info.udn, info.location);

        if (err != null) {
            warning ("Failed to create introspection for '%s': %s",
                    info.udn, err.message);
        } else {
            print_state_variables (introspection);
            print_actions (introspection);
        }
    }

    private void print_state_variables (ServiceIntrospection introspection) {
        /* this will result in C compiler warning since the return value
           is actually "_const_ GList*", and Vala can't express that. */
        weak List<ServiceStateVariableInfo> variables =
            introspection.list_state_variables ();

        if (variables != null) {
            print ("State variables:\n");
        }

        foreach (weak ServiceStateVariableInfo var_info in variables) {
            print ("\tstate variable: %s\n" +
                    "\t\ttype: %s\n" +
                    "\t\tsend events: %s\n",
                    var_info.name,
                    var_info.type.name (),
                    var_info.send_events? "yes": "no");

            Value def_val = Value (typeof (string));
            if (var_info.default_value.transform (ref def_val)) {
                weak string str = def_val.get_string ();
                if (str != null)
                    print ("\t\tdefault value: %s\n", str);
            }
            def_val.unset ();

            if (var_info.is_numeric) {
                Value min = Value (typeof (string));
                Value max = Value (typeof (string));
                Value step = Value (typeof (string));

                var_info.minimum.transform (ref min);
                var_info.maximum.transform (ref max);
                var_info.step.transform (ref step);

                print ("\t\tminimum: %s\n" +
                        "\t\tmaximum: %s\n" +
                        "\t\tstep: %s\n",
                        min.get_string(),
                        max.get_string(),
                        step.get_string());

                min.unset ();
                max.unset ();
                step.unset ();
            }

            if (var_info.allowed_values != null) {
                print ("\t\tallowed values: ");
                weak List<string> l = var_info.allowed_values;
                foreach (string val in l) {
                    print ("\"%s\" ", val);
                }
                print ("\n");
            }
        }
    }

    private void print_actions (ServiceIntrospection introspection) {
        /* this will result in C compiler warning since the return value
           is actually "_const_ GList*", and Vala can't express that. */
        weak List<ServiceActionInfo> actions = introspection.list_actions ();

        if (actions != null) {
            print ("Actions:\n");
        }

        foreach (weak ServiceActionInfo action_info in actions) {
            print ("\taction: %s\n", action_info.name);

            weak List<ServiceActionArgInfo> l = action_info.arguments;
            foreach (weak ServiceActionArgInfo arg_info in l) {
                print ("\t\targument: %s\n" +
                        "\t\t\tdirection: %s\n" +
                        "\t\t\trelated state variable: %s\n\n",
                        arg_info.name,
                        (arg_info.direction == ServiceActionArgDirection.IN) ?
                        "in":"out",
                        arg_info.related_state_variable);
            }
        }
    }

}
