#!/bin/bash
#
# sliders : http://wingtk.sourceforge.net/ishan/sliders.html
#           http://www.hc11.demon.nl/15puzzle/15puzzen.htm
#
# Created by alain COURIVAUD, august 2008
#
#-----------------------------------------------------------


# Pipe filename must be unique for your application
PIPE="/tmp/gtk.bash.\$$"

# Find GTK-server configfile first
if [[ -f gtk-server.cfg ]]; then
 CFG=gtk-server.cfg
elif [[ -f /etc/gtk-server.cfg ]]; then
 CFG=/etc/gtk-server.cfg
elif [[ -f /usr/local/etc/gtk-server.cfg ]]; then
 CFG=/usr/local/etc/gtk-server.cfg
else
 echo "No GTK-server configfile found! Please install GTK-server..."
 exit 1
fi

# Now create global functionnames from GTK API
if [[ ! -f $HOME/.gtk4bash || $CFG -nt $HOME/.gtk4bash ]]; then
 echo "#!/bin/bash" > $HOME/.gtk4bash
 echo "gtk-server -fifo=$PIPE &" >> $HOME/.gtk4bash
 echo "while [ ! -p $PIPE ]; do continue; done" >> $HOME/.gtk4bash
 while read LINE
 do
 if [[ $LINE = *FUNCTION_NAME* ]]; then
     LINE=${LINE#*= }
     printf "\nfunction ${LINE%%,*}\n" >> $HOME/.gtk4bash
     printf "{\n/bin/echo ${LINE%%,*} \$@ > $PIPE" >> $HOME/.gtk4bash
     printf "\nread GTK < $PIPE\n}\n" >> $HOME/.gtk4bash
 fi
 done < $CFG
fi

# Declare global variables
declare GTK NULL="NULL"
unset CFG PIPE LINE

# Include the generated file to use embedded GTK functions
. ${HOME}/.gtk4bash

#---------------------------------------------------------- Global inits

# GTK-server must go after an error in the script
trap 'echo "gtk_server_exit" > $PIPE' ERR

# Define SIGUSR1 in GTK-server configfile to catch exit of GTK-server
trap 'exit' SIGUSR1

# Assignment function
function define() { $2 $3 $4 $5 $6 $7 $8 $9; eval $1="$GTK"; }


# Save my directory
MYDIR=${0%/*}

gtk_init $NULL $NULL

# Window
define WIN gtk_window_new 0
#gtk_window_set_default_size $WIN 300 300     #why can't i use it for the WIN size ?
gtk_widget_set_size_request $WIN 200 200
gtk_window_set_title $WIN "TAQUIN"
gtk_window_set_position $WIN 1
gtk_window_set_resizable $WIN 0

#Vbox
define VBOX gtk_vbox_new 0 0
gtk_container_add $WIN $VBOX
gtk_widget_show $VBOX

# Accec_group
define GRP gtk_accel_group_new
gtk_window_add_accel_group $WIN $GRP

# Menubar
define BAR gtk_menu_bar_new
define FILE gtk_menu_item_new_with_mnemonic "_File"
define HELP gtk_menu_item_new_with_mnemonic "_Help"

define FILEMENU gtk_menu_new
define HELPMENU gtk_menu_new

gtk_menu_item_set_submenu $FILE $FILEMENU
gtk_menu_item_set_submenu $HELP $HELPMENU

# File menu content
define NEW gtk_image_menu_item_new_from_stock "gtk-new" $GRP
define QUIT gtk_image_menu_item_new_from_stock "gtk-quit" $GRP

# Help menu content
define ABOUT gtk_image_menu_item_new_from_stock "gtk-about" $GRP
#define ABOUT gtk_menu_item_new_with_mnemonic "_About" $GRP  
#FUNCTION_NAME = gtk_widget_add_accelerator, NONE, NONE, 6, WIDGET, STRING, WIDGET, LONG, LONG, LONG
gtk_widget_add_accelerator $ABOUT "activate" $GRP 97 1 1  

#separator
define SEPARATOR_FILE gtk_separator_menu_item_new
gtk_widget_set_sensitive $SEPARATOR_FILE 0

gtk_box_pack_start $VBOX $BAR 0 0 1
gtk_container_add $BAR $FILE
gtk_container_add $FILEMENU $NEW
gtk_container_add $FILEMENU $SEPARATOR_FILE 
gtk_container_add $FILEMENU $QUIT
gtk_container_add $BAR $HELP
gtk_container_add $HELPMENU $ABOUT

gtk_server_connect  $QUIT "activate" "al1_gtk_quit"
gtk_server_connect  $NEW "activate" "al1_gtk_new"
gtk_server_connect  $ABOUT "activate" "al1_gtk_about"


#alignement
define ALIGNEMENT gtk_alignment_new 0.5 0.5 1 1

gtk_box_pack_start $VBOX $ALIGNEMENT 1 1 0
gtk_alignment_set_padding $ALIGNEMENT 20 20 40 40


#table
define TAB gtk_table_new  4 4 1
#gtk_box_pack_start $VBOX $TAB 1 1 1
gtk_container_add $ALIGNEMENT $TAB
gtk_widget_show $TAB

#buttons
for x in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
do
 temp=$x
 define BTN[$x] gtk_button_new_with_label "$((x + 1))" 
 gtk_object_set_data ${BTN[$x]} "current_pos" "$x"
 unset temp
done

c=0
for x in 0 1 2 3
do
 for y in 0 1 2 3
 do
  if ! [[ ($x -eq 3 &&  $y -eq 3) ]]
  then
    gtk_table_attach_defaults $TAB ${BTN[$c]} $y $((y + 1)) $x $((x + 1)) 
    gtk_widget_show ${BTN[$c]}
    ((c = c + 1))
   fi       
 done
done


# Status bar
define STATUSBAR gtk_statusbar_new
gtk_statusbar_set_has_resize_grip $STATUSBAR 0
gtk_box_pack_start $VBOX $STATUSBAR 0 0 1
gtk_statusbar_push $STATUSBAR 0 "'Welcome to TAQUIN...'"
gtk_widget_show $STATUSBAR



# Show all widgets
gtk_widget_show_all $WIN


#---------------------------------------------------------- Init variables

VACANT_POS=15
MOVE_NO=1

#---------------------------------------------------------- Functions
function has_player_won
{

gagne="OUI"

for x in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
do
# set -x
  echo "x : " $x
  define POS gtk_object_get_data ${BTN[$x]} "current_pos"
  echo "pos : " $POS
  if ! [[ $x -eq  $POS  ]]
  then
    gagne="NON" 
  fi
set +x
done

}


function is_legal
{
# set -x
((vacant_x_pos = VACANT_POS % 4))
((vacant_y_pos = VACANT_POS / 4))
((current_x_pos = CURRENT_POS % 4))
((current_y_pos = CURRENT_POS / 4))

((diffa = vacant_x_pos - current_x_pos))
((diffb = vacant_y_pos - current_y_pos))

# val abs d'un entier : x=${x#-}
a=${diffa#-}
b=${diffb#-}


if [[ ( (($a -eq 1 && $b -eq 0) || ($a -eq 0 && $b -eq 1)) && !($a -eq 1 && $b -eq 1) ) ]]
then
   libre="OUI"
   gtk_statusbar_push $STATUSBAR 0 "'Move N° : $MOVE_NO'"
else
   libre="NON"
   gtk_statusbar_push $STATUSBAR 0 "'Illegal move !'"
fi
set +x
}


function move
{

define CURRENT_POS gtk_object_get_data ${BTN[$1]} "current_pos"

is_legal

if [[ $libre = "OUI" ]]
then
   ((x_pos = VACANT_POS % 4))
   ((y_pos = VACANT_POS / 4))
   gtk_container_remove $TAB ${BTN[$1]}
   define BTN[$1] gtk_button_new_with_label "$(($1 + 1))" 
   gtk_table_attach_defaults $TAB ${BTN[$1]} $x_pos $((x_pos + 1)) $y_pos $((y_pos + 1)) 
   gtk_widget_show ${BTN[$1]}
   gtk_object_set_data ${BTN[$1]} "current_pos" "$VACANT_POS"
   VACANT_POS=$CURRENT_POS
   ((MOVE_NO = MOVE_NO + 1))
   
   has_player_won

   if [[ $gagne = "OUI" ]]
   then
     gtk_widget_hide $TAB
     define IMAGE gtk_image_new
     gtk_image_set_from_file $IMAGE "coupe1.jpeg"
     gtk_object_ref $TAB
     gtk_container_remove $ALIGNEMENT $TAB
     gtk_container_add $ALIGNEMENT $IMAGE
     gtk_widget_show $IMAGE
     gtk_statusbar_push $STATUSBAR 0 "'Win ! in $((MOVE_NO - 1)) move(s)'"

 
   fi
fi

}


function swap_buttons
{

define P_POS gtk_object_get_data ${BTN[$1]} "current_pos"
define Q_POS gtk_object_get_data ${BTN[$2]} "current_pos"

((p_x_pos = $P_POS % 4))
((p_y_pos = $P_POS / 4))
((q_x_pos = $Q_POS % 4))
((q_y_pos = $Q_POS / 4))

gtk_object_ref ${BTN[$1]}
gtk_object_ref ${BTN[$2]}
gtk_container_remove $TAB ${BTN[$1]}
gtk_container_remove $TAB ${BTN[$2]}

gtk_table_attach_defaults $TAB ${BTN[$1]} $q_x_pos $((q_x_pos + 1)) $q_y_pos $((q_y_pos + 1)) 
gtk_table_attach_defaults $TAB ${BTN[$2]} $p_x_pos $((p_x_pos + 1)) $p_y_pos $((p_y_pos + 1)) 

gtk_object_set_data ${BTN[$1]} "current_pos" "$Q_POS"
gtk_object_set_data ${BTN[$2]} "current_pos" "$P_POS"

}


function on_new_activate
{

MOVE_NO=1

if [[ $IMAGE ]]
then
  gtk_object_ref $IMAGE
  gtk_container_remove $ALIGNEMENT $IMAGE
  gtk_container_add $ALIGNEMENT $TAB
  gtk_widget_show $TAB

  #gtk_container_remove $VBOX $STATUSBAR
  #gtk_box_pack_start $VBOX $TAB 1 1 1
  #gtk_widget_show $TAB
  #define STATUSBAR gtk_statusbar_new
  #gtk_box_pack_start $VBOX $STATUSBAR  1 1 1
  #gtk_statusbar_push $STATUSBAR 0 "'Welcome to TAQUIN...'"
  #gtk_widget_show $STATUSBAR
fi

for x in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
do
  rand=$(($RANDOM%15))
  if ! [[ $x -eq $rand ]]
  then
   swap_buttons $x $rand
  fi
done

}

function on_about_activate
{

gtk_server_version
define DIALOG gtk_message_dialog_new $WIN 0 0 2 "'\t\t  TAQUIN \r\rBASH ${BASH_VERSION#* } with GTK-server $GTK.\r\r\tVisit http://www.gtk-server.org/ for more info!'"
gtk_window_set_title $DIALOG "'About this program'"
gtk_widget_show $DIALOG
gtk_dialog_run $DIALOG
gtk_widget_destroy $DIALOG

}
#---------------------------------------------------------- Mainloop

until [[ $EVENT = $WIN || $EVENT = "al1_gtk_quit" ]]
do

define EVENT gtk_server_callback "wait"

   case $EVENT in

      "al1_gtk_new")
        on_new_activate;;

      "al1_gtk_about")
        on_about_activate;;

      ${BTN[0]})
	move 0;;

      ${BTN[1]})
        move 1;;

      ${BTN[2]})
        move 2;;

      ${BTN[3]})
        move 3;;

      ${BTN[4]})
        move 4;;

      ${BTN[5]})
        move 5;;

      ${BTN[6]})
        move 6;;

      ${BTN[7]})
        move 7;;

      ${BTN[8]})
        move 8;;

      ${BTN[9]})
        move 9;;

      ${BTN[10]})
        move 10;;

      ${BTN[11]})
        move 11;;

      ${BTN[12]})
        move 12;;
   
      ${BTN[13]})
        move 13;;

      ${BTN[14]})
        move 14;;

      ${BTN[15]})
        move 15;;
   
   esac

done

# Exit GTK
gtk_server_exit
