/*  frontend.c - The frontend to Gqcam, a GTK based QuickPict clone.
    Copyright (C) 1999 Cory Lueninghoener (cluenin1@bigred.unl.edu)

    This software contains ideas and modified parts from qcread, 
    written by Alex Belits.
    Copyright (C) 1996, 1997 Alex Belits

    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 <gtk/gtk.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <linux/types.h> 
#include <errno.h>

#include "save.h"
#include "frontend.h"

int dev;
int bytes_per_rgb;
struct video_window vid_win;
struct video_capability vid_caps;
struct video_picture vid_pic;
GtkWidget *drawing_area;
static GdkPixmap *pixmap = NULL;
unsigned char pic[MAX_RGBA_IMAGE_SIZE];
int frozen;
guint timeoutid;

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

static gint
configure_event (GtkWidget *widget, GdkEventConfigure *event)
{
  if (pixmap)
    gdk_pixmap_unref(pixmap);

  pixmap = gdk_pixmap_new(widget->window,
			  widget->allocation.width,
			  widget->allocation.height,
			  -1);
  gdk_draw_rectangle (pixmap,
		      widget->style->white_gc,
		      TRUE,
		      0, 0,
		      widget->allocation.width,
		      widget->allocation.height);

  return TRUE;
}

static gint
expose_event (GtkWidget *widget, GdkEventExpose *event)
{
  gdk_draw_pixmap(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;
}

gint grab (gpointer data)
{
  GdkDrawable *drawable;
  int len, height, width, ls=0, x, y, i, count=0, xpos, ypos;
  GdkRectangle update_rec;
  static int lasttime = 0;
  static int framecount = 0;
  static float rate;
  static int size = 0;
  int thetime;
  static double diff = 1.;

  if ( lasttime == 0 ) 
    lasttime = time(NULL);
  
  thetime = time(NULL);
  
  if ( ( thetime - lasttime ) > (int)diff-1 ) {
    rate = ((float)(framecount)) / diff;
    printf("%3.3f fps\n", rate);
    framecount = 0;
    lasttime = thetime;
    size = 0;
  };
  
  framecount++;
		
  drawable = drawing_area->window;

/*  ioctl (dev, VIDIOCGCAP, &vid_caps);*/
  height = vid_caps.maxheight;
  width = vid_caps.maxwidth;

  errno = 0;
  while( (len = read (dev, pic, MAX_RGBA_IMAGE_SIZE)) <= 0 ) {
    if(errno!=0 && errno!=EINTR) {
      perror("Error read image\n");
      return(FALSE);
    }
  }
  size+=len;

  update_rec.x = 0;
  update_rec.y = 0;
  update_rec.width = 352;
  update_rec.height = 288;
  gdk_draw_rgb_image (pixmap, drawing_area->style->white_gc,
		      vid_win.x, vid_win.y, vid_win.width, vid_win.height,
		      GDK_RGB_DITHER_NONE, pic, vid_win.width*bytes_per_rgb);
  gtk_widget_draw (drawing_area, &update_rec);

  return (TRUE);
}

void clearimg()
{
  GdkRectangle update_rec;

  configure_event(GTK_WIDGET (drawing_area), NULL);

  update_rec.x = 0;
  update_rec.y = 0;
  update_rec.width = 352;
  update_rec.height = 288;
  gtk_widget_draw (drawing_area, &update_rec);
  return;
}


void freeze(GtkWidget *widget, GdkEvent  *event, gpointer   data)
{
  if (GTK_TOGGLE_BUTTON (widget)->active)
    {
      gtk_timeout_remove(timeoutid);
      frozen=1;
      
    } else {
      timeoutid = gtk_idle_add (grab, (gpointer) data);
      frozen=0;
    } 
} 


void setbrightness(GtkAdjustment *adj, GtkWidget *none)
{
  vid_pic.brightness = (adj->value)*256;
  if (ioctl (dev, VIDIOCSPICT, &vid_pic) == -1) {
    perror ("ioctl (VIDIOCSPICT)");
    return;
  }
}

void setcolor(GtkAdjustment *adj, GtkWidget *none)
{
  vid_pic.colour = (adj->value)*256;
  if (ioctl (dev, VIDIOCSPICT, &vid_pic) == -1) {
    perror ("ioctl (VIDIOCSPICT)");
    return;
  }
}

void setcontrast(GtkAdjustment *adj, GtkWidget *none)
{
  vid_pic.contrast = (adj->value)*256;
  if (ioctl (dev, VIDIOCSPICT, &vid_pic) == -1) {
    perror ("ioctl (VIDIOCSPICT)");
    return;
  }
}

void setsize_cif( GtkWidget *widget, GdkEvent  *event, gpointer   data )
{
  vid_win.x=0;
  vid_win.y=0;
  vid_win.width=352;
  vid_win.height=288;
  if (ioctl (dev, VIDIOCSWIN, &vid_win) == -1) {
    perror ("ioctl (VIDIOCSWIN)");
    return;
  }
  clearimg();
  return;
}
void setsize_qcif( GtkWidget *widget, GdkEvent  *event, gpointer   data )
{
  vid_win.x=88;
  vid_win.y=48;
  vid_win.width=176;
  vid_win.height=144;
  if (ioctl (dev, VIDIOCSWIN, &vid_win) == -1) {
    perror ("ioctl (VIDIOCSWIN)");
    return;
  }
  clearimg();
  return; 
}

void savecancel(GtkWidget *widget, GdkEvent *event, gpointer data)
{
  gtk_widget_destroy(GTK_WIDGET(widget));
  if (!frozen)
    timeoutid = gtk_idle_add (grab, (gpointer) data);
  return;
}

void saveok(GtkWidget *widget, GdkEvent *event, gpointer data)
{
  int ls=0, x, y;
  int i;
  int lines, pixels_per_line;
  FILE *outfile;
  unsigned char buff[3];

  outfile = fopen(gtk_file_selection_get_filename(GTK_FILE_SELECTION (widget)), "w");
/*
  fprintf (outfile, "P3\n%d %d\n%d\n", vid_win.width, vid_win.height, 255);
  for (x = 0; x < vid_win.width; x++) {
    for (y = 0; y < vid_win.height; y++) {
      fprintf (outfile, "%03d %03d %03d  ", pic[0], pic[0], pic[0]);
      pic += 1;
      if (ls++ > 4) {
	fprintf (outfile, "\n");
	ls = 0;
      }
    }
  }
*/  
/*
  fprintf (outfile, "P6\n%d %d\n%d\n", vid_win.width, vid_win.height, 255);
  for (x = 0; x < vid_win.width * vid_win.height; x++) {
    buff[0] = pic[2];
    buff[1] = pic[1];
    buff[2] = pic[0];
    fwrite (buff, 1, 3, outfile);
    pic += 1;
  }
*/

  fprintf (outfile, "P6\n%d %d\n%d\n", vid_win.width, vid_win.height, 255);
  for (i = 0; i < 352*288; i++){
    buff[0] = pic[i];
    buff[1] = pic[i];
    buff[2] = pic[i];
    fwrite (buff, 1, 3, outfile);
  }
  


  /*
  lines = vid_win.height;
  pixels_per_line = vid_win.width;
  fprintf(stdout,"P5\n");
  fprintf(stdout,"%d %d\n", pixels_per_line, lines);
  fprintf(stdout,"%d\n",(vid_pic.depth==4)?15:63);

  for (i = 0; i < pixels_per_line * lines; i++) {
    printf("%c", pic[i]);
    fputc(pic[i],stdout);
  }
*/

  fclose(outfile);
  gtk_widget_destroy(GTK_WIDGET(widget));
  if (!frozen)
    timeoutid = gtk_timeout_add (TIMEOUT_LEN, grab, (gpointer) data);
  return;
}

void snap(GtkWidget *widget, GdkEvent *event, gpointer data)
{
  GtkWidget *savedialog;
  if (!frozen)
    gtk_timeout_remove(timeoutid);
  savedialog = gtk_file_selection_new("Save Image");
  gtk_widget_show(savedialog);
  gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (savedialog)->cancel_button), "clicked", (GtkSignalFunc) savecancel, GTK_OBJECT (savedialog));

  gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION (savedialog)->ok_button), "clicked", (GtkSignalFunc) saveok, GTK_OBJECT (savedialog));

  return;
}

int main( int   argc, char *argv[] )
{
  GtkWidget *window;
  GtkWidget *topbox;
  GtkWidget *outerbox;
  GtkWidget *innerbox;
  GtkWidget *scalebox;
  GtkWidget *sizedepthbox;
  GtkWidget *targetbox;
  GtkWidget *frame;
  GtkObject *adjb;
  GtkWidget *scaleb;
  GtkObject *adjw;
  GtkWidget *scalew;
  GtkObject *adjc;
  GtkWidget *scalec;
  GtkWidget *radiobutton;
  GSList *radiogroup;
  GtkWidget *button;
  GdkDrawable *drawable;
  guchar *gbuff;
  GdkColor c;
  int ib=130, ic=30, iw=150, i, count=32;

  gtk_set_locale();
  gtk_init (&argc, &argv);
  gdk_rgb_init();

  dev = open ("/dev/video", O_RDWR);
  if (dev < 0) {
	  perror("/dev/video");
	  exit(1);
  }

  ioctl (dev, VIDIOCGCAP, &vid_caps);
  ioctl (dev, VIDIOCGWIN, &vid_win);
  ioctl (dev, VIDIOCGPICT, &vid_pic);

  ib = (vid_pic.brightness)/256;
  ic = (vid_pic.contrast)/256;
  iw = (vid_pic.colour)/256;

  /* this is what gdk_draw_rgb_image expects */
  vid_pic.palette = VIDEO_PALETTE_RGB24;
  bytes_per_rgb = 3;
  vid_pic.depth = 24;
  if(ioctl (dev, VIDIOCSPICT, &vid_pic)) {
    perror("wrong palette/depth");
    exit( 1 );
  }

  /* set initial video window size */
#if 0
  vid_win.x=88;
  vid_win.y=48;
  vid_win.width=176;
  vid_win.height=144;
  if (ioctl (dev, VIDIOCSWIN, &vid_win) == -1) {
    perror ("ioctl (VIDIOCSWIN)");
    exit( 1 );
  }
#else
  vid_win.x=0;
  vid_win.y=0;
  vid_win.width=352;
  vid_win.height=288;
  if (ioctl (dev, VIDIOCSWIN, &vid_win) == -1) {
    perror ("ioctl (VIDIOCSWIN)");
    exit( 1 );
  }
#endif
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW (window), "Gqcam");

  gtk_signal_connect (GTK_OBJECT (window), "delete_event",
		      GTK_SIGNAL_FUNC (delete_event), NULL);
  
  gtk_container_set_border_width (GTK_CONTAINER (window), 2);

  /* Create topbox */
  topbox = gtk_vbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (window), topbox);

  /* Create the drawing area */
  frame = gtk_frame_new(NULL);
  gtk_box_pack_start (GTK_BOX(topbox), frame, TRUE, TRUE, 0);
  gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
  gtk_widget_show(frame);

  drawing_area = gtk_drawing_area_new ();
  gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 352, 288);
/*  gtk_box_pack_start (GTK_BOX (topbox), drawing_area, TRUE, TRUE, 0);*/
  gtk_container_add(GTK_CONTAINER(frame), drawing_area);
  gtk_widget_show (drawing_area);

/*------ bp -------*/

  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
		      (GtkSignalFunc) expose_event, NULL);
  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
		      (GtkSignalFunc) configure_event, NULL);

/*-----------------*/

  /* Create new outerbox */
  outerbox = gtk_hbox_new (FALSE, 0);
  gtk_box_pack_start (GTK_BOX (topbox), outerbox, TRUE, TRUE, 0);

  /* Create scalebox */
  scalebox = gtk_vbox_new (FALSE, 2);
  gtk_widget_set_usize (GTK_WIDGET(scalebox), 200, 150);
  gtk_box_pack_start( GTK_BOX (outerbox), scalebox, 1, 1, 0);
  gtk_widget_show (scalebox);

  /* Create Brightness Scale */
  frame = gtk_frame_new("Brightness");
  gtk_box_pack_start( GTK_BOX (scalebox), frame, 1, 1, 0);
  gtk_widget_show (frame);

  adjb = gtk_adjustment_new( ib, 0, 255, 1, 10, 1);
  scaleb = gtk_hscale_new(GTK_ADJUSTMENT(adjb));
  gtk_signal_connect (GTK_OBJECT (adjb), "value_changed",
		      GTK_SIGNAL_FUNC (setbrightness), NULL);
  gtk_scale_set_digits(GTK_SCALE(scaleb), 0);
  gtk_container_add (GTK_CONTAINER (frame), scaleb);
  gtk_widget_show (scaleb);
  
  /* Create Color Scale */
  frame = gtk_frame_new("Color");
  gtk_box_pack_start( GTK_BOX (scalebox), frame, 1, 1, 0);
  gtk_widget_show (frame);
  adjw = gtk_adjustment_new( iw, 0, 255, 1, 10, 1);
  scalew = gtk_hscale_new(GTK_ADJUSTMENT(adjw));
  gtk_signal_connect (GTK_OBJECT (adjw), "value_changed",
		      GTK_SIGNAL_FUNC (setcolor), NULL);
  gtk_scale_set_digits(GTK_SCALE(scalew), 0);
  gtk_container_add (GTK_CONTAINER (frame), scalew);
  gtk_widget_show (scalew);

  /* Create Contrast Scale */
  frame = gtk_frame_new("Contrast");
  gtk_box_pack_start( GTK_BOX (scalebox), frame, 1, 1, 0);
  gtk_widget_show (frame);

  adjc = gtk_adjustment_new( ic, 0, 255, 1, 10, 1);
  scalec = gtk_hscale_new(GTK_ADJUSTMENT(adjc));
  gtk_signal_connect (GTK_OBJECT (adjc), "value_changed",
		      GTK_SIGNAL_FUNC (setcontrast), NULL);
  gtk_scale_set_digits(GTK_SCALE(scalec), 0);
  gtk_container_add (GTK_CONTAINER (frame), scalec);
  gtk_widget_show (scalec);

  /* Create sizedepthbox */
  sizedepthbox = gtk_vbox_new (FALSE, 0);
  gtk_box_pack_start( GTK_BOX (outerbox), sizedepthbox, 1, 1, 0);
  gtk_widget_show (sizedepthbox);

  /* This is the size... */
  frame = gtk_frame_new("Size");
  gtk_box_pack_start( GTK_BOX (sizedepthbox), frame, 1, 1, 0);
  gtk_widget_show (frame);

  innerbox = gtk_vbox_new (TRUE, 0);
  gtk_container_add (GTK_CONTAINER (frame), innerbox);
  gtk_widget_show (innerbox);

  radiobutton = gtk_radio_button_new_with_label (NULL, "CIF");
  gtk_box_pack_start (GTK_BOX (innerbox), radiobutton, TRUE, TRUE, 0);
  if (vid_win.width == 352)
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radiobutton), TRUE);
  gtk_signal_connect_object (GTK_OBJECT (radiobutton), "pressed", GTK_SIGNAL_FUNC(setsize_cif), NULL);
  gtk_widget_show (radiobutton);
  
  radiogroup = gtk_radio_button_group (GTK_RADIO_BUTTON (radiobutton));
  radiobutton = gtk_radio_button_new_with_label(radiogroup, "QCIF");
  gtk_box_pack_start (GTK_BOX (innerbox), radiobutton, TRUE, TRUE, 0);
  if (vid_win.width == 176)
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radiobutton), TRUE);
  gtk_widget_show (radiobutton);
  gtk_signal_connect_object (GTK_OBJECT (radiobutton), "pressed", GTK_SIGNAL_FUNC(setsize_qcif), NULL);
  
  /* Create a couple buttons */
  innerbox = gtk_hbox_new (TRUE, 0);
  gtk_box_pack_start( GTK_BOX (topbox), innerbox, 1, 1, 0);
  gtk_widget_show (innerbox);

  button = gtk_button_new_with_label ("Snap Picture");
  gtk_box_pack_start( GTK_BOX (innerbox), button, 1, 1, 0);
  gtk_widget_show(button);
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
		      GTK_SIGNAL_FUNC (save_dialog), NULL);

  button = gtk_toggle_button_new_with_label ("Freeze Picture");
  gtk_box_pack_start( GTK_BOX (innerbox), button, 1, 1, 0);
  gtk_widget_show(button);
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
		      GTK_SIGNAL_FUNC (freeze), NULL);

  button = gtk_button_new_with_label ("Quit");
  gtk_box_pack_start( GTK_BOX (innerbox), button, 1, 1, 0);
  gtk_widget_show(button);
  gtk_signal_connect (GTK_OBJECT (button), "clicked",
		      GTK_SIGNAL_FUNC (delete_event), NULL);

  gtk_widget_show (outerbox);
  gtk_widget_show (topbox);
  gtk_widget_show (window);


  timeoutid =  gtk_idle_add (grab, (gpointer) drawing_area);
  frozen = 0;

  gtk_main ();
  
  return 0;
}
