/* 
 *  Linux memory game
 *  By Xiaoguang Zhang
 */

#include <gtk/gtk.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <stdlib.h>
#include "lmemory.h"

  int flipped;
  int flipped_btn[3];

/*
remove a pixmap
*/
void
lmem_remove_card(GtkWidget * widget,GtkWidget * pixmap)
{
	gtk_widget_hide(pixmap);
	gtk_object_ref(GTK_OBJECT(pixmap));
  	gtk_container_remove(GTK_CONTAINER(widget),pixmap);
}

/*
Each card has two pixmaps. When it's flipped we hide the one that is
showing and show the one hidden
*/
void
flip_pixmap (GtkWidget * widget, GtkWidget * pixmap1, GtkWidget * pixmap2)
{
        lmem_remove_card(widget,pixmap1);

	gtk_widget_show(pixmap2);
  	gtk_container_add(GTK_CONTAINER(widget),pixmap2);
	gtk_object_unref(GTK_OBJECT(pixmap2));
}

/*
Move all cards on their backs by lmem_jump
*/
void
pixmaps_jump ( gint lmem_jump )
{
  gint lmem_temp[NUM];
  gint j, k;

  j = 0;
  while (j<NUM)
  {
    lmem_temp[j] = lmem_state[j];
    j++;
  }

  j = 0;
  while (j<NUM)
  {
/*
Skip the blank squares (no cards)
*/
    if (lmem_state[j] != 0) {
    k = j+lmem_jump;
/* Wrap around if we move to the last square */
    if(k>=NUM) k = k-NUM;
    while (lmem_temp[k]==0)
    {
      k++;
      if(k==NUM) k=0;
    }

    lmem_state[j] = lmem_temp[k];
    lmem_temp[k] = 0; /* erase this because it's been used */
    }
    j++;
  }

}

/*
Flip the card that is clicked
*/
void
lmem_flip_card (GtkWidget * widget, gpointer * data)
{
  gint k, l, lmem_jump;
  gint j;
  char *frame_label;

  click_count++;
  asprintf(&frame_label, "%s:  %i",indicator[lmem_level],click_count);
  gtk_frame_set_label((GtkFrame *)frame,(gchar *)frame_label);

  if(lmem_state[(int) data]>0){
/*
If there are already two cards turned up, we turn those two cards
back.
*/
    if(flipped == match_card) {
    j = 0;
    while ( j <= flipped-1 ) {
      k = flipped_btn[j];
      if(lmem_state[k]<0){
        flip_pixmap (button[k], second_pixmap[-lmem_state[k]-match_card],
	   default_pixmap[k]);
	lmem_state[k] = -lmem_state[k];
      }
      j++;
    }
    flipped = 0;

/*
Moved the other cards if the skill level is appropriate
*/
      switch (lmem_level)
      {
	case MASTER:
	case DAEMON:
	  lmem_jump = 1;
	  break;
	default:
	  lmem_jump = 0;
      }
      if(lmem_jump>0) pixmaps_jump(lmem_jump);
    }

    k = (int) data;
      flipped_btn[flipped] = k;
      l = lmem_state[k]-match_card;
      flip_pixmap (button[k], default_pixmap[k], second_pixmap[l]);
/*
If two cards are matched remove both
*/
      if( (flipped==match_card-1) &&
          (lmem_state[flipped_btn[0]]/match_card==-lmem_state[k]/match_card) &&
          (lmem_state[flipped_btn[0]]/match_card==lmem_state[flipped_btn[flipped-1]]/match_card) ){
        lmem_remove_card(button[k],second_pixmap[l]);
        lmem_state[k]=0;
      j = 0;
      while ( j <= flipped-1 ) {
	k = flipped_btn[j];
	l = -lmem_state[k]-match_card;
        lmem_remove_card(button[k],second_pixmap[l]);
        lmem_state[k]=0;
        j++;
      }
        flipped = 0;
/*
Move the other cards if the skill level is appropriate
*/
        switch (lmem_level)
        {
	  case SKILLED:
	  case MASTER:
	    lmem_jump = 1;
	    break;
	  case DAEMON:
	    lmem_jump = lln_get_random ( (double) NUM);
	    break;
	  default:
	    lmem_jump = 0;
        }
        if(lmem_jump>0) pixmaps_jump(lmem_jump);
      }else{
/*
If a card is flipped, its lmem_state is also flipped :-)
*/
	lmem_state[k] = -lmem_state[k];
        flipped++;
      }
  }

}


void
delete_event (GtkWidget * widget, GdkEvent * event, gpointer * data)
{
  gtk_main_quit ();
}

void
lmem_pixmaps(GtkWidget *window, GSList *image_files)
{
  gint k, l;

  k = 0;
  while( k < NUM)
  {
      if(lmem_state[k] == 0) {
        default_pixmap[k] = (gpointer) xpm_widget_default(window);
        gtk_container_add (GTK_CONTAINER (button[k]), default_pixmap[k]);
        gtk_widget_show (default_pixmap[k]);
      }
      lmem_state[k] = 0;
      k++;
  }

  k = 0;
  while( k < NUM)
  {
      second_pixmap[k] = (gpointer) xpm_widget(window, image_files->data);
      gtk_object_ref(GTK_OBJECT(second_pixmap[k]));
      
      if( (((k+1)%match_card)==0 || same_card==1 ) )
        image_files = image_files->next;
      k++;
  }
}

/*
Reset to a new game
*/
void
lmem_Newgame (GtkWidget *window, guint callback_action, GtkWidget * widget)
{
  gint j, k, l;
  GSList *image_files;
  char *frame_label;

  click_count=0;
/*  printf("lmem_level=%i\n",lmem_level); */
  asprintf(&frame_label, "%s:  0",indicator[lmem_level]);
  gtk_frame_set_label((GtkFrame *)frame,(gchar *)frame_label);
/*
First remove any card that is turned up
*/
    k=0;
    while(k<NUM){
      if(lmem_state[k]<0){
	l = -lmem_state[k]-match_card;
        lmem_remove_card(button[k],second_pixmap[l]);
	lmem_state[k]=0;
      }
      k++;
    }

/*
Reread the image files
*/
  image_files = lmem_dir_list(NULL,lmem_image_dir);
  if(image_files == NULL) exit(1);
  lmem_pixmaps(window, image_files);

/*
Randomly assign the image files to positions on the grid
*/
    j=0;
    while(j<NUM){

      l = lln_get_random((double) NUM-j);
      k=-1;
      while(l>0){
	k++;
        if(lmem_state[k]==0) l--;
      }
      lmem_state[k] = j+match_card;

      j++;
    }
/*
If the skill level is LITTLE_ONE then we start with all the
cards turned up
*/
    if(lmem_level == LITTLE_ONE){
      k=0;
      while(k<NUM){
        l = lmem_state[k]-match_card;
        flip_pixmap (button[k], default_pixmap[k], second_pixmap[l]);
	default_pixmap[k] = second_pixmap[l];
        second_pixmap[l] = (gpointer) xpm_widget_default(window);
        gtk_object_ref(GTK_OBJECT(second_pixmap[l]));
        k++;
      }
    }
    flipped = 0;
    flipped_btn[0] = -1;
    flipped_btn[1] = -1;
    flipped_btn[match_card-1] = -1;

}

const char *indicator[5] = {"Little One","Beginner","Skilled","Master","Daemon"};
void
lmem_setup()
{
  gint x, z, i, j, k, l;

  GtkWidget *window;
  GtkWidget *box[SIZE];
  GtkWidget *bigbox;
  GtkWidget *vbox;
  GtkWidget *menubar;
  GtkWidget *reset_box;
  GtkWidget *reset_button;
  GtkWidget *label;
  gint pixmap_size = PIXMAP_SIZE;

  lln_set_random();

  /* create a new window */
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW (window), "The memory game");
  gtk_window_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);

  gtk_signal_connect (GTK_OBJECT (window), "delete_event",
		      GTK_SIGNAL_FUNC (delete_event), NULL);

  /* sets the border width of the window. */
  gtk_container_border_width (GTK_CONTAINER (window), 10);

  /* we create boxes to pack widgets into */
  bigbox = gtk_vbox_new (FALSE, 0);

  /* put the box into the main window. */
  gtk_container_add (GTK_CONTAINER (window), bigbox);

  get_main_menu (window, &menubar);
  gtk_box_pack_start (GTK_BOX (bigbox), menubar, FALSE, TRUE, 0);
/*  gtk_widget_show (menubar); */
  frame = gtk_frame_new(NULL);
  gtk_box_pack_start (GTK_BOX (bigbox), frame, FALSE, TRUE, 0);
  vbox = gtk_vbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (frame), vbox);

  k = 0;
  j = 0;
  while (j < SIZE)
    {box[j] = gtk_hbox_new (TRUE, 0);
  /* put the horizontal boxes into the vertical one */
  gtk_box_pack_start (GTK_BOX (vbox), box[j], TRUE, TRUE, 1);

  /* Make a row of buttons */
  i = 0;
  while (i < SIZEP)
    {
      button[k] = gtk_button_new ();
      gtk_widget_set_usize ( button[k], pixmap_size, pixmap_size);

      gtk_box_pack_start (GTK_BOX (box[j]), button[k], TRUE, TRUE, 1);

      /* Now when the button is clicked, we call the "show_number" function
       *        * with a pointer to the button as it's argument */
      gtk_signal_connect (GTK_OBJECT (button[k]), "clicked",
			  GTK_SIGNAL_FUNC (lmem_flip_card), (gpointer) k);
      k++;
      i++;
    }
      j++;
    }

  /* Default to BEGINNER level and same_card = 2*/

    lmem_level = BEGINNER;
    match_card = 2;
    same_card = 2;

    gtk_widget_show_all (window);

    lmem_Newgame (window,0,NULL);

}

void
lln_set_random ()
{
  time_t t1;

  (void) time (&t1);
  /* use time in seconds to set seed */
  srand ((int) t1);
}

int
lln_get_random (double max)
{
  int i;

  i = 1 + (int) (max * rand () / (RAND_MAX + 1.0));
  //1+(rand() % max);

  return (i);
}
