/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
 *
 * Copyright (C) 2010 Red Hat, Inc
 * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com>
 *
 * This program 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 program 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 program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 */

#include <config.h>

#include <polkit/polkit.h>

#include <glib.h>
#include <glib/gi18n.h>

typedef struct {
  /* Will be one of the other two below, or "Unknown" */ 
  const char *hardware_string;

  char *xorg_vesa_hardware;
  char *glx_renderer;
} GraphicsData;

typedef struct
{
  char *regex;
  char *replacement;
} ReplaceStrings;

static char *
prettify_info (const char *info)
{
  char *pretty;
  int   i;
  static const ReplaceStrings rs[] = {
    { "Mesa DRI ", ""},
    { "Intel[(]R[)]", "Intel<sup>\302\256</sup>"},
    { "Core[(]TM[)]", "Core<sup>\342\204\242</sup>"},
    { "Atom[(]TM[)]", "Atom<sup>\342\204\242</sup>"},
    { "Graphics Controller", "Graphics"},
  };

  pretty = g_markup_escape_text (info, -1);

  for (i = 0; i < G_N_ELEMENTS (rs); i++)
    {
      GError *error;
      GRegex *re;
      char   *new;

      error = NULL;

      re = g_regex_new (rs[i].regex, 0, 0, &error);
      if (re == NULL)
        {
          g_warning ("Error building regex: %s", error->message);
          g_error_free (error);
          continue;
        }

      new = g_regex_replace_literal (re,
                                     pretty,
                                     -1,
                                     0,
                                     rs[i].replacement,
                                     0,
                                     &error);

      g_regex_unref (re);

      if (error != NULL)
        {
          g_warning ("Error replacing %s: %s", rs[i].regex, error->message);
          g_error_free (error);
          continue;
        }

      g_free (pretty);
      pretty = new;
    }

  return pretty;
}

static void
graphics_data_free (GraphicsData *gdata)
{
  g_free (gdata->xorg_vesa_hardware);
  g_free (gdata->glx_renderer);
  g_slice_free (GraphicsData, gdata);
}

static char *
get_graphics_data_glx_renderer (void)
{
  GError     *error;
  GRegex     *re;
  GMatchInfo *match_info;
  char       *output;
  char       *result;
  GString    *info;

  info = g_string_new (NULL);

  error = NULL;
  g_spawn_command_line_sync ("glxinfo -l", &output, NULL, NULL, &error);
  if (error != NULL)
    {
      g_warning ("Unable to get graphics info: %s", error->message);
      g_error_free (error);
      return NULL;
    }

  re = g_regex_new ("^OpenGL renderer string: (.+)$", G_REGEX_MULTILINE, 0, &error);
  if (re == NULL)
    {
      g_warning ("Error building regex: %s", error->message);
      g_error_free (error);
      goto out;
    }

  g_regex_match (re, output, 0, &match_info);
  while (g_match_info_matches (match_info))
    {
      char *device;

      device = g_match_info_fetch (match_info, 1);
      g_string_append_printf (info, "%s ", device);
      g_free (device);

      g_match_info_next (match_info, NULL);
    }
  g_match_info_free (match_info);
  g_regex_unref (re);

 out:
  g_free (output);
  result = prettify_info (info->str);
  g_string_free (info, TRUE);

  return result;
}

static char *
get_graphics_data_xorg_vesa_hardware (void)
{
  char *display_num;
  char *log_path;
  char *log_contents;
  gsize log_len;
  GError *error = NULL;
  GRegex *re;
  GMatchInfo *match;
  char *result = NULL;

  {
    const char *display;

    display = g_getenv ("DISPLAY");
    if (!display)
      return NULL;

    re = g_regex_new ("^:([0-9]+)", 0, 0, NULL);
    g_assert (re != NULL);

    g_regex_match (re, display, 0, &match);

    if (!g_match_info_matches (match))
      {
        g_regex_unref (re);
        g_match_info_free (match);
        return NULL;
      }

    display_num = g_match_info_fetch (match, 1);

    g_regex_unref (re);
    re = NULL;
    g_match_info_free (match);
    match = NULL;
  }

  log_path = g_strdup_printf ("/var/log/Xorg.%s.log", display_num);
  g_free (display_num);
  log_contents = NULL;
  g_file_get_contents (log_path, &log_contents, &log_len, &error);
  g_free (log_path);
  if (!log_contents)
    return NULL;

  re = g_regex_new ("VESA VBE OEM Product: (.*)$", G_REGEX_MULTILINE, 0, NULL);
  g_assert (re != NULL);

  g_regex_match (re, log_contents, 0, &match);
  if (g_match_info_matches (match))
    {
      char *tmp;
      char *pretty_tmp;
      tmp = g_match_info_fetch (match, 1);
      pretty_tmp = prettify_info (tmp);
      g_free (tmp);
      /* Translators: VESA is an techncial acronym, don't translate it. */
      result = g_strdup_printf (_("VESA: %s"), pretty_tmp); 
      g_free (pretty_tmp);
    }
  g_match_info_free (match);
  g_regex_unref (re);

  return result;
}

int main()
{
  GraphicsData *result;

  result = g_slice_new0 (GraphicsData);

  result->glx_renderer = get_graphics_data_glx_renderer ();
  result->xorg_vesa_hardware = get_graphics_data_xorg_vesa_hardware ();

  if (result->xorg_vesa_hardware != NULL)
    result->hardware_string = result->xorg_vesa_hardware;
  else if (result->glx_renderer != NULL)
    result->hardware_string = result->glx_renderer;
  else
    result->hardware_string = _("Unknown");

  g_debug("original code path:\n");
  g_debug("parse Xorg string: %s\n",result->xorg_vesa_hardware);
  g_debug("glxinfo string: %s\n",result->glx_renderer);
  g_debug("Display result: %s\n",result->hardware_string);

  if (result->glx_renderer != NULL)
    result->hardware_string = result->glx_renderer;
  else if (result->xorg_vesa_hardware != NULL)
    result->hardware_string = result->xorg_vesa_hardware;
  else
    result->hardware_string = _("Unknown");
    
  g_debug("proposed code path:\n");    
  g_debug("glxinfo string: %s\n",result->glx_renderer);
  g_debug("parse Xorg string: %s\n",result->xorg_vesa_hardware);
  g_debug("Display result: %s\n",result->hardware_string);

  return 0;                             
}
