/* app.c
 * Copyright (C) 2002-2004 Pascal Eberhard <pascal.ebo@netcourrier.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 "common.h"
#include <string.h>

// used by app_new_noname & app_list_find_noname
#define APP_NONAME_CMDLINE ""
#define APP_NONAME_PATH ""
#define APP_NONAME_ICON ""

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
app_t * app_new(gchar *cmdline, gchar *path, gchar *icon, gint x, gint y)
{
  app_t *app;

  g_assert(cmdline != NULL && path != NULL && icon != NULL);

  app = (app_t *) malloc(sizeof(app_t));
  g_assert(app != NULL);

  app->cmdline = cmdline;
  app->path = path;
  app->icon = icon;
  app->x    = x;
  app->y    = y;
  return app;
}

// ----------------------------------------------------------------------------
app_t * app_new_noname(gint x, gint y)
{
  app_t *app;
  app = app_new(g_strdup(APP_NONAME_CMDLINE), g_strdup(APP_NONAME_PATH),
                g_strdup(APP_NONAME_ICON), x, y);
  return app;
}
// ----------------------------------------------------------------------------
void app_free(app_t **app)
{
  g_assert(app != NULL && *app != NULL);

  TRACE("app:%p", *app);
  if ((*app)->cmdline)
    g_free((*app)->cmdline);
  if ((*app)->path)
    g_free((*app)->path);
  if ((*app)->icon)
    g_free((*app)->icon);
  free((*app));
  (*app) = NULL;
}
// ----------------------------------------------------------------------------
app_t * app_clone(app_t *app)
{
  app_t *newapp;

  g_assert(app != NULL);

  newapp = (app_t *) malloc(sizeof(app_t));
  g_assert(newapp != NULL);

  newapp->cmdline = g_strdup(app->cmdline);
  newapp->path = g_strdup(app->path);
  newapp->icon = g_strdup(app->icon);
  newapp->x = app->x;
  newapp->y = app->y;
  return newapp;
}
// ----------------------------------------------------------------------------
gboolean app_exec(app_t *app, gboolean exit_at_app_launch)
{
  gboolean spawned;

  g_assert(app != NULL);
  spawned = sys_spawn(app->cmdline, app->path);
  if (!spawned)
  {
    WARN("sys_spawn, cmdline:%s, path:%s", app->cmdline, app->path);
    return FALSE;
  }
  if (exit_at_app_launch)
    gtk_main_quit();
  return TRUE;
}
// ----------------------------------------------------------------------------
void app_dump(app_t *app)
{
  g_assert(app != NULL);
  TRACE("icon:%s, cmdline:%s, x:%d, y:%d",
          app->icon, app->cmdline, app->x, app->y);
}
// ----------------------------------------------------------------------------
void app_dumpln(app_t *app)
{
  g_assert(app != NULL);
  TRACE("[app|icon:%s, cmdline:%s, x:%d, y:%d]",
          app->icon, app->cmdline, app->x, app->y);
}
// ----------------------------------------------------------------------------
gboolean app_is_executable(app_t *app)
{
  int      argcp;
  char   **argvp;
  gboolean res, is_exec;
  g_assert(app != NULL && app->cmdline != NULL);
  res = g_shell_parse_argv(app->cmdline, &argcp, &argvp, NULL/*GError*/);
  if (res == TRUE)
  {
    if (g_path_is_absolute(argvp[0]))
      is_exec = g_file_test(argvp[0], G_FILE_TEST_IS_EXECUTABLE);
    else
    {
      char *absolute_path;
      absolute_path = g_find_program_in_path(argvp[0]);
      is_exec = g_file_test(absolute_path, G_FILE_TEST_IS_EXECUTABLE);
      g_free(absolute_path);
    }
    g_strfreev(argvp);
  }
  else
    return FALSE;
  return is_exec;
}
// ----------------------------------------------------------------------------
gboolean app_path_is_valid(app_t *app)
{
  gboolean is_valid;
  g_assert(app != NULL && app->path != NULL);
  if (strcmp("", app->path) == 0)
    return TRUE;
  is_valid = g_file_test(app->path, G_FILE_TEST_IS_DIR);
  return is_valid;
}
// ----------------------------------------------------------------------------
gboolean app_icon_is_valid(app_t *app)
{
  gboolean is_valid;
  g_assert(app != NULL && app->icon != NULL);
  is_valid = g_file_test(app->icon, G_FILE_TEST_EXISTS);
  return is_valid;
}
// ----------------------------------------------------------------------------
const char *app_get_cmdline(app_t *app)
{
  g_assert(app != NULL);
  return app->cmdline;
}
// ----------------------------------------------------------------------------
void app_set_cmdline(app_t *app, const char *value)
{
  g_assert(app != NULL && value != NULL);
  TRACE("%s", "");
  if (app->cmdline)
    g_free(app->cmdline);
  app->cmdline = g_strdup(value);
  g_assert(app->cmdline != NULL);
}
// ----------------------------------------------------------------------------
const char *app_get_path(app_t *app)
{
  g_assert(app != NULL);
  return app->path;
}
// ----------------------------------------------------------------------------
void app_set_path(app_t *app, const char *value)
{
  g_assert(app != NULL && value != NULL);
  TRACE("%s", "");
  if (app->path)
    g_free(app->path);
  app->path = g_strdup(value);
  g_assert(app->path != NULL);
}
// ----------------------------------------------------------------------------
const char *app_get_icon(app_t *app)
{
  g_assert(app != NULL);
  return app->icon;
}
// ----------------------------------------------------------------------------
void app_set_icon(app_t *app, const char *value)
{
  g_assert(app != NULL && value != NULL);
  TRACE("%s", "");
  if (app->icon)
    g_free(app->icon);
  app->icon = g_strdup(value);
  g_assert(app->icon != NULL);
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
app_list_t* app_list_new(void)
{
  app_list_t *apps;
  apps = (app_list_t *) malloc(sizeof(app_list_t));
  g_assert(apps != NULL);
  apps->apps = NULL;
  apps->hamster = NULL;
  return apps;
}

// ----------------------------------------------------------------------------
void app_list_free(app_list_t **apps)
{
  app_t *app;

  g_assert(apps != NULL && *apps != NULL);

  TRACE("apps:%p", apps);
  while ((*apps)->apps)
  {
    (*apps)->hamster = g_list_first((*apps)->apps);
    if ((*apps)->hamster)
      app = (*apps)->hamster->data;
    else
    {
      WARN("list:%p, (*apps)->hamster:%p", 
                (*apps)->apps, (*apps)->hamster);
    }
    (*apps)->apps = g_list_remove((*apps)->apps, app);
    app_free(&app);
  }
}

// ----------------------------------------------------------------------------
int app_list_add(app_list_t *apps, app_t *app)
{
  gboolean empty;
  gint try_new_pos;

  g_assert(apps != NULL && app != NULL);

  try_new_pos = 0;
  empty = app_list_xy_empty(apps, app->x, app->y);
  while (!empty)
  {
    TRACE("dupplicate icon at x:%d, y:%d, "
            "change second icon position", app->x, app->y);
    app->x++;
    empty = app_list_xy_empty(apps, app->x, app->y);
    if (try_new_pos > 20)
    {
      WARN("whaou, try:%d > 20, it's big! icon:%s, cmdline:%s, x:%d, y:%d",
                try_new_pos, app->icon, app->cmdline, app->x, app->y);
      return -1;
     }
    try_new_pos++;
  }
  apps->apps = g_list_append(apps->apps, app);
  return 0;
}
// ----------------------------------------------------------------------------
int app_list_remove(app_list_t *apps, app_t *app)
{
  GList *apps_new;
  gint  len;

  g_assert(apps != NULL && app != NULL);

  TRACE("apps:%p, app:%p", apps, app);
  len = app_list_length(apps);
  apps_new = g_list_remove(apps->apps, app);
  if ((!apps_new) && (len !=1))
  {
    WARN("app:%p introuvable dans apps:%p", app, apps);
    return -1;
  }
  apps->apps = apps_new;
  app_free(&app);
  return 0;
}
// ----------------------------------------------------------------------------
app_t *app_list_first(app_list_t *apps)
{
  g_assert(apps != NULL);

  if (!apps->apps)
    return NULL;
  apps->hamster = g_list_first(apps->apps);
  return apps->hamster->data;
}
// ----------------------------------------------------------------------------
app_t *app_list_next(app_list_t *apps)
{
  g_assert(apps != NULL);
  g_assert(apps->apps != NULL && apps->hamster != NULL);

  apps->hamster = g_list_next(apps->hamster);
  if (!apps->hamster)
    return NULL;
  return apps->hamster->data;
}
// ----------------------------------------------------------------------------
app_t *app_list_nth(app_list_t *apps, int nth)
{
  g_assert(apps != NULL && apps->apps != NULL);

  apps->hamster = g_list_nth(apps->apps, nth);
  if (!apps->hamster)
    return NULL;
  return apps->hamster->data;
}

// ----------------------------------------------------------------------------
int app_list_length(app_list_t *apps)
{
  g_assert(apps != NULL && apps->apps != NULL);

  return g_list_length(apps->apps);
}
// ----------------------------------------------------------------------------
void app_list_dump(app_list_t *apps)
{
  app_t *app;
  
  g_assert(apps != NULL);

  app = app_list_first(apps);
  while(app)
  {
    g_print("app[");
    app_dump(app);
    g_print("]\n");
    app = app_list_next(apps);
  }
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
gint app_list_delta_x(app_list_t *apps)
{
  app_t *app;
  gint   x_min;
  gint   x_max;
  
  g_assert(apps != NULL && apps->apps != NULL);

  app = app_list_first(apps);
  x_min = app->x;
  x_max = app->x;
  app = app_list_next(apps);
  while(app)
  {
    if (x_max < app->x)
      x_max = app->x;
    if (x_min > app->x)
      x_min = app->x;
    app = app_list_next(apps);
  }
  return (x_max - x_min);
}
// ----------------------------------------------------------------------------
gint app_list_delta_y(app_list_t *apps)
{
  app_t *app;
  gint   y_min;
  gint   y_max;
  
  g_assert(apps != NULL && apps->apps != NULL);

  app = app_list_first(apps);
  y_min = app->y;
  y_max = app->y;
  app = app_list_next(apps);
  while(app)
  {
    if (y_max < app->y)
      y_max = app->y;
    if (y_min > app->y)
      y_min = app->y;
    app = app_list_next(apps);
  }
  return (y_max - y_min);
}
// ----------------------------------------------------------------------------
int app_list_min_x(app_list_t *apps)
{
  app_t *app;
  gint   x_min;
  
  g_assert(apps != NULL && apps->apps != NULL);

  app = app_list_first(apps);
  x_min = app->x;
  app = app_list_next(apps);
  while(app)
  {
    if (x_min > app->x)
      x_min = app->x;
    app = app_list_next(apps);
  }
  return x_min;
}
// ----------------------------------------------------------------------------
int app_list_min_y(app_list_t *apps)
{
  app_t *app;
  gint   y_min;
  
  g_assert(apps != NULL && apps->apps != NULL);

  app = app_list_first(apps);
  y_min = app->y;
  app = app_list_next(apps);
  while(app)
  {
    if (y_min > app->y)
      y_min = app->y;
    app = app_list_next(apps);
  }
  return y_min;
}
// ----------------------------------------------------------------------------
int app_list_max_x(app_list_t *apps)
{
  app_t *app;
  gint   x_max;
  
  g_assert(apps != NULL && apps->apps != NULL);

  app = app_list_first(apps);
  x_max = app->x;
  app = app_list_next(apps);
  while(app)
  {
    if (x_max < app->x)
      x_max = app->x;
    app = app_list_next(apps);
  }
  return x_max;
}
// ----------------------------------------------------------------------------
int app_list_max_y(app_list_t *apps)
{
  app_t *app;
  gint   y_max;
  
  g_assert(apps != NULL && apps->apps != NULL);

  app = app_list_first(apps);
  y_max = app->y;
  app = app_list_next(apps);
  while(app)
  {
    if (y_max < app->y)
      y_max = app->y;
    app = app_list_next(apps);
  }
  return y_max;
}
// ----------------------------------------------------------------------------
app_t * app_list_at_xy(app_list_t *apps, gint x, gint y)
{
  app_t *app;
  GList *hamster;
  g_assert(apps != NULL);
  hamster = g_list_first(apps->apps);
  while(hamster != NULL)
  {
    app = hamster->data;
    if ((app->x == x) && (app->y == y))
    {
      return app;
    }
    hamster = g_list_next(hamster);
  }
  return NULL;
}
// ----------------------------------------------------------------------------
gboolean app_list_xy_empty(app_list_t *apps, gint x, gint y)
{
  app_t *app;
  
  g_assert(apps != NULL);

  if (!apps->apps)
    return TRUE;

  app = app_list_at_xy(apps, x, y);
  if (app)
    return FALSE;
  return TRUE;
}
// ----------------------------------------------------------------------------
app_t * app_list_find_noname(app_list_t *apps)
{
  app_t *app;
  GList *hamster;
  g_assert(apps != NULL);
  hamster = g_list_first(apps->apps);
  while(hamster != NULL)
  {
    app = hamster->data;
    if (!strcmp(app->cmdline, APP_NONAME_CMDLINE) &&
        !strcmp(app->path, APP_NONAME_PATH) &&
        !strcmp(app->icon, APP_NONAME_ICON))
      return app;
    hamster = g_list_next(hamster);
  }
  return NULL;
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
