/*
 * Copyright (C) 2008 Canonical Ltd
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as 
 * published by the Free Software Foundation.
 *
 * 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, see <http://www.gnu.org/licenses/>.
 *
 * Authored by Neil Jagdish Patel <neil.patel@canonical.com>
 *
 */

#include "launcher-wm.h"

#include "launcher-menu.h"

G_DEFINE_TYPE (LauncherWm, launcher_wm, G_TYPE_OBJECT);

#define LAUNCHER_WM_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
  LAUNCHER_TYPE_WM, \
  LauncherWmPrivate))

struct _LauncherWmPrivate
{
  WnckScreen *screen;

  GHashTable *table;
};

enum
{
  SHOW_DECS,
  HIDE_DECS,

  LAST_SIGNAL
};
static guint _wm_signals[LAST_SIGNAL] = { 0 };

static void
on_active_window_changed (WnckScreen *screen, 
                          WnckWindow *prev_window,
                          LauncherWm *wm)
{
  WnckWindow *window;
  WnckWindowType type;

  window = wnck_screen_get_active_window (screen);

  if (!WNCK_IS_WINDOW (window))
  {
    g_signal_emit (wm, _wm_signals[HIDE_DECS], 0);
    /*g_debug ("ACTIVE: Desktop\n");*/
    return;
  }
  
  type = wnck_window_get_window_type (window);
  switch (type)
  {
    case WNCK_WINDOW_NORMAL:
       break;
    case WNCK_WINDOW_DESKTOP:
    case WNCK_WINDOW_DOCK:
      g_signal_emit (wm, _wm_signals[HIDE_DECS], 0);
      wnck_screen_toggle_showing_desktop (screen, TRUE);
      return;
    default:
      return;
   }

  g_signal_emit (wm, _wm_signals[SHOW_DECS], 0, window);
}

static void
on_window_opened (WnckScreen *screen, WnckWindow *window, LauncherWm *wm)
{
  LauncherWmPrivate *priv;
  WnckWindowType type;
  GList *list, *l;
  gint pid;

  g_return_if_fail (LAUNCHER_IS_WM (wm));
  priv = wm->priv;

  type = wnck_window_get_window_type (window);
  switch (type)
  {
    case WNCK_WINDOW_NORMAL:

      break;
    default:
      return;
  }

  pid = wnck_window_get_pid (window);
  
  list = launcher_menu_get_applications (launcher_menu_get_default ());
  for (l = list; l; l = l->next)
  {
    if (pid == launcher_menu_application_get_pid (l->data))
    {
      launcher_menu_application_set_window (l->data, window);
      wnck_window_activate (window, GDK_CURRENT_TIME);

      g_hash_table_insert (priv->table, (gpointer)&pid, l->data);
      return;
    }
  }
}

static void
on_window_closed (WnckScreen *screen, WnckWindow *window, LauncherWm *wm)
{
  LauncherWmPrivate *priv;
  LauncherMenuApplication *app = NULL;
  WnckWindowType type;
  gint pid;

  g_return_if_fail (LAUNCHER_IS_WM (wm));
  priv = wm->priv;

  type = wnck_window_get_window_type (window);
  switch (type)
  {
    case WNCK_WINDOW_NORMAL:
      break;
    default:
      return;
   }

  pid = wnck_window_get_pid (window);
  
  app = g_hash_table_lookup (priv->table, (gconstpointer)&pid);

  if (app)
  {
    launcher_menu_application_set_pid (app, -1);
    launcher_menu_application_set_window (app, NULL);
    g_hash_table_remove (priv->table, (gconstpointer)&pid);
  }
}

/*
 * Destroy the hashtable when the menu changes, as all its keys are invalid
 */
static void
on_menu_changed (LauncherMenu *menu, LauncherWm *wm)
{
  g_return_if_fail (LAUNCHER_IS_WM (wm));
} 

/* GObject stuff */
static void
launcher_wm_class_init (LauncherWmClass *klass)
{
  GObjectClass        *obj_class = G_OBJECT_CLASS (klass);

	_wm_signals[SHOW_DECS] =
		g_signal_new ("show-windec",
			      G_OBJECT_CLASS_TYPE (obj_class),
			      G_SIGNAL_RUN_LAST,
			      G_STRUCT_OFFSET (LauncherWmClass, show_windec),
			      NULL, NULL,
			      g_cclosure_marshal_VOID__OBJECT, 
			      G_TYPE_NONE,
			      1, WNCK_TYPE_WINDOW);

  _wm_signals[HIDE_DECS] =
		g_signal_new ("hide-windec",
			      G_OBJECT_CLASS_TYPE (obj_class),
			      G_SIGNAL_RUN_LAST,
			      G_STRUCT_OFFSET (LauncherWmClass, hide_windec),
			      NULL, NULL,
			      g_cclosure_marshal_VOID__VOID, 
			      G_TYPE_NONE, 0);  

  g_type_class_add_private (obj_class, sizeof (LauncherWmPrivate));
}

static void
launcher_wm_init (LauncherWm *wm)
{
  LauncherWmPrivate *priv;
	
  priv = wm->priv = LAUNCHER_WM_GET_PRIVATE (wm);

  priv->screen = wnck_screen_get_default ();

  priv->table = g_hash_table_new (g_int_hash, g_direct_equal);

  g_signal_connect (priv->screen, "active-window-changed",
                    G_CALLBACK (on_active_window_changed), (gpointer)wm);
  g_signal_connect (priv->screen, "window-opened",
                    G_CALLBACK (on_window_opened), (gpointer)wm);
  g_signal_connect (priv->screen, "window-closed",
                    G_CALLBACK (on_window_closed), (gpointer)wm);

  g_signal_connect (launcher_menu_get_default (), "menu-changed",
                    G_CALLBACK (on_menu_changed), wm);
}

LauncherWm *
launcher_wm_get_default (void)

{
  static LauncherWm *wm = NULL;

  if (!wm)
    wm = g_object_new (LAUNCHER_TYPE_WM, 
                       NULL);

  return wm;
}
