
/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include <stdlib.h>
#include <stdio.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <glib/gstdio.h>
#include <string.h>

/* Backing pixmap for drawing area */
static GdkPixmap *pixmap = NULL;

//buffer pixmap which will be drawn into the pixmap drawn on screen
static GdkPixmap *buffer_pixmap = NULL;

//point data to be added to an appropriate file upon leaving the relevant page [or exiting?]
static GList *points_list = NULL;

//static char *folder_name = "chopin_prelude_op45-a4";
static int current_page = 0;
static int prev_page = 0;

static int vert_page_progress = 0;
static int hori_page_progress = 0;

//percentage of height at which we change from uncovering vertically to horizontally
static int change_height_percent=80;

static GdkPixbuf *pp_pbuf_image = NULL;
static GdkGC* pp_gc = NULL;

static int pp_width = 0;
static int pp_height = 0;

static int page_width = 0;
static int page_height = 0;

//for tracking mouse movement
static int last_x_pos = -1;
static int last_y_pos = -1;


static gboolean in_progress = FALSE;

static gboolean load_show_page(	GtkWidget	*widget,
				char		*folder_name,
				int		page_number);

static gboolean load_show_page_immediate(	GtkWidget	*widget,
					char		*folder_name,
					int		page_number);

static gboolean read_point_data_from_file (GtkWidget	*widget,
					   GdkPixmap	*drawing_pixmap,
						char	*filename);


static guint timeout_id = 0;


static gboolean update_progress_page(gpointer data)
{
  GtkWidget* widget = (GtkWidget*)data;

  g_print("updating page progress = %d\n", vert_page_progress);

  if (vert_page_progress < 100)
  {
    if (vert_page_progress < change_height_percent)
    {

      int prev_height = (int)(pp_height * (vert_page_progress / 100.0));
      vert_page_progress+=10;
      int update_height = (int)(pp_height * (vert_page_progress / 100.0));
  
//      gdk_draw_pixbuf (pixmap, pp_gc, pp_pbuf_image, 
//		     0, 0, 0, 0, -1, update_height, GDK_RGB_DITHER_NONE, 0, 0);

      gdk_draw_drawable (pixmap, pp_gc, buffer_pixmap, 
		     0, 0, 0, 0, -1, update_height);
  
      gtk_widget_queue_draw_area (widget,
		                0, prev_height,
  		                pp_width, update_height - prev_height);
      return TRUE;
    }
    else
    {
      //update horizontally
      if (hori_page_progress < 100)
      {

        hori_page_progress+=10;

        int update_height = (int)(pp_height * (vert_page_progress / 100.0));
        int update_width = (int)(pp_width * (hori_page_progress / 100.0));

//        gdk_draw_pixbuf (pixmap, pp_gc, pp_pbuf_image, 
//		       0, update_height, 0, update_height, update_width, pp_height - update_height, GDK_RGB_DITHER_NONE, 0, 0);

      gdk_draw_drawable (pixmap, pp_gc, buffer_pixmap, 
		     0, update_height, 0, update_height, update_width, pp_height - update_height);

        gtk_widget_queue_draw_area (widget,
		                  0, update_height,
   		                  update_width, pp_height);

	return TRUE;

      }
      else
      {
        //reset values
//        vert_page_progress = 0;
//        hori_page_progress = 0;
	in_progress = FALSE;



 	return FALSE;
      }
    }
  }

  else
  {

    //reset values
//    vert_page_progress = 0;
//    hori_page_progress = 0;
    in_progress = FALSE;
    return FALSE;
  }

}


/* Create a new backing pixmap of the appropriate size */
static gboolean configure_event( GtkWidget         *widget,
                                 GdkEventConfigure *event,
				 gpointer	    folder_name )
{

//  char *filename = "chopin_prelude_op45-a4/chopin_prelude_op45-a4-page00.tif";
//  char *filename = "page1.tif";
 
  if (pixmap)
    g_object_unref (pixmap);

  pixmap = gdk_pixmap_new (widget->window,
			   widget->allocation.width,
			   widget->allocation.height,
			   -1);

  buffer_pixmap = gdk_pixmap_new (widget->window,
			   widget->allocation.width,
			   widget->allocation.height,
			   -1);


  gdk_draw_rectangle (pixmap,
		      widget->style->black_gc,
		      TRUE,
		      0, 0,
		      widget->allocation.width,
		      widget->allocation.height);


  pp_gc = gdk_gc_new (pixmap);

  //reset values
  vert_page_progress = 0;
  hori_page_progress = 0;
  in_progress = TRUE;
  load_show_page_immediate (widget, (char*)folder_name, 0);

  return TRUE;
}

/* Redraw the screen from the backing pixmap */
static gboolean expose_event( GtkWidget      *widget,
                              GdkEventExpose *event )
{
  gdk_draw_drawable (widget->window,
		     widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
		     pixmap,
		     event->area.x, event->area.y,
		     event->area.x, event->area.y,
		     event->area.width, event->area.height);

  return FALSE;
}




#define min2(x,y) (x<y)?x:y
#define max2(x,y) (x>y)?x:y
//connecting line
static void draw_connecting_line (GtkWidget	*widget,
				  GdkPixmap	*drawing_pixmap,
				  gdouble	last_x,
				  gdouble	last_y,
				  gdouble	x,
				  gdouble	y)
{ 
  //we are going to draw a line between two points instead of just drawing the next point
  gdk_gc_set_line_attributes (	widget->style->black_gc,
				2, GDK_LINE_SOLID,
				GDK_CAP_BUTT, GDK_JOIN_ROUND);

  gdk_draw_line ( drawing_pixmap,
		  widget->style->black_gc,
		  last_x, last_y,
		  x, y);

  int x_min = min2(x, last_x);
  int y_min = min2(y, last_y);
  int x_max = max2(x, last_x);
  int y_max = max2(y, last_y);
	
  gtk_widget_queue_draw_area (	widget,
				x_min - 2, y_min - 2,
				x_max - x_min + 5, y_max - y_min + 5);
}

/* Draw a rectangle on the screen */
static void draw_brush( GtkWidget *widget,
			GdkPixmap *drawing_pixmap,
                        gdouble    x,
                        gdouble    y)
{
  GdkRectangle update_rect;

  update_rect.x = x - 2;
  update_rect.y = y - 2;
  update_rect.width = 4;
  update_rect.height = 4;
  gdk_draw_rectangle (drawing_pixmap,
		      widget->style->black_gc,
		      TRUE,
		      update_rect.x, update_rect.y,
		      update_rect.width, update_rect.height);
  gtk_widget_queue_draw_area (widget,
		              update_rect.x, update_rect.y,
		              update_rect.width, update_rect.height);
}



static gboolean file_exists (char *filename)
{
  //if NULL is returned then the file probably does not exist; return false
  if (g_fopen(filename, "r") == NULL) return FALSE;
  return TRUE;
}

static gboolean load_show_page(	GtkWidget	*widget,
				char		*folder_name,
				int		page_number)
{


      char filename[512];
      sprintf(filename, "%s/%s-page%02d.tif", folder_name, folder_name, page_number);


      g_print("%s\n\n", filename);


//      filename = "chopin_prelude_op45-a4/chopin_prelude_op45-a4-page01.tif";


  if (!file_exists(filename)) return FALSE;


  //get the percentage of page to load/display before swapping from vertical loading to horizontal loading
  char filename_pagebreak[512];
  sprintf (filename_pagebreak, "%s.pagebreak", filename);
  if (file_exists(filename_pagebreak)) {
    FILE *file = fopen(filename_pagebreak, "r");
    char line_buf[10]; //shouldn't be longer than 2 characters, really
    fgets(line_buf, 10, file);
    change_height_percent = atoi ( line_buf );
  }
  else
  {
    change_height_percent = 80; //defaults to 80% if there is no pagebreak file
  }
  g_print("change_height_percent: %d\n", change_height_percent);



  // Get the origial image size.
  gdk_pixbuf_get_file_info(filename, &pp_width, &pp_height);
  page_width = widget->allocation.width;
  page_height = widget->allocation.height;

  gdk_drawable_get_size(pixmap, &page_width, &page_height);

//getting the scaled sizes to load the image in at fullscreen
  int w = pp_width;
  int h = pp_height;
  double scale = 1;
  if (pp_width >= pp_height)
  {
    if (pp_width != page_width)
    {
      scale = (double)pp_width / (double)page_width;
    }
  }
  else if (pp_height > pp_width)
  {
    if (pp_height != page_height)
    {
      scale = (double)pp_height / (double)page_height;
    }
  }
  w = (int)((double)pp_width / scale);
  h = (int)((double)pp_height / scale)- 1;
  pp_width = w;
  pp_height = h;

  pp_pbuf_image = gdk_pixbuf_new_from_file_at_size(filename, pp_width, pp_height, 0);

      gdk_draw_pixbuf (buffer_pixmap, pp_gc, pp_pbuf_image, 
		     0, 0, 0, 0, -1, -1, GDK_RGB_DITHER_NONE, 0, 0);

//drawing the point/scribble data onto the buffer pixmap
	char point_filename[512];
	sprintf(point_filename, "%s/%s-page%02d.tif.pointdata", folder_name, folder_name, page_number);
	read_point_data_from_file(widget, buffer_pixmap, point_filename);




  //pp_gc = gdk_gc_new (pixmap);




  //reset values
  vert_page_progress = 0;
  hori_page_progress = 0;
  timeout_id = g_timeout_add (1000, update_progress_page, widget);

  return TRUE;

}



static gboolean load_show_page_immediate(  GtkWidget	*widget,
					   char		*folder_name,
					   int		page_number)
{


  char filename[512];
  sprintf(filename, "%s/%s-page%02d.tif", folder_name, folder_name, page_number);


  g_print("%s\n\n", filename);


//      filename = "chopin_prelude_op45-a4/chopin_prelude_op45-a4-page01.tif";


  if (!file_exists(filename)) return FALSE;



  // Get the origial image size.
  gdk_pixbuf_get_file_info(filename, &pp_width, &pp_height);
  page_width = widget->allocation.width;
  page_height = widget->allocation.height;

  gdk_drawable_get_size(pixmap, &page_width, &page_height);

//getting the scaled sizes to load the image in at fullscreen
  int w = pp_width;
  int h = pp_height;
  double scale = 1;
  if (pp_width >= pp_height)
  {
    if (pp_width != page_width)
    {
      scale = (double)pp_width / (double)page_width;
    }
  }
  else if (pp_height > pp_width)
  {
    if (pp_height != page_height)
    {
      scale = (double)pp_height / (double)page_height;
    }
  }
  w = (int)((double)pp_width / scale);
  h = (int)((double)pp_height / scale)- 1;
  pp_width = w;
  pp_height = h;

  pp_pbuf_image = gdk_pixbuf_new_from_file_at_size(filename, pp_width, pp_height, 0);

  //pp_gc = gdk_gc_new (pixmap);



  //reset values
  vert_page_progress = 0;
  hori_page_progress = 0;





      gdk_draw_pixbuf (buffer_pixmap, pp_gc, pp_pbuf_image, 
		     0, 0, 0, 0, -1, -1, GDK_RGB_DITHER_NONE, 0, 0);

//drawing the point/scribble data onto the buffer pixmap
	char point_filename[512];
	sprintf(point_filename, "%s/%s-page%02d.tif.pointdata", folder_name, folder_name, page_number);
	read_point_data_from_file(widget, buffer_pixmap, point_filename);



//current


      gdk_draw_drawable (pixmap, pp_gc, buffer_pixmap, 
		     0, 0, 0, 0, -1, -1);

//	gdk_draw_pixbuf (pixmap, pp_gc, pp_pbuf_image, 0, 0, 0, 0, -1, -1, GDK_RGB_DITHER_NONE,  0, 0);
  
      gtk_widget_queue_draw_area (widget,
		                0, 0,
  		                pp_width, pp_height);





//  g_timeout_add (1000, update_progress_page, widget);

  in_progress = FALSE;

  return TRUE;

}





static gboolean write_point_data_to_file (  char	*filename)
{
  FILE *file;
  file = fopen(filename, "w+");

  GList *curr = points_list;
  while (curr != NULL)
  {
    g_print("writing: %s\n", (char*)curr->data);
    fprintf(file, "%s\n", (char*)curr->data);
    curr = g_list_next(curr);
  }

  fclose(file);

  return TRUE;
}

static gboolean read_point_data_from_file (GtkWidget	*widget,
					   GdkPixmap	*drawing_pixmap,
						char	*filename)
{
  //reset points list
  points_list = NULL;

  FILE *file;
  file = fopen(filename, "r+");
  if (file == NULL)
  {
    g_print ("no point file data\n");
    return FALSE;
  }
  int old_x_val, old_y_val, x_val, y_val;
  gboolean start_line = TRUE;
//  while (feof(file) == 0)
  g_print("gonna scan us some file: %s\n", filename);

  while (fscanf(file, "%d %d\n", &x_val, &y_val) != EOF)
    {
        //add this data to the list of point data, ...
      char *data = malloc(16);
      if (data == NULL)
      {
        fprintf(stderr, "error (failed to allocate memory in button_press_event");
        exit(-1);
      }
      sprintf (data, "%d %d", x_val, y_val);
      points_list = g_list_append(points_list, data);

      g_print("%s\n", data);
//break;
//    fscanf(file, "%d %d\n", &x_val, &y_val);
    if (x_val == -1) //then continue;
    {
      start_line = TRUE;
      continue;
    }
    else if (start_line)
    {
      draw_brush(widget, drawing_pixmap, x_val, y_val);
      old_x_val = x_val;
      old_y_val = y_val;
    }
    else
    {
      draw_connecting_line (widget, drawing_pixmap, old_x_val, old_y_val, x_val, y_val);
      old_x_val = x_val;
      old_y_val = y_val;      
    }
    
    start_line = FALSE;
  }
  fclose(file);
  return TRUE;
}


static gboolean button_release_event( GtkWidget      *widget,
                                    GdkEventButton   *event)
{
  g_print("mouse released\n");
  last_x_pos = -1;
  last_y_pos = -1;

  //add this gap to the list of point data, ...
  points_list = g_list_append(points_list, "-1 -1");

  return TRUE;	
}


static gboolean button_press_event( GtkWidget      *widget,
                                    GdkEventButton *event,
				    gpointer	   folder_name)
{


  if (event->button == 1 && pixmap != NULL)
  {
    if (!in_progress)
    {
      draw_brush (widget, pixmap, event->x, event->y);
      last_x_pos = event->x;
      last_y_pos = event->y;

      //add this data to the list of point data, ...
      char *data = malloc(16);
      if (data == NULL)
      {
	fprintf(stderr, "error (failed to allocate memory in button_press_event");
	exit(-1);
      }
      sprintf (data, "%d %d", (int)event->x, (int)event->y);
      points_list = g_list_append(points_list, data);

      //g_print("%x\n", folder_name);

      //in_progress = TRUE;

      //current_page += 1;
      //load_show_page (widget, (char*)folder_name, current_page);
    }
    else
    {
      g_print("in progress so can't draw\n");
    }
  }

  return TRUE;
}


static gboolean key_press_event( GtkWidget      *widget,
                                 GdkEventKey    *event,
				 gpointer	data_list)
{

if (event->type == GDK_KEY_RELEASE) return TRUE;

GtkWidget *drawing_area = (GtkWidget*)g_list_nth_data(data_list, 0);
char *folder_name = (char*)g_list_nth_data(data_list, 1);

g_print("called keypress event\n");
  if (!in_progress)
  {
  g_print("NOT inprogress\n");
  //write the point data for this page to a file
  char filename[512];
  sprintf(filename, "%s/%s-page%02d.tif.pointdata", folder_name, folder_name, current_page);
  g_print("writing to file: %s", filename);
  write_point_data_to_file (filename);

  switch (event->keyval)
    {
    case GDK_Right:
      printf("right!\n");
      prev_page = current_page;
      current_page += 1;
      break;
    case GDK_Left:
      printf("left!\n");
      prev_page = current_page;
      current_page -= 1;
      break;
    default:
      return TRUE;
    }
    in_progress = TRUE;
    load_show_page (drawing_area, folder_name, current_page);
  }
  else //in progress, so speed up that progress: load page immediately
  {
  g_print("in progress\n");
  switch (event->keyval)
    {
    case GDK_Right:
      g_source_remove(timeout_id);
      if (current_page != prev_page+1)
      {
	current_page = prev_page;
      }
      load_show_page_immediate(drawing_area, folder_name, current_page);
//      printf("right!\n");
//      current_page += 1;
      break;
    case GDK_Left:
      g_source_remove(timeout_id);
      if (current_page != prev_page-1)
      {
	current_page = prev_page;
      }
      load_show_page_immediate(drawing_area, folder_name, current_page);
//      printf("left!\n");
//      current_page -= 1;
      break;
    default:
      return TRUE;
    }
      
//    load_show_page_immediate(drawing_area, folder_name, current_page);
  }

  return TRUE;
}

static gboolean motion_notify_event( GtkWidget *widget,
                                     GdkEventMotion *event )
{
  int x, y;
  GdkModifierType state;

  if (event->is_hint)
    gdk_window_get_pointer (event->window, &x, &y, &state);
  else
    {
      x = event->x;
      y = event->y;
      state = event->state;
    }

  if (state & GDK_BUTTON1_MASK && pixmap != NULL)
  {
    if (!in_progress)
    {
	//if we haven't set x yet, don't do this
	if (last_x_pos == -1) return TRUE;

	draw_connecting_line (widget, pixmap, last_x_pos, last_y_pos, x, y);

	last_x_pos = x;
	last_y_pos = y;



        //add this data to the list of point data, ...
        char *data = malloc(16);
        if (data == NULL)
        {
  	  fprintf(stderr, "error (failed to allocate memory in button_press_event");
	  exit(-1);
        }
        sprintf (data, "%d %d", (int)event->x, (int)event->y);
        points_list = g_list_append(points_list, data);


//      draw_brush (widget, x, y);
    }

  }

  return TRUE;
}

void quit ()
{
  exit (0);
}

int main( int   argc,
          char *argv[] )
{

char *folder_name;

  if (argc == 1)
  {
    //default
    folder_name = "chopin_prelude_op45-a4";
  }
  else
  {
    folder_name = argv[1];
  }


//************************************
/*
FILE *writing;
//int buffer = 256;
int value = 6;
char *filename;
filename = "file.txt";
writing = fopen(filename, "w+");
fprintf(writing, "%d\n", value);
value = 7;
fprintf(writing, "%d\n", value);
value = 8;
fprintf(writing, "%d\n", value);
fclose(writing);

int blah = 0;
writing = fopen(filename, "r+");
fscanf(writing, "%d\n", &blah);
g_print("%d\n", blah);
fscanf(writing, "%d\n", &blah);
g_print("%d\n", blah);
fscanf(writing, "%d\n", &blah);
g_print("%d\n", blah);
fclose(writing);
*/
//************************************


  GtkWidget *window;
  GtkWidget *drawing_area;
  GtkWidget *vbox;

  GtkWidget *button;

  gtk_init (&argc, &argv);

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_widget_set_name (window, "Test Input");

  vbox = gtk_vbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (window), vbox);
  gtk_widget_show (vbox);

  g_signal_connect (window, "destroy",
                    G_CALLBACK (quit), NULL);

  /* Create the drawing area */

  drawing_area = gtk_drawing_area_new ();
  gtk_widget_set_size_request (GTK_WIDGET (drawing_area), 200, 200);
  gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);

  gtk_widget_show (drawing_area);

  /* Signals used to handle backing pixmap */

  g_signal_connect (drawing_area, "expose-event",
		    G_CALLBACK (expose_event), NULL);
  g_signal_connect (drawing_area,"configure-event",
		    G_CALLBACK (configure_event), folder_name);

  /* Event signals */

  g_signal_connect (drawing_area, "motion-notify-event",
		    G_CALLBACK (motion_notify_event), NULL);
  g_signal_connect (drawing_area, "button-press-event",
		    G_CALLBACK (button_press_event), folder_name);
  g_signal_connect (drawing_area, "button-release-event",
		    G_CALLBACK (button_release_event), NULL);

  //needs to be passed both the drawing_area, and the folder_name, so create a glist and pass a pointer to that
  GList *key_press_data = NULL;
  key_press_data = g_list_append(key_press_data, drawing_area);
  key_press_data = g_list_append(key_press_data, folder_name);

  g_signal_connect (window, "key-press-event",
		    G_CALLBACK (key_press_event), key_press_data);


  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
			 | GDK_LEAVE_NOTIFY_MASK
			 | GDK_BUTTON_PRESS_MASK
			 | GDK_BUTTON_RELEASE_MASK
			 | GDK_POINTER_MOTION_MASK
			 | GDK_POINTER_MOTION_HINT_MASK);

  /* .. And a quit button */
  button = gtk_button_new_with_label ("Quit");
  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);

  g_signal_connect_swapped (button, "clicked",
			    G_CALLBACK (gtk_widget_destroy),
			    window);
  gtk_widget_show (button);

  gtk_widget_show (window);

  gtk_main ();

  return 0;
}
