/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include <Xm/Xm.h>
#include <Xm/List.h>
#include <mars.h>
#include <sys/types.h>
#include <sys/time.h>
#include <dirent.h>
#include <sys/stat.h>
#include <xec.h>

svc *s;

typedef struct article {
	struct article *next;
	char   *title;
	char   *note;
	char   *examples;
	time_t  date;
	boolean seen;
	boolean mail;
} article;

extern Widget top,article_list,article_text,form,delete_button,save_button;

XtAppContext app_context;
Display      *display;

article      *news    = NULL;
article      *current = NULL;

struct  {
	int  mode;
	char id[80];
	char subject[80];
	char from[80];
	char date[80];
	char *msgtmp;
	char *tartmp;
} mailbuf = {
	0,};

void load_seen(void)
{
}

FILE *tarfile,*msgfile,*nulfile;
extern FILE *mailout,*mailin;

void scan_mail(int mode)
{
	char *mail = getenv("MAIL");

	mailbuf.mode = mode;
	mailout = nulfile = fopen("/dev/null","w");

	if(!nulfile)
	{
		marslog(LOG_EROR|LOG_PERR,"Canot open /dev/null");
		return;
	}

	mailin  = fopen(mail,"r");
	if(!mailin)
	{
		fclose(nulfile);
		marslog(LOG_EROR|LOG_PERR,"Canot open mailbox %s",mail);
		return;
	}

	maillex();

	fclose(mailin);
	fclose(nulfile);
}

void load_mail(article *a)
{
	strcpy(mailbuf.id,a->examples);
	scan_mail(1);
	a->note     = strcache(mailbuf.msgtmp);
	a->examples = strcache(mailbuf.tartmp);
}

boolean was_seen(article *a)
{
	return false;
}

void mark_seen(article *a)
{
}

void created(const char *name,const char *kind)
{
	request *u = empty_request("STATUS");
	set_value(u,"NAME",   *name == '/' ? "%s" : "/%s", name);
	set_value(u,"CLASS",  "%s", kind);
	set_value(u,"STATUS", "CREATED");
	send_message(s,u);
	free_all_requests(u);
}

void copyicon(char *a,char *b)
{
	FILE *g = fopen(b,"w");
	request *r = read_request_file(a);
	if(r == NULL)
	{
		r=empty_request("NOTE");
		set_value(r,"ICON_CLASS","NOTE");
	}
	set_value(r,"X","0");
	set_value(r,"Y","0");
	if(g) {
		save_all_requests(g,r);
		fclose(g);
	}
	free_all_requests(r);
}

void browse_callback (Widget w, XtPointer cd, XmListCallbackStruct *cb )
{
	char *p = xec_GetString(cb->item);
	article *a = news;

	while(a)
	{
		if(strcmp(p,a->title) == 0)
		{
			if(a->mail && !a->note) load_mail(a);
			current = a;
			xec_LoadText(article_text,a->note,0);
			/* XtSetSensitive(delete_button,True); */
			XtSetSensitive(save_button,a->examples != NULL);
		}
		a = a->next;
	}

	XtFree(p);

}

boolean isdir(char *p)
{
	struct stat s;
	if(stat(p,&s)<0) return false;
	return (S_ISDIR(s.st_mode) != 0);
}

void delete_callback (Widget w, XtPointer cd, XmAnyCallbackStruct *cb )
{
	if(current)
	{
		xec_RemoveListItem(article_list,current->title);
		XtSetSensitive(save_button,False);
		XtSetSensitive(delete_button,False);
		XmTextSetString(article_text,NULL);
		mark_seen(current);
	}
	current = NULL;
}

void copy(char *p,char *dir)
{
	const char *d = dirname(p);
	const char *b = mbasename(p);

	if(isdir(p))
		copyfile(p,dir);
	else
	{
		char f1[1024];
		char f2[1024];

		sprintf(f1,"%s/%s",d,b);
		sprintf(f2,"%s/%s",dir,b);
		copydata(f1,f2);
		sprintf(f1,"%s/.%s",d,b);
		sprintf(f2,"%s/.%s",dir,b);
		copyicon(f1,f2);
	}
}

void copy_mail(article *a,char *dir)
{
	char buf[1024];
	if(chdir(dir))
		marslog(LOG_EROR|LOG_PERR,"Cannot chdir(%s)",dir);
	sprintf(buf,"$METVIEW_BIN/metview-mail -x '%s'", a->examples);
	system(buf);
}

void save_callback (Widget w, XtPointer cd, XmAnyCallbackStruct *cb )
{
	char *u = getenv("METVIEW_USER_DIRECTORY");

	if(current)
	{
		int n = 0;
		char dir[1024];

		xec_SetWatchCursor(top);

		sprintf(dir,"%s/%s %s", u,
		    current->mail?"Mail":"Examples",
		    current->title);
		while(access(dir,0) == 0)
			sprintf(dir,"%s/%s %s (%d)", u,
			    current->mail?"Mail":"Examples",
			    current->title,++n);

		if(mkdir(dir,0777) == 0)
		{
			if(current->mail)
			{
				char buf[1024];
				FILE *f;

				sprintf(buf,"%s/%s",dir,current->title);
				copydata(current->note,buf);


                /* create a 'dot' file to tell Metview this is a NOTE icon */

				sprintf(buf,"%s/.%s",dir,current->title);

				f = fopen(buf,"w");
				if(f)
				{
					fprintf(f,"USER_INTERFACE,ICON_CLASS=NOTE\n");
					fclose(f);
				}
				printf("%s\n",buf);




				copy_mail(current,dir);
			}
			else
			{
				copy(current->note,dir);
				copy(current->examples,dir);
			}
			created(mbasename(dir),"FOLDER");
		}
		else marslog(LOG_EROR|LOG_PERR,"mkdir(%s)",dir);

		xec_ResetCursor(top);

	}
}

void close_callback (Widget w, XtPointer cd, XmAnyCallbackStruct *cb )
{
	marsexit(0);
}



void mail_message_id(char *id)
{
	switch(mailbuf.mode)
	{
	case 0:
		strcpy(mailbuf.id,id);
		break;

	case 1:
		if(strcmp(mailbuf.id,id) == 0)
		{
			mailbuf.mode = 2;
			if(mailout != nulfile)
				fclose(mailout);
			strfree(mailbuf.msgtmp);
			mailbuf.msgtmp = strcache(marstmp());
			mailout = fopen(mailbuf.msgtmp,"w");
			if(!mailout)
			{
				marslog(LOG_EROR|LOG_PERR,"Cannot open %s",mailbuf.msgtmp);
				mailout = nulfile;
			}
		}
		break;

	case 2:
		mailbuf.mode = 1;
		break;
	}
}

void mail_date(char *date)
{
	if(mailbuf.mode == 0)
    {
        strcpy(mailbuf.date,date);
        
        if (strlen(mailbuf.date) > 11) /* crop the date to avoid the time-of-day */
        {
            mailbuf.date[11] = '\0';
        }
    }
}

void mail_subject(char *sub)
{
	if(mailbuf.mode == 0) 
    {
        strcpy(mailbuf.subject,sub);

        if (strlen(mailbuf.subject) > 16) /* crop the subject line */
        {
            mailbuf.subject[16] = '\0';
        }
    }
}

void mail_from(char *from)
{
	if(mailbuf.mode == 0)
    {
        char tmp[256] = "";
        char *pchsrc, *pchdest;
        int  copying = 0;
        int  i = 0;

        strcpy(mailbuf.from,from);


        /* try to find the 'real' name, e.g. auser@ecmwf.int (Arnold User)
           has the 'real' name in brackets */

        pchsrc = mailbuf.from;
        pchdest = tmp;

        while (pchsrc != NULL && *pchsrc != '\0')
        {
            if (copying)
                pchdest[i++] = *pchsrc;

            if (*pchsrc == '(' || *pchsrc == '<')
                copying = 1;
            else if (*pchsrc == ')' || *pchsrc == '>')
                copying = 0;
            
            pchsrc++;
        }
        
        if (i > 0) i--;   /* remove closing bracket */
        pchdest[i] = '\0';
        
        if (i > 0)
            strcpy (mailbuf.from, tmp);
    }
}

void mail_start_icon()
{
	char *p;
	char buf[1024];
	article *a;
	article *b = news;
	article *c = NULL;

	switch(mailbuf.mode)
	{
	case 0:
		sprintf(buf,"%s (%s, %s)",mailbuf.subject,mailbuf.from,mailbuf.date);
/*		sprintf(buf,"%s (%s)",mailbuf.subject,mailbuf.from);*/
		p = buf;
		while(*p)
		{
			if(*p == '/' || *p == '@' || *p == '?' || *p == '*' || *p == '<' || *p == '>' || *p == '#')
			   *p = '-';
			p++;
		}

		a = NEW_CLEAR(article);
		a->date     = time(0);
		a->title    = strcache(buf);
		a->note     = NULL;
		a->examples = strcache(mailbuf.id);
		a->seen = 0;
		a->mail = true;

		while(b)
		{
			if(b->date > a->date) c = b;
			b = b->next;
		}

		if(c) {
			a->next = c->next;
			c->next = a;
		}
		else
		{
			a->next = news;
			news = a;
		}
		break;

	case 1:
		break;

	case 2:
		if(mailout != nulfile)
			fclose(mailout);
		strfree(mailbuf.tartmp);
		mailbuf.tartmp = strcache(marstmp());
		mailout = fopen(mailbuf.tartmp,"w");
		if(!mailout)
		{
			marslog(LOG_EROR|LOG_PERR,"Cannot open %s",mailbuf.tartmp);
			mailout = nulfile;
		}
		break;
	}
}

void mail_end_icon()
{
	if(mailbuf.mode == 2)
	{
		if(mailout != nulfile)
			fclose(mailout);
		mailout = nulfile;
	}
}

void mail_message(char *text)
{
	printf("%s",text);
}

int mailwrap() {
	return 1;
}


void build_list(void)
{
	request *r;
	struct dirent *e;
	DIR *d;
	article *a;
	char *dir = getenv("METVIEW_NEWS");

	scan_mail(0);
	load_seen();


	d = opendir(dir);
	if(!d) {
		marslog(LOG_EROR|LOG_PERR,"opendir %s",dir);
		return;
	}

	while(e = readdir(d))
	{
		if(*e->d_name != '.')
		{
			char buf[1024];
			const char *n,*m;
			sprintf(buf,"%s/.%s",dir,e->d_name);
			if(access(buf,0) == 0)
			{
				request *s = read_request_file(buf);
				n = get_value(s,"ICON_CLASS",0);
				if(n && (strcmp(n,"ARTICLE") == 0))
				{
					struct stat st = {
						0																																								};

					sprintf(buf,"%s/%s",dir,e->d_name);
					r = read_request_file(buf);

					stat(buf,&st); /* Get date */

					n = get_value(r,"NOTE",0);
					m = get_value(r,"EXAMPLES",0);

					if(n)
					{
						article *b = news;
						article *c = NULL;

						a = NEW_CLEAR(article);
						a->date  = st.st_mtime;
						a->title = strcache(e->d_name);
						a->note  = strcache(makepath(dirname(buf),n));
						if(m) a->examples = strcache(makepath(dirname(buf),m));
						a->seen = was_seen(a);

						while(b)
						{
							if(b->date > a->date) c = b;
							b = b->next;
						}

						if(c) {
							a->next = c->next;
							c->next = a;
						}
						else
						{
							a->next = news;
							news = a;
						}
					}


					free_all_requests(r);
				}
				free_all_requests(s);
			}
		}
	}

	closedir(d);

	a = news;
	while(a)
	{
		if(!a->seen) xec_AddListItem(article_list,a->title);
		a = a->next;
	}
}

void clean_up()
{
	article *a = news;
	while(a)
	{
		article *b = a->next;
		if(a->mail && a->note)
		{
			if(a->note) unlink(a->note);
			if(a->examples) unlink(a->examples);
		}
		strfree(a->title);
		strfree(a->note);
		strfree(a->examples);
		FREE(a);
		a = b;
	}
	news = NULL;
}

void refresh_callback(Widget w,XtPointer cd,XtPointer cb)
{
	clean_up();
	xec_ClearList(article_list);
	XtSetSensitive(save_button,False);
	XmTextSetString(article_text,"");
	build_list();
}

void serve(svcid *id,request *r,void *v)
{
	if(XtIsRealized(top))
		/* XRaiseWindow(XtDisplay(top),XtWindow(top)); */
		XMapRaised(XtDisplay(top),XtWindow(top));
	send_reply(id,NULL);
}

static void panic(int code,void *data)
{
	clean_up();
}

int main (int argc, char **argv)
{
	marsinit(&argc,argv,0,0,0);
	install_exit_proc(panic,NULL);

	XtToolkitInitialize ();
	app_context = XtCreateApplicationContext ();
	display = XtOpenDisplay (app_context, NULL, argv[0], "Metview",
	    NULL, 0, &argc, argv);
	if (!display)
	{
		printf("%s: can't open display, exiting...\n", argv[0]);
		exit (-1);
	}
	/* Register converters, just in case you are really unlucky !! */
	XmRegisterConverters();
	/* String to unit type doesn't get added !! */
	XtAddConverter ( XmRString, XmRUnitType, XmCvtStringToUnitType, NULL, 0 );
	create_top ( display, argv[0], argc, argv );
	build_list();
	XtRealizeWidget (top);

	s = RegisterService(app_context,progname());
	add_service_callback(s,NULL, serve, NULL);


	XtAppMainLoop (app_context);
	exit (0);
}
