/*
    ragmaan/idle_task.c            (C) 2003 Raymond (zandbergen@home.nl)

    "ragmaan" is an anagram generator

    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 <glib.h>
#include <gtk/gtk.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ragmaan.h"
#include "state_stack.h"
#include "idle_task.h"
#include "search.h"

static const gint idle_status_chunk_size = 10;
static gboolean has_further_subwords (gchar * s);

/* The idle task updates the status of all results 
 * (in chunks) when there is nothing else to do. */

gboolean
idle_task (gpointer data)
{
  gint i;
  gboolean done;
  GtkTreeModel *m;
  gboolean status_iterator_valid;

  gdk_threads_enter ();
  set_busy_cursor (FALSE);
  m =
    gtk_tree_view_get_model (GTK_TREE_VIEW (global_widgets.result_tree_view));

  if (state_stack_tos->idle_state.initialised)
    {
      /* task never leaves an invalid iterator */
      status_iterator_valid = 1; 
    }
  else
    {
      /* start from the top */
      status_iterator_valid =
	gtk_tree_model_get_iter_first (m, &state_stack_tos->idle_state.iter);
      state_stack_tos->idle_state.initialised = TRUE;
    }
  i = 0;
  /* handle chunk */
  while (status_iterator_valid && i++ < idle_status_chunk_size)
    {
      gint status;
      gchar *rest;
      gint pic;

      gtk_tree_model_get (m, &state_stack_tos->idle_state.iter,
			  COLUMN_STATUS, &status, -1);

      if (status == SUBWORD_STATE_DESCEND_UNKNOWN)
	{
	  gtk_tree_model_get (m, &state_stack_tos->idle_state.iter,
			      COLUMN_REST, &rest, -1);
	  pic =
	    has_further_subwords (rest) ? SUBWORD_STATE_DESCEND_OK :
	    SUBWORD_STATE_DEAD;

	  gtk_list_store_set (GTK_LIST_STORE (m),
			      &state_stack_tos->idle_state.iter,
			      COLUMN_STATUS, pic, -1);
	  g_free (rest);
	}
      i++;
      status_iterator_valid = gtk_tree_model_iter_next (m, &state_stack_tos->idle_state.iter);
    }
  /* done, but may need to reschedule myself for next chunk */
  done = !status_iterator_valid;

  state_stack_tos->idle_state.done = done;
  state_stack_tos->idle_state.running = !done;
  gdk_threads_leave ();
  return !done;
}

/* task control */

void
idle_task_stop (void)
{
  if (state_stack_tos->idle_state.running)
    {
      gtk_idle_remove (state_stack_tos->idle_state.tag);
      state_stack_tos->idle_state.running = FALSE;
    }
}

void
idle_task_start (void)
{
  if (!state_stack_tos->idle_state.done)
    {
      state_stack_tos->idle_state.running = TRUE;
      state_stack_tos->idle_state.tag = gtk_idle_add (idle_task, NULL);
    }
  else
    set_busy_cursor (FALSE);
}

void
idle_task_init (void)
{
  state_stack_tos->idle_state.running = FALSE;
  state_stack_tos->idle_state.initialised = FALSE;
  state_stack_tos->idle_state.done = FALSE;
}

/* this is what the idle task actually does */
static gboolean
has_further_subwords (gchar * s)
{
  SEARCH_STATE_T ss;
  init_search_reverse (&hash_table, &ss, s, rm_str_real_len (s), 1, 0);
  return !!find_word_wl_reverse (&ss, &hash_table);
}
