/* AisleRiot - cscmi.h
 * Copyright (C) 1998, 2003 Jonathan Blandford <jrb@mit.edu>
 *
 * This game 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, 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
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <string.h>

#include "cscmi.h"
#include "sol.h"
#include "slot.h"
#include "menu.h"

lambda_data* game_data = NULL;

/* Scheme to C functions... */

void add_slot(SCM slot_data) 
{
  hslot_type hslot = malloc(sizeof(slot_type));

  hslot->id = SCM_INUM(SCM_CAR(slot_data));
  hslot->cards = new_deck(SCM_CADR(slot_data));
  hslot->x = SCM_INUM(SCM_CAR(SCM_CADR(SCM_CADDR(slot_data))));
  hslot->y = SCM_INUM(SCM_CADR(SCM_CADR(SCM_CADDR(slot_data))));
  
  hslot->dx = hslot->dy = 0;
  hslot->expansion_depth = 0;

  if (!strcmp("expanded", SCM_CHARS(SCM_CAR(SCM_CADDR(slot_data))))) {
    hslot->dy = y_expanded_offset;
  }
  else if (!strcmp("expanded-right", 
		   SCM_CHARS(SCM_CAR(SCM_CADDR(slot_data))))) {
    hslot->dx = x_expanded_offset;
  }
  else if (!strcmp("partially-expanded", 
		   SCM_CHARS(SCM_CAR(SCM_CADDR(slot_data))))) {
    hslot->dy = y_expanded_offset;
    hslot->expansion_depth = SCM_INUM(SCM_CADDR(SCM_CADDR(slot_data)));
  }
  else if (!strcmp("partially-expanded-right", 
		   SCM_CHARS(SCM_CAR(SCM_CADDR(slot_data))))) {
    hslot->dx = x_expanded_offset;
    hslot->expansion_depth = SCM_INUM(SCM_CADDR(SCM_CADDR(slot_data)));
  }

  hslot->length = hslot->exposed = 0;
  update_slot_length(hslot);

  if (slot_list)
    g_list_append(slot_list, hslot);
  else {
    slot_list = g_list_alloc();
    slot_list->data = hslot;
  }
}

hcard_type new_card(SCM card_data) 
{
  hcard_type temp_card = malloc(sizeof(card_type));

  temp_card->value = SCM_INUM(SCM_CAR(card_data));
  temp_card->suit = SCM_INUM(SCM_CADR(card_data));
  temp_card->direction = !(SCM_NFALSEP(SCM_CADDR(card_data)));

  return temp_card;
}

GList* new_deck(SCM deck_data) 
{
  SCM list_el;
  GList* temp_deck = NULL;

  if (SCM_NFALSEP(deck_data)) {
    for (list_el = deck_data; list_el != SCM_EOL; list_el = SCM_CDR(list_el))
      add_card(&temp_deck,new_card(SCM_CAR(list_el)));
  }
  
  return g_list_reverse(temp_deck);
}

/* C to Scheme functions... */
SCM make_card(hcard_type card) 
{
  return gh_cons(gh_long2scm(card->value),
		 gh_cons(gh_long2scm(card->suit),
			 gh_cons(gh_bool2scm(!card->direction), SCM_EOL)));
}

/* Scheme functions */
static SCM scm_gettext(SCM message)
{
  static char * input = NULL;
  char * output;
  int len;

  /* This is needed because we can't free the string before returning
   * if it isn't translated. This way we have a permanent one-string
   * memory leak and nothing more. */
  if (!input)
    free (input);
  
  input = gh_scm2newstr (message, &len);
  output = gettext (input);
  return gh_str02scm (output);
}

static SCM scm_undo_set_sensitive (SCM in_state)
{
  gboolean state;

  state = gh_scm2bool (in_state) ? TRUE : FALSE;
  undo_set_sensitive (state);

  return SCM_EOL;
}

static SCM scm_redo_set_sensitive (SCM in_state)
{
  gboolean state;

  state = gh_scm2bool (in_state) ? TRUE : FALSE;
  redo_set_sensitive (state);

  return SCM_EOL;
}

static SCM scm_get_card_width() 
{
  return gh_long2scm(get_card_width());
}

static SCM scm_get_card_height() 
{
  return gh_long2scm(get_card_height());
}

static SCM scm_get_horiz_offset() 
{
  return gh_long2scm(get_horiz_offset());
}

static SCM scm_get_vert_offset() 
{
  return gh_long2scm(get_vert_offset());
}

static SCM scm_get_horiz_start() 
{
  return gh_long2scm(get_horiz_start());
}

static SCM scm_get_vert_start() 
{
  return gh_long2scm(get_vert_start());
}

static SCM scm_set_statusbar_message(SCM message)
{
  gnome_appbar_clear_stack (GNOME_APPBAR (GNOME_APP (app)->statusbar));
  gnome_appbar_push (GNOME_APPBAR(GNOME_APP (app)->statusbar), _(gh_scm2newstr(message,NULL)));
  return SCM_EOL;
}

static SCM scm_set_surface_layout(SCM surface) 
{
  if (surface != SCM_EOL) {
    SCM list_el;
  
    delete_surface();

    for (list_el = surface; list_el != SCM_EOL; list_el = SCM_CDR(list_el))
      add_slot(SCM_CAR(list_el));
  }
  return SCM_EOL;
}


static SCM scm_reset_surface() 
{
  delete_surface();
  return SCM_EOL;
}

static SCM gg_scm_add_slot(SCM slot) 
{
  add_slot(slot);
  return SCM_EOL;
}

static SCM scm_set_slot_y_expansion(SCM scm_slot_id, SCM new_exp_val)
{
  hslot_type slot = get_slot(gh_scm2int(scm_slot_id));
  slot->dy = gh_scm2int(new_exp_val);
  return SCM_EOL;
}

static SCM scm_set_slot_x_expansion(SCM scm_slot_id, SCM new_exp_val)
{
  hslot_type slot = get_slot(gh_scm2int(scm_slot_id));
  slot->dx = gh_scm2int(new_exp_val);
  return SCM_EOL;
}

static SCM scm_get_slot(SCM scm_slot_id) 
{
  SCM cards = SCM_EOL;
  hslot_type slot = get_slot(gh_scm2int(scm_slot_id));
  GList* tempcard;
  
  if (slot) {
    for (tempcard = slot->cards; tempcard; tempcard = tempcard->next)
      cards = gh_cons(make_card(tempcard->data), cards);

    cards = gh_cons(scm_slot_id, gh_cons(cards, SCM_EOL));
  }
  return cards; 
}

static SCM scm_set_cards(SCM scm_slot_id, SCM new_cards) 
{
  hslot_type hslot = get_slot(gh_scm2int(scm_slot_id));
  GList* tempptr;
  
  for (tempptr = hslot->cards; tempptr; tempptr = tempptr->next)
    free(tempptr->data);

  hslot->cards = new_deck(new_cards);
  update_slot_length(hslot);

  return SCM_BOOL_T;
}

static SCM scm_set_lambda(SCM start_game_lambda, 
                          SCM pressed_lambda, 
                          SCM released_lambda, 
                          SCM clicked_lambda, 
                          SCM dbl_clicked_lambda,
                          SCM game_over_lambda,
                          SCM winning_game_lambda,
                          SCM hint_lambda,
                          SCM rest) 
{
  if (!game_data)
	 game_data = malloc(sizeof(lambda_data));
  game_data->start_game_lambda = start_game_lambda;
  game_data->button_pressed_lambda = pressed_lambda;
  game_data->button_released_lambda = released_lambda;
  game_data->button_clicked_lambda = clicked_lambda;
  game_data->button_double_clicked_lambda = dbl_clicked_lambda;
  game_data->game_over_lambda = game_over_lambda;
  game_data->winning_game_lambda = winning_game_lambda;
  game_data->hint_lambda = hint_lambda;
  game_data->get_options_lambda = gh_car(rest);
  game_data->apply_options_lambda = gh_cadr(rest);
  game_data->timeout_lambda = gh_caddr(rest);
  return SCM_EOL;
}

static SCM scm_myrandom(SCM range) 
{
  return gh_long2scm(g_random_int_range(0,SCM_INUM(range)));
}

static SCM scm_get_score() 
{
  return gh_int2scm(score);
}

static SCM scm_set_score(SCM new) 
{
  score = gh_scm2int(new);
  set_score();
  return gh_int2scm(score);
}

static SCM scm_add_to_score(SCM new) 
{
  score += gh_scm2int(new);
  set_score();
  return gh_int2scm(score);
}

static SCM scm_set_timeout (SCM new) 
{
  timeout = gh_scm2int(new);
  return new;
}

static SCM scm_get_timeout () 
{
  return gh_int2scm(timeout);
}

void cscm_init () 
{
  /* FIXME: On 1997-11-14, gh_enter stopped loading `icd-9/boot-9.scm'.
     In my copy of guile, the first define in boot-9.scm is for "provide",
     and it looked as good a test as any  */
  gh_eval_str ("(if (not (defined? \'provide))\n"
  	       "  (primitive-load-path \"ice-9/boot-9.scm\"))");
  gh_new_procedure0_0("get-card-width", scm_get_card_width);
  gh_new_procedure0_0("get-card-height", scm_get_card_height);
  gh_new_procedure0_0("get-horiz-offset",scm_get_horiz_offset);
  gh_new_procedure0_0("get-vert-offset", scm_get_vert_offset);
  gh_new_procedure0_0("get-horiz-start", scm_get_horiz_start);
  gh_new_procedure0_0("get-vert-start", scm_get_vert_start);
  gh_new_procedure1_0("set-statusbar-message", scm_set_statusbar_message);
  gh_new_procedure1_0("set-surface-layout", scm_set_surface_layout);
  gh_new_procedure0_0("reset-surface", scm_reset_surface);
  gh_new_procedure1_0("add-slot", gg_scm_add_slot);
  gh_new_procedure1_0("get-slot", scm_get_slot);  
  gh_new_procedure2_0("set-cards-c!", scm_set_cards);
  gh_new_procedure2_0("set-slot-y-expansion!", scm_set_slot_y_expansion);
  gh_new_procedure2_0("set-slot-x-expansion!", scm_set_slot_x_expansion);
  gh_new_procedure("set-lambda", scm_set_lambda, 8, 0, 1);
  gh_new_procedure1_0("random", scm_myrandom);
  gh_new_procedure0_0("get-score", scm_get_score);  
  gh_new_procedure1_0("set-score!", scm_set_score);
  gh_new_procedure0_0("get-timeout", scm_get_timeout);  
  gh_new_procedure1_0("set-timeout!", scm_set_timeout);
  gh_new_procedure1_0("add-to-score!", scm_add_to_score);
  gh_new_procedure("_", scm_gettext, 1, 0, 0);
  gh_new_procedure1_0("undo-set-sensitive", scm_undo_set_sensitive);
  gh_new_procedure1_0("redo-set-sensitive", scm_redo_set_sensitive);
  eval_installed_file ("sol.scm");
}
