/*
 * MATE CPUFreq Applet
 * Copyright (C) 2004 Carlos Garcia Campos <carlosgc@gnome.org>
 *
 *  This library 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 2 of the License, or (at your option) any later version.
 *
 *  This library 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 library; if not, write to the Free
 *  Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * Authors : Carlos Garc�a Campos <carlosgc@gnome.org>
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <glib.h>
#include <glib-object.h>

#ifdef HAVE_POLKIT
#include "cpufreq-selector-service.h"
#else
#include <unistd.h>
#endif
#include "cpufreq-selector-factory.h"

static gint    cpu = 0;
static gchar  *governor = NULL;
static gulong  frequency = 0;

static const GOptionEntry options[] = {
    { "cpu",       'c', 0, G_OPTION_ARG_INT,    &cpu,       "CPU Number",       NULL },
    { "governor",  'g', 0, G_OPTION_ARG_STRING, &governor,  "Governor",         NULL },
    { "frequency", 'f', 0, G_OPTION_ARG_INT,    &frequency, "Frequency in KHz", NULL },
    { NULL }
};

#ifdef HAVE_POLKIT
static void
do_exit (GMainLoop *loop,
         GObject   *object)
{
    if (g_main_loop_is_running (loop))
        g_main_loop_quit (loop);
}

static void
cpufreq_selector_set_values_dbus (void)
{
    DBusGConnection *connection;
    DBusGProxy      *proxy;
    gboolean         res;
    GError          *error = NULL;

    connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
    if (!connection) {
        g_printerr ("Couldn't connect to system bus: %s\n",
                    error->message);
        g_error_free (error);

        return;
    }

    proxy = dbus_g_proxy_new_for_name (connection,
                                       "org.mate.CPUFreqSelector",
                                       "/org/mate/cpufreq_selector/selector",
                                       "org.mate.CPUFreqSelector");
    if (!proxy) {
        g_printerr ("Could not construct proxy object\n");

        return;
    }

    if (governor) {
        res = dbus_g_proxy_call (proxy, "SetGovernor", &error,
                                 G_TYPE_UINT, cpu,
                                 G_TYPE_STRING, governor,
                                 G_TYPE_INVALID,
                                 G_TYPE_INVALID);
        if (!res) {
            if (error) {
                g_printerr ("Error calling SetGovernor: %s\n", error->message);
                g_error_free (error);
            } else {
                g_printerr ("Error calling SetGovernor\n");
            }

            g_object_unref (proxy);

            return;
        }
    }

    if (frequency != 0) {
        res = dbus_g_proxy_call (proxy, "SetFrequency", &error,
                                 G_TYPE_UINT, cpu,
                                 G_TYPE_UINT, frequency,
                                 G_TYPE_INVALID,
                                 G_TYPE_INVALID);
        if (!res) {
            if (error) {
                g_printerr ("Error calling SetFrequency: %s\n", error->message);
                g_error_free (error);
            } else {
                g_printerr ("Error calling SetFrequency\n");
            }

            g_object_unref (proxy);

            return;
        }
    }

    g_object_unref (proxy);
}
#endif /* HAVE_POLKIT */

static void
cpufreq_selector_set_values (void)
{
    CPUFreqSelector *selector;
    GError          *error = NULL;

    selector = cpufreq_selector_factory_create_selector (cpu);
    if (!selector) {
        g_printerr ("No cpufreq support\n");

        return;
    }

    if (governor) {
        cpufreq_selector_set_governor (selector, governor, &error);

        if (error) {
            g_printerr ("%s\n", error->message);
            g_error_free (error);
            error = NULL;
        }
    }

    if (frequency != 0) {
        cpufreq_selector_set_frequency (selector, frequency, &error);

        if (error) {
            g_printerr ("%s\n", error->message);
            g_error_free (error);
            error = NULL;
        }
    }

    g_object_unref (selector);
}

gint
main (gint argc, gchar **argv)
{
#ifdef HAVE_POLKIT
    GMainLoop      *loop;
#endif
    GOptionContext *context;
    GError         *error = NULL;

#ifndef HAVE_POLKIT
    if (geteuid () != 0) {
        g_printerr ("You must be root\n");

        return 1;
    }

    if (argc < 2) {
        g_printerr ("Missing operand after `cpufreq-selector'\n");
        g_printerr ("Try `cpufreq-selector --help' for more information.\n");

        return 1;
    }
#endif

    context = g_option_context_new ("- CPUFreq Selector");
    g_option_context_add_main_entries (context, options, NULL);

    if (!g_option_context_parse (context, &argc, &argv, &error)) {
        if (error) {
            g_printerr ("%s\n", error->message);
            g_error_free (error);
        }

        g_option_context_free (context);

        return 1;
    }

    g_option_context_free (context);

#ifdef HAVE_POLKIT
    if (!cpufreq_selector_service_register (SELECTOR_SERVICE, &error)) {
        if (governor || frequency != 0) {
            cpufreq_selector_set_values_dbus ();

            return 0;
        }

        g_printerr ("%s\n", error->message);
        g_error_free (error);

        return 1;
    }

    cpufreq_selector_set_values ();

    loop = g_main_loop_new (NULL, FALSE);
    g_object_weak_ref (G_OBJECT (SELECTOR_SERVICE),
                       (GWeakNotify) do_exit,
                       loop);

    g_main_loop_run (loop);

    g_main_loop_unref (loop);
#else /* !HAVE_POLKIT */
    cpufreq_selector_set_values ();
#endif /* HAVE_POLKIT */

        return 0;
}