/*****************************************************************************
 * yahoophshare.c
 *
 * 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.
 *
 * Copyright (C) 2006 Stefan Sikora
 *****************************************************************************/
 
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif

#include <netdb.h>
#include <arpa/inet.h>
#include "gyach.h"
#include "main.h"
#include "yahoochat.h"
#include "util.h"
#include "yahoophshare.h"
#include "sounds.h"
#include "friends.h"
#include "profname.h"
#include "conference.h"
#include "users.h"
#include "jpeglib.h"

enum {
	COL_URI,
	COL_ICON,
	COL_FKEY,
	NUM_COLS
	};

GtkWidget *thumbimage1, *thumbimage2, *thumbimage3, *thumbimage4, *thumbimage5;
GtkWidget *counterlabel;
GtkListStore *picturelist;
GtkTooltips	*tooltips;
GtkWidget *eboxprev;
gint picturecount = 0;
gint pictureposition = 0;
gchar tmp[10];


gchar *itoa(gint value) {
	snprintf((gchar *)&tmp, sizeof(tmp), "%i", value);
	return (gchar *)&tmp;
}


gchar *getpathfromuri(gchar *uri) {
	gchar *new;
	
	if(uri) {
		// find the last of the first slashes (file:///home...)
		new = strstr(uri, "/");
		while(*new == '/') new++;
		return (gchar *)(--new);
	}
	return NULL;
}


gchar *getfilenamefrompath(gchar *path) {
	gchar *new;
	
	if(path) {
		// find the last slash
		new = strrchr(path, '/');
		return (gchar *)(++new);
	}
	return NULL;
}


void set_counterlabel() {
	snprintf((gchar *)&tmp, sizeof(tmp), "%i/%i", pictureposition, picturecount);
	gtk_label_set_text(GTK_LABEL(counterlabel), (gchar *)&tmp);
}


void icon_redraw(gint pos, GtkWidget *image) {
	GtkTreeIter iter;
	GdkPixbuf *pixbuf = NULL;
	
	if(pos>0 && pos<=picturecount) {
		gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(picturelist), &iter,	itoa(pos-1));
		gtk_tree_model_get(GTK_TREE_MODEL(picturelist), &iter, COL_ICON, &pixbuf, -1);
		gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
	}
	else gtk_image_set_from_stock(GTK_IMAGE(image), GTK_STOCK_FILE, GTK_ICON_SIZE_MENU);
}


void icon_redraw_all() {
	icon_redraw(pictureposition-2, thumbimage1);
	icon_redraw(pictureposition-1, thumbimage2);
	icon_redraw(pictureposition, thumbimage3);
	icon_redraw(pictureposition+1, thumbimage4);
	icon_redraw(pictureposition+2, thumbimage5);
	set_counterlabel();
}


// Callback-functions
void on_mainwindow_destroy(GtkWidget *widget, gpointer data) {
	char *who = NULL;
	
	who = g_object_get_data(G_OBJECT(widget), "who");
	ymsg_yphoto_close(ymsg_sess, who);
}


void on_buttonleft_clicked(GtkWidget *widget, gpointer data) {
	pictureposition--;
	if(pictureposition<=0) pictureposition++;
	icon_redraw_all();
}


void on_buttonright_clicked(GtkWidget *widget, gpointer data) {
	pictureposition++;
	if(pictureposition>picturecount) pictureposition = picturecount;
	icon_redraw_all();
}


gboolean on_thumb_clicked(GtkWidget *widget, GdkEventButton *event, gpointer data) {
	GdkPixbuf *pixbuf = NULL;
	GError *error = NULL;
	GtkTreeIter iter;
	gchar *filename;

	if(picturecount>0) {	/* avoid crash */
		gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(picturelist), &iter,	itoa(pictureposition-1));
		gtk_tree_model_get(GTK_TREE_MODEL(picturelist), &iter, COL_URI, &filename, -1);

		pixbuf = gdk_pixbuf_new_from_file_at_size(filename, 200,100, &error);
		if(!error) {
			gtk_image_set_from_pixbuf(GTK_IMAGE(data), pixbuf);
			gtk_tooltips_set_tip(tooltips, eboxprev, getfilenamefrompath(filename), "");
		} else g_error_free(error);
		g_object_unref(pixbuf);
	}
	return TRUE;
}


/* generates a "random" filekey */
void yahoo_yphoto_genfilekey(char *rndcookie) {
    static char possible[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ00";
    int i;

    for(i=0; i<22; i++) rndcookie[i] = possible[(rand() & 0x3f)];
    
    rndcookie[22] = '-';
    rndcookie[23] = '-';
    rndcookie[24] = 0x00;
} /* yahoo_yphoto_genfilekey */


static const char *yphoto_b64s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

/* BASE64-decoder */
int yphoto_b64_decode(char *target, int tlen, const char *source, int slen) {
	const char *inp;
	char *outp;
	char *outend;
	const char *inend;
	int bits=0;
	int working=0;
	char *i;

	if(slen==0) slen = strlen(source);
	outp = target;
	inp = source;
	outend = target+tlen;
	inend = source+slen;
	
	for(;outp<outend && inp<inend;inp++) {
		if ( ((char)*inp)=='\n') continue;

		working <<= 6;
		i = strchr(yphoto_b64s,(char)*inp);
		
		if(i==NULL) return(-1);
		if(*i=='=') { /* pad char */
			if((working&0xFF) != 0) return(-1);
			break;
		}

		bits += 6;
		working |= (i-yphoto_b64s);
		
		if(bits>=8) {
		*(outp++)=(char)((working&(0xFF<<(bits-8)))>>(bits-8));
		bits-=8;
		}
	}

	if(outp == outend) {
		*(--outp)=0;
		return(-1);
	}

	*outp = 0;
	return(outp-target);
} /* yphoto_b64_decode */


/* BASE64-encoder helpfunction */
static int add_char(char *pos, char ch, int done, char *end) {
	if(pos>=end) return(1);

	if(done) *pos = yphoto_b64s[64];
	else *pos = yphoto_b64s[(int)ch];

	return(0);
} /* add_char */


/* BASE64-encoder */
int yphoto_b64_encode(char *target, int tlen, const char *source, int slen)  {
	const char*inp;
	char*outp;
	char*outend;
	const char*inend;
	char*tmpbuf=NULL;
	int done=0;
	char enc;
	int buf=0;

	if(slen==0) slen=strlen(source);
	inp=source;

	if(source==target) {
		tmpbuf = (char *)malloc(tlen);
		if(tmpbuf==NULL) return(-1);
		outp=tmpbuf;
	}
	else outp=target;

	outend = outp+tlen;
	inend = inp+slen;
	
	for(;(inp < inend) && !done;) {
		enc = *(inp++);
		buf = (enc & 0x03)<<4;
		enc = (enc&0xFC)>>2;

		if(add_char(outp++, enc, done, outend)) {
			if(target==source)
			free(tmpbuf);
			return(-1);
		}

		enc = buf|((*inp & 0xF0) >> 4);
		if(add_char(outp++, enc, done, outend))  {
			if(target==source) free(tmpbuf);
			return(-1);
		}

		if(inp==inend) done=1;

		buf = (*(inp++)<<2)&0x3C;
		enc = buf|((*inp & 0xC0)>>6);

		if(add_char(outp++, enc, done, outend))  {
			if(target==source) free(tmpbuf);
			return(-1);
		}

		if(inp==inend) done=1;

		enc = ((int)*(inp++))&0x3F;
		if(add_char(outp++, enc, done, outend))  {
			if(target==source) free(tmpbuf);
			return(-1);
		}
		if(inp==inend) done=1;
	}

	if(outp<outend) *outp = 0;
	if(target==source)  {
		memcpy(target,tmpbuf,tlen);
		free(tmpbuf);
	}
	return(outp-target);
} /* yphoto_b64_encode */


/* create jpeg from preview-pixbuf */
void yahoo_yphoto_genpreview(GdkPixbuf *pixbuf) {
	JSAMPLE *image_buffer;
	struct jpeg_compress_struct cinfo;
	struct jpeg_error_mgr jerr;

	FILE *outfile;
	JSAMPROW row_pointer[1];
	int row_stride;

	image_buffer = (JSAMPLE*)gdk_pixbuf_get_pixels(pixbuf);
	
	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_compress(&cinfo);

	outfile = fopen("/tmp/gyachi_preview.jpg", "wb");
	jpeg_stdio_dest(&cinfo, outfile);
	
	cinfo.image_width = gdk_pixbuf_get_width(pixbuf);
	cinfo.image_height = gdk_pixbuf_get_height(pixbuf);
	cinfo.input_components = 3;
	cinfo.in_color_space = JCS_RGB;
	jpeg_set_defaults(&cinfo);

	jpeg_start_compress(&cinfo, TRUE);
	row_stride = gdk_pixbuf_get_rowstride(pixbuf);

	while(cinfo.next_scanline < cinfo.image_height) {
		row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride];
		jpeg_write_scanlines(&cinfo, row_pointer, 1);
	}

	jpeg_finish_compress(&cinfo);
	
	fclose(outfile);
	jpeg_destroy_compress(&cinfo);
} /* yahoo_yphoto_genpreview */


void on_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y,
							GtkSelectionData *selection_data, guint info, guint32 time,
							gpointer data) {
	GdkPixbuf *pixbuf = NULL;
	gchar **uriarray = NULL;
	gchar **uris;
	gchar *oneuri;
	gchar *path;
	GError *error = NULL;
	GtkTreeIter iter;
	
	char filekey[25];
	char preview[2000];
	char jpgdata[1500];
	int prevlen = 0;
	int jpgdatalen;
	FILE *f;
	struct stat sbuf;
	char *who = NULL;
	
	who = g_object_get_data(G_OBJECT(widget), "who");

	if(selection_data->length > 0) {
		uriarray = gtk_selection_data_get_uris(selection_data);
		if(uriarray) {
			uris = uriarray;
			while((oneuri = *uris) != NULL) {
				path = getpathfromuri(oneuri);
				pixbuf = gdk_pixbuf_new_from_file_at_size(path, 48,48, &error);
				if(!error) {
					yahoo_yphoto_genfilekey((char *)&filekey);
					yahoo_yphoto_genpreview(pixbuf);
					stat("/tmp/gyachi_preview.jpg", &sbuf);			// TODO: Error-Handling, possible buffer-overrun !
					jpgdatalen = (int)sbuf.st_size;
					f=fopen("/tmp/gyachi_preview.jpg", "rb");
					jpgdatalen = fread((char *)&jpgdata, 1, jpgdatalen, f);
					fclose(f);
					prevlen = yphoto_b64_encode((char *)&preview, sizeof(preview), (char *)&jpgdata, jpgdatalen);
					preview[prevlen] = '\0';
					ymsg_yphoto_key(ymsg_sess, who, (char *)&filekey, "0");
					ymsg_yphoto_prev(ymsg_sess, who, (char *)&filekey, getfilenamefrompath(path), (char *)&preview);
					ymsg_yphoto_key(ymsg_sess, who, (char *)&filekey, "1"); 

					gtk_list_store_insert(picturelist, &iter, pictureposition);
					gtk_list_store_set(picturelist, &iter,
									COL_URI, path,
									COL_ICON, pixbuf,
									COL_FKEY, filekey, -1);
					
					pictureposition++;
					picturecount++;
					pixbuf = NULL;
				} else g_error_free(error);
				uris++;
			}
			g_strfreev(uriarray);
			icon_redraw_all();
		}
	}
}


/* Displaying the photosharing-gui */
void yahoo_yphoto_gui(char *who) {
	GtkWidget *mainwindow;
	GtkWidget *hbox, *vbox;
	GtkWidget *previewimage;
	GtkWidget *ebox;
	GtkWidget *frame, *frame2;
	GtkWidget *buttonleft, *buttonright, *buttonsave, *buttonfullscreen;
	char titlebuf[80];
		
	// prepare the window-title
	snprintf(titlebuf, sizeof(titlebuf)-1, "Preview - %s", who);

	// prepare list for pictures
	picturelist = gtk_list_store_new(NUM_COLS, G_TYPE_STRING, G_TYPE_POINTER);

	// create and show the widgets
	mainwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title(GTK_WINDOW(mainwindow), "GYachI Photosharing");
	vbox = gtk_vbox_new(FALSE, 0);
	gtk_container_add(GTK_CONTAINER(mainwindow), vbox);

	frame = gtk_frame_new(titlebuf);
	eboxprev = gtk_event_box_new();	
	previewimage = gtk_image_new();
	gtk_widget_set_size_request(previewimage, 200, 100);
	gtk_container_add(GTK_CONTAINER(frame), eboxprev);
	gtk_container_add(GTK_CONTAINER(eboxprev), previewimage);
	gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);

	hbox = gtk_hbox_new(FALSE, 0);
	frame = gtk_frame_new(NULL);
	thumbimage1 = gtk_image_new();
	gtk_widget_set_size_request(thumbimage1, 48, 48);
	gtk_container_add(GTK_CONTAINER(frame), thumbimage1);
	gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0);

	frame = gtk_frame_new(NULL);
	thumbimage2 = gtk_image_new();
	gtk_widget_set_size_request(thumbimage2, 48, 48);
	gtk_container_add(GTK_CONTAINER(frame), thumbimage2);
	gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0);
	
	frame = gtk_frame_new(NULL);
	frame2 = gtk_frame_new(NULL);
	ebox = gtk_event_box_new();	
	thumbimage3 = gtk_image_new();
	gtk_widget_set_size_request(thumbimage3, 48, 48);
	gtk_container_add(GTK_CONTAINER(frame), frame2);
	gtk_container_add(GTK_CONTAINER(frame2), ebox);
	gtk_container_add(GTK_CONTAINER(ebox), thumbimage3);
	gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 2);
	g_object_set_data(G_OBJECT(ebox), "who", strdup(who));

	frame = gtk_frame_new(NULL);
	thumbimage4 = gtk_image_new();
	gtk_widget_set_size_request(thumbimage4, 48, 48);
	gtk_container_add(GTK_CONTAINER(frame), thumbimage4);
	gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0);

	frame = gtk_frame_new(NULL);
	thumbimage5 = gtk_image_new();
	gtk_widget_set_size_request(thumbimage5, 48, 48);
	gtk_container_add(GTK_CONTAINER(frame), thumbimage5);
	gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);

	gtk_drag_dest_set(ebox, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY);
	gtk_drag_dest_add_uri_targets(ebox);

	hbox = gtk_hbox_new(FALSE, 0);
	buttonleft = gtk_button_new_from_stock(GTK_STOCK_GO_BACK);
	buttonright = gtk_button_new_from_stock(GTK_STOCK_GO_FORWARD);
	buttonsave = gtk_button_new_from_stock(GTK_STOCK_SAVE);
	buttonfullscreen = gtk_button_new_from_stock(GTK_STOCK_ZOOM_IN);
	counterlabel = gtk_label_new(NULL);
	gtk_box_pack_start(GTK_BOX(hbox), buttonleft, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(hbox), buttonright, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(hbox), buttonsave, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(hbox), buttonfullscreen, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(hbox), counterlabel, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);

	tooltips = gtk_tooltips_new();
	gtk_tooltips_enable(tooltips);
	
	icon_redraw_all();
	gtk_widget_show_all(mainwindow);

	g_object_set_data(G_OBJECT(mainwindow), "who", strdup(who));

	// connect signals to callback functions
	g_signal_connect(G_OBJECT(mainwindow), "destroy", G_CALLBACK(on_mainwindow_destroy), NULL);
    g_signal_connect(ebox, "drag_data_received", G_CALLBACK(on_drag_data_received), thumbimage3);
    g_signal_connect(ebox, "button-release-event", G_CALLBACK(on_thumb_clicked), previewimage);
	g_signal_connect(buttonleft, "clicked", G_CALLBACK(on_buttonleft_clicked), NULL);	
	g_signal_connect(buttonright, "clicked", G_CALLBACK(on_buttonright_clicked), NULL);	
} /* yahoo_yphoto_gui */


void on_yphoto_reject(GtkWidget *button, gpointer user_data) {
	GtkWidget *tmp_widget;
	char *who = NULL;
	
	who = g_object_get_data(G_OBJECT(button), "who");
	if (who) {
		ymsg_yphoto_reject(ymsg_sess, who);
		free(who);
	}
	tmp_widget = g_object_get_data(G_OBJECT(button), "mywindow");
	if (tmp_widget) gtk_widget_destroy(tmp_widget);
}


void on_yphoto_accept(GtkWidget *button, gpointer user_data) {
	GtkWidget *tmp_widget;
	char *who = NULL;
	
	who = g_object_get_data(G_OBJECT(button), "who");
	if (who) {
		ymsg_yphoto_reject(ymsg_sess, who); 	// until everything works ;-)
//		ymsg_yphoto_accept(ymsg_sess, who);
//		yahoo_yphoto_gui(who);
		free(who);
	}
	tmp_widget = g_object_get_data(G_OBJECT(button), "mywindow");
	if (tmp_widget) gtk_widget_destroy(tmp_widget);
}


/* handles incoming photosharing-session */
void yahoo_yphoto_offer_msg(char *who)
{
	char buff[512];
	GtkWidget *okbutton=NULL;
	GtkWidget *cbutton=NULL;

	//TODO: looking for options (pm's off: photosharing off)
	
	snprintf(buff, sizeof(buff)-1, _("The Yahoo user <b>%s</b> wants to share photos.\n\nDo you want to accept?\nTHIS FEATURE IS NOT IMPLEMENTED IN GYACHI!"), who);

	okbutton = show_confirm_dialog_config(buff, _("Yes"), _("No"), 0);
	if(!okbutton) {
		ymsg_yphoto_reject(ymsg_sess, who); 
		return;
	}
	g_signal_connect(G_OBJECT(okbutton), "clicked", G_CALLBACK(on_yphoto_accept), NULL);
    g_object_set_data(G_OBJECT(okbutton), "who", strdup(who));

    cbutton = g_object_get_data(G_OBJECT(okbutton), "cancel");
    if(cbutton) {
        g_signal_connect(G_OBJECT(cbutton), "clicked", G_CALLBACK(on_yphoto_reject), NULL);
		g_object_set_data(G_OBJECT(cbutton), "who", strdup(who));
    }
    play_sound_event(SOUND_EVENT_OTHER);
} /* yahoo_yphoto_offer */


/* sends invitation for a photosharing-session */
void yahoo_yphoto_invite(char *who) {
//	ymsg_yphoto_invite(ymsg_sess, who);
} /* yahoo_yphoto_invite */


/* handles declining of session */
void yahoo_yphoto_decline_msg(char *who) {
	char url[1024];
	
	snprintf(url, 1024, _("%s has declined photosharing-session"), who);
	show_ok_dialog(url);
}


/* buddy accepted invitation */
void yahoo_yphoto_accept_msg(char *who) {
	yahoo_yphoto_gui(who);	
}


/* handles closing of session */
void yahoo_yphoto_closed_msg(char *who) {
	char url[1024];
	
	snprintf(url, 1024, _("%s has closed photosharing-session"), who);
	show_ok_dialog(url);
}

//TODO:
// better encapsulating of variables -> multiple photosharing-sessions!
// photo-sharing-services 215/216/218 (filetransfers)
// handling of cancel-msg
// save/full-buttons in gui
// file filter (jpg, gif, png, etc. target: image)
// logging and information in mainchat-window

