/*	WebDownloader for X-Window
 *	Copyright (C) 1999-2002 Koshelev Maxim
 *	This Program is free but not GPL!!! You can't modify it
 *	without agreement with author. You can't distribute modified
 *	program but you can distribute unmodified program.
 *
 *	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.
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include "mainlog.h"
#include "var.h"
#include "face/colors.h"
#include "face/list.h"
#include "face/prefs.h"
#include "locstr.h"
#include "face/lmenu.h"
#include "face/log.h"
#include "ntlocale.h"
#include "main.h"

static gint list_menu_open_row_main_log(GtkWidget *widget, tMLog *Log) {
	Log->open_selected_row();
	return TRUE;
};

static gint list_menu_clear_main_log(GtkWidget *widget, tMLog *Log) {
	Log->done();
	return TRUE;
};

static gint list_menu_open_properties(GtkWidget *widget, tMLog *Log){
	d4x_prefs_init_page(PREFS_PAGE_MAINLOG);
	return TRUE;
};

int main_log_event_handler2(GtkWidget *widget,GdkEventButton *event,tMLog *log) {
	return log->popup(event);
};

tMLog::tMLog():tStringList(){
	start=time(NULL);
	list=NULL;
	string=NULL;
	current_line=0;
	fd=0;
};

void tMLog::reinit(int a) {
	MaxNum=a;
};

static void _ml_clist_addr_destroy_(d4x::URL *addr){
	if (addr) delete(addr);
};

void tMLog::add_to_list() {
	current_line+=1;
	tLogString *str=(tLogString *)Last;
	char *color;
	char str_type;
	switch (str->type & (LOG_DETAILED-1)) {
		case LOG_OK:{
				color="black";
				str_type='+';
				break;
			};
		case LOG_FROM_SERVER:
			{
				color="blue";
				str_type='-';
				break;
			};
		case LOG_WARNING:
			{
				str_type='?';
				color="darkgreen";
				break;
			};
		case LOG_ERROR:
			{
				str_type='!';
				color="red";
				break;
			};
		default:
			str_type=' ';
			color="black";
	};
	struct tm msgtime;
	localtime_r(&(str->time),&msgtime);
	char useful[MAX_LEN];
	strftime(useful,MAX_LEN,"%T",&msgtime);
	char tmpdate[MAX_LEN];
	strftime(tmpdate,MAX_LEN,"%d %b %Y",&msgtime);
	GtkTreeIter iter;
	if (list){
		char *date_utf=g_convert(tmpdate,-1,"UTF-8",LOCALE_CODEPAGE,NULL,NULL,NULL);
		GtkListStore *store=(GtkListStore *)gtk_tree_view_get_model(list);
		gtk_list_store_append(store, &iter);
		gtk_list_store_set(store, &iter,
				   ML_COL_NUM, current_line,
				   ML_COL_TIME, useful,
				   ML_COL_DATE, date_utf?date_utf:tmpdate,
				   ML_COL_STRING, str->body,
				   ML_COL_LAST, color,
				   -1);
		if (date_utf) g_free(date_utf);
/*FIXME: GTK2
			gtk_clist_set_row_data_full(list,row,addr,
						    GtkDestroyNotify(_ml_clist_addr_destroy_));
*/
	};
	strftime(useful,MAX_LEN,"%T %d %b %Y ",&msgtime);
	if (CFG.WITHOUT_FACE){
		if (str->type==LOG_ERROR){
			if (CFG.COLORIFIED_OUTPUT) printf("%c[31;40;1m",27); //red
			printf("%c %s %s\n",str_type,useful,str->body);
		}else{
			if (CFG.COLORIFIED_OUTPUT) printf("%c[35;40m",27);   //magenta
			printf("%c ",str_type);
			if (CFG.COLORIFIED_OUTPUT) printf("%c[34;40;1m",27); //blue
			g_print("%s ",useful);
			if (CFG.COLORIFIED_OUTPUT) printf("%c[32;40;1m",27);
			g_print("%s\n",str->body);
		};
	};
	if (fd) {
		if (CFG.MAIN_LOG_FILE_LIMIT){
			struct stat finfo;
			fstat(fd,&finfo);
			if (finfo.st_size>(CFG.MAIN_LOG_FILE_LIMIT*1024)){
				ftruncate(fd,0);
				lseek(fd,0,SEEK_SET);
				add(_("Limitation for size of file of mainlog reached! File have been truncated."),LOG_ERROR);
			};
		};
		if (write(fd,&str_type,sizeof(str_type))<0 ||
		    write(fd,useful,strlen(useful))<0 ||
		    write(fd,str->body,strlen(str->body))<0 ||
		    write(fd,"\n",strlen("\n"))<0) {
			close(fd);
			fd=0;
			add(_("Can't write to file interrupting write to file"),LOG_ERROR);
		};
	};
};

void tMLog::print() {
	if (!list) return;
	tLogString *prom=(tLogString *)First;
	while (prom) {
		prom=(tLogString *)prom->prev;
	};
};

void tMLog::add(char *str,int len,int type) {
	DBC_RETURN_IF_FAIL(str!=NULL);
	if ((type & LOG_DETAILED)  && !CFG.MAIN_LOG_DETAILED) return;
	tLogString *temp=new tLogString(str,len,type);
	temp->time=time(NULL);
	insert(temp);
	add_to_list();
	Size+=len;
};

void tMLog::add(char *str,int type) {
	DBC_RETURN_IF_FAIL(str!=NULL);
	if ((type & LOG_DETAILED)  && !CFG.MAIN_LOG_DETAILED) return;	
	int len=strlen(str);
	tLogString *ins=new tLogString(str,len,type);
	insert(ins);
	add_to_list();
	Size+=len;
};

void tMLog::init_list(GtkTreeView *clist) {
	list=clist;
	if (list==NULL) return;
	g_signal_connect(G_OBJECT(list),"event",G_CALLBACK(main_log_event_handler2),this);
	/* Initing popup menu
	 */
	popup_menu=gtk_menu_new();
	open_row_item=gtk_menu_item_new_with_label(_("Open a row"));
	gtk_menu_shell_append(GTK_MENU_SHELL(popup_menu),open_row_item);
	g_signal_connect(G_OBJECT(open_row_item),"activate",G_CALLBACK(list_menu_open_row_main_log),this);
	clear_item=gtk_menu_item_new_with_label(_("Clear log"));
	gtk_menu_shell_append(GTK_MENU_SHELL(popup_menu),clear_item);
	g_signal_connect(G_OBJECT(clear_item),"activate",G_CALLBACK(list_menu_clear_main_log),this);
	GtkWidget *item=gtk_menu_item_new_with_label(_("Properties"));
	gtk_menu_shell_append(GTK_MENU_SHELL(popup_menu),item);
	g_signal_connect(G_OBJECT(item),"activate",G_CALLBACK(list_menu_open_properties),this);
	gtk_widget_show_all(popup_menu);
};

int tMLog::popup(GdkEventButton *event) {
	if (!list) return FALSE;
	GtkTreeSelection *sel=gtk_tree_view_get_selection(list);
	GtkTreePath *path=NULL;
	if (event && event->type==GDK_BUTTON_PRESS && event->button==3) {
		gtk_tree_selection_unselect_all(sel);
		int selected=0;
		if (gtk_tree_view_get_path_at_pos(list,gint(event->x),gint(event->y),&path,NULL,NULL,NULL)){
			selected=1;
			gtk_tree_selection_select_path(sel,path);
			gtk_tree_path_free(path);
		};
		if (selected)
			gtk_widget_set_sensitive(open_row_item,TRUE);
		else
			gtk_widget_set_sensitive(open_row_item,FALSE);
		if (Num>0)
			gtk_widget_set_sensitive(clear_item,TRUE);
		else
			gtk_widget_set_sensitive(clear_item,FALSE);
		gtk_menu_popup(GTK_MENU(popup_menu),NULL,NULL,NULL,NULL,event->button,event->time);
		return TRUE;
	};
	if (event && event->type==GDK_2BUTTON_PRESS && event->button==1){
		if (gtk_tree_view_get_path_at_pos(list,gint(event->x),gint(event->y),&path,NULL,NULL,NULL)){
			gtk_tree_selection_select_path(sel,path);
			GtkTreeIter iter;
			GtkTreeModel *model=gtk_tree_view_get_model(list);
			gtk_tree_model_get_iter(model,&iter,path);
			gtk_tree_path_free(path);
			open_row(&iter);
		};
		return TRUE;
	};
	return FALSE;
};

void tMLog::real_open_row(GtkTreeIter *iter){
	char data[MAX_LEN];
	char *text;
	int num=0;
// FIXME GTK2
	GValue val={0,};
	GtkTreeModel *model=gtk_tree_view_get_model(list);
	gtk_tree_model_get_value(model,iter,ML_COL_NUM,&val);
	num=g_value_get_int(&val);
	g_value_unset(&val);
	sprintf(data,_("row number %i of main log"),num);
	gtk_tree_model_get_value(model,iter,ML_COL_STRING,&val);
	text=(char*)g_value_get_string(&val);
	if (!string)
		string=new tStringDialog;
	string->init(text,data);
	g_value_unset(&val);
};

void tMLog::open_row(GtkTreeIter *iter) {
	if (!list) return;
/*
	tAddr *addr=(tAddr *)gtk_clist_get_row_data(list,row);
	tDownload *dwn;
	if (addr  && (dwn=_aa_.find_url(addr))){
		log_window_init(dwn);
		D4X_QVT->move_to(dwn);
	}else{
*/
		real_open_row(iter);
//	};
};

void tMLog::open_selected_row() {
	if (!list) return;
	GtkTreeSelection *sel=gtk_tree_view_get_selection(list);
	GtkTreeIter iter;
	if (gtk_tree_selection_get_selected(sel,NULL,&iter)){
		real_open_row(&iter);
	};
};

void tMLog::reinit_file() {
	if (fd) {
		close(fd);
		fd=0;
	};
	if (CFG.SAVE_MAIN_LOG && CFG.SAVE_LOG_PATH) {
		if (CFG.APPEND_REWRITE_LOG) {
			fd=open(CFG.SAVE_LOG_PATH,O_WRONLY|O_CREAT,S_IRUSR | S_IWUSR );
			lseek(fd,0,SEEK_END);
		} else
			fd=open(CFG.SAVE_LOG_PATH,O_TRUNC | O_CREAT |O_RDWR,S_IRUSR | S_IWUSR);
		if (fd<0) {
			add(_("Can't open file for saving log"),LOG_ERROR);
			fd=0;
		};
	};
};

void tMLog::add(char *str) {
	DBC_RETURN_IF_FAIL(str!=NULL);
	int len=strlen(str);
	tLogString *ins=new tLogString(str,len,LOG_FROM_SERVER);
	insert(ins);
	add_to_list();
	Size+=len;
};

void tMLog::myprintf(int type,char *fmt,...){
	DBC_RETURN_IF_FAIL(fmt!=NULL);

	char str[MAX_LEN+1];
	char *cur=str;
	va_list ap;
	va_start(ap,fmt);
	last_error.clear();
	*cur=0;
	while (*fmt && cur-str<MAX_LEN){
		if (*fmt=='%'){
			fmt+=1;
			switch(*fmt){
			case 's':{
				char *s=va_arg(ap,char *);
				if (s)
					g_snprintf(cur,MAX_LEN-(cur-str),"%s",s);
				else
					g_snprintf(cur,MAX_LEN-(cur-str),"%s","NULL");
				break;
			};
			case 'z':{
				tDownload *temp=va_arg(ap,tDownload *);
				if (temp){
					g_snprintf(cur,MAX_LEN-(cur-str),"%s",std::string(temp->info).c_str());
					last_error=temp->info;
				}else{
					g_snprintf(cur,MAX_LEN-(cur-str),"%s","NULL");
				};
				break;
			};
			case 'i':{
				g_snprintf(cur,MAX_LEN-(cur-str),"%i",va_arg(ap,int));
				break;
			};
			case 'l':{
				switch(*(fmt+1)){
				case 'u':{
					fmt+=1;
					g_snprintf(cur,MAX_LEN-(cur-str),"%lu",va_arg(ap,unsigned long));
					break;
				};
				case 'i':{
					fmt+=1;
					g_snprintf(cur,MAX_LEN-(cur-str),"%li",va_arg(ap,long));
					break;
				};
				};
				break;
			};
			default:{
				*cur=*fmt;
				cur+=1;
				*cur=0;			       
			};
			};
			if (*fmt==0) break;
			while(*cur) cur+=1;
		}else{
			*cur=*fmt;
			cur+=1;
			*cur=0;
		};
		fmt+=1;
	};
	va_end(ap);
	add(str,type);
};

void tMLog::dispose() {
	if (list){
		GtkTreeIter iter;
		GtkListStore *store=(GtkListStore *)gtk_tree_view_get_model(list);
		gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store),&iter);
		gtk_list_store_remove(store,&iter);
	};
	tStringList::dispose();
};

tLogString *tMLog::last() {
	return (tLogString *)tStringList::last();
};

tLogString *tMLog::next() {
	return (tLogString *)tStringList::next();
};

tLogString *tMLog::first() {
	return (tLogString *)tStringList::first();
};

void tMLog::done(){
	tStringList::done();
};

tMLog::~tMLog() {
	done();
	if (string) delete(string);
};


syntax highlighted by Code2HTML, v. 0.9.1