/*
 * This file is part of the FEddi package
 *
 * Personal use allowed under the terms of the
 *
 *              GNU GENERAL PUBLIC LICENSE Version 2
 *              (see LICENSE for the complete text)
 *
 *-------------------------------------------------------------------
 *
 *    ENTER AT YOUR OWN RISK !!
 *
 * This source is without any documentation and can drive you mad.
 * In case of sudden epileptic seizures please call your doctor.
 *
 */

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <ncurses.h>
#include <signal.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include "proc.h"
#include "functs.h"
#include "colors.h"
#include "charset.h"
#include "template.h"
#include "mbhelp.h"

extern sigset_t allmask;
extern WINDOW *wTxt;
extern FolderType *Folder;
extern int maxFld, curFld;
extern sig_atomic_t show_time_now;
extern int MsgLines, KludgeLines;
extern LineListType *MsgTxt, *Kludges;

extern void initmenu();
extern void showtime();

void expandFilename(char *);

int inputline(WINDOW *win, WINDOW *hlp, int y, int x, int l, char *s,
		char **h, int e, int tabexpand)
{
	char line[PATH_MAX];
	int i, j, in=0, k, hist=0, old_curs=CURSOR_OFF;
	sigprocmask(SIG_BLOCK,&allmask,NULL);
	wkill(hlp,COL_StatusLine);
	mvwaddstr(hlp,0,1,tabexpand?bhelp_inputfile:bhelp_inputline);
	wrefresh(hlp);
	strcpy(line,s);
	old_curs=curs_set(CURSOR_ON);
	wmove(win,y,x);
	wclrnumn(win,l);
	mvwaddstru(win,y,x,line);
	wrefresh(win);
	i=j=strlen(line);
	while (in!=27 && in!=10)
	{
		sigprocmask(SIG_UNBLOCK,&allmask,NULL);
		if (show_time_now) showtime();
		in=getchn();
		if (show_time_now) showtime();
		sigprocmask(SIG_BLOCK,&allmask,NULL);
		switch (in)
		{
			case 9:
				if (tabexpand)
				{
					line[i]=0;
					expandFilename(line);
					i=j=strlen(line);
					mvwaddstr(win,y,x,line);
					touchwin(win);
					wrefresh(win);
				}
				break;
			case 10: break;
			case 25:
				wmove(win,y,x);
				for (i=0; i<l; i++) waddch(win,32);
				j=i=0;
				wmove(win,y,x);
				wrefresh(win);
				break;
				if (i<l)
				{
					if (j!=i)
						for (k=i; k>j; k--)
						{
							line[k]=line[k-1];
							mvwaddch(win,y,x+k,line[k-1]);
						}
					line[j]=in;
					mvwaddch(win,y,x+j,in);
					wrefresh(win);
					i++;
					j++;
				}
				break;
			case 127:
				if (i>0 && j>0)
				{
					if (j!=i)
						for (k=j; k<i; k++)
						{
							line[k-1]=line[k];
							mvwaddch(win,y,x+k-1,line[k]);
						}
					i--;
					mvwaddch(win,y,x+i,32);
					j--;
					wmove(win,y,x+j);
					wrefresh(win);
				}
				break;
			case 0x1b:
				in=getchn();
				if (in==0x5b)
					switch ((in=getchn()))
					{
						case 0x44: if (j>0) j--;
											wmove(win,y,x+j); wrefresh(win); break;
						case 0x43: if (j<i) j++;
											wmove(win,y,x+j); wrefresh(win); break;
						case 0x41: if (j>0)
											{
												while (((line[j]>='a' && line[j]<='z')||\
																(line[j]>='A' && line[j]<='Z')||\
																(line[j]>='0' && line[j]<='9')) && j>0) j--;
												while (!((line[j]>='a' && line[j]<='z')||\
																	(line[j]>='A' && line[j]<='Z')||\
																	(line[j]>='0' && line[j]<='9')) && j>0) j--;
												for (; j>0 && ((line[j]>='a' && line[j]<='z')||\
																				(line[j]>='A' && line[j]<='Z')||\
																				(line[j]>='0' && line[j]<='9')); j--);
												while (!((line[j]>='a' && line[j]<='z')||\
																	(line[j]>='A' && line[j]<='Z')||\
																	(line[j]>='0' && line[j]<='9')) && j<i) j++;
											}
											wmove(win,y,x+j); wrefresh(win); break;
						case 0x42: if (j<i)
											{
												j++;
												if (!(
															!((line[j]>='a' && line[j]<='z')||\
																(line[j]>='A' && line[j]<='Z')||\
																(line[j]>='0' && line[j]<='9')) &&\
															((line[j-1]>='a' && line[j-1]<='z')||\
																(line[j-1]>='A' && line[j-1]<='Z')||\
																(line[j-1]>='0' && line[j-1]<='9'))))
													for (; j<i && ((line[j]>='a' && line[j]<='z')||\
																					(line[j]>='A' && line[j]<='Z')||\
																					(line[j]>='0' && line[j]<='9')); j++);
												while (!((line[j]>='a' && line[j]<='z')||\
																	(line[j]>='A' && line[j]<='Z')||\
																	(line[j]>='0' && line[j]<='9')) && j<i) j++;
											}
											wmove(win,y,x+j); wrefresh(win); break;
						case 0x31: getch();
											j=0; wmove(win,y,x+j); wrefresh(win); break;
						case 0x34: getch();
											j=i; wmove(win,y,x+j); wrefresh(win); break;
						case 0x33: getch();
											if (j!=i && i>0)
											{
												i--;
												for (k=j; k<i; k++)
												{
													line[k]=line[k+1];
													mvwaddch(win,y,x+k,line[k+1]);
												}
												mvwaddch(win,y,x+i,32);
												wmove(win,y,x+j);
												wrefresh(win);
											}
											break;
						case 0x35: getch();
											if (h && hist>0)
											{
												hist--;
												strncpy(line,h[hist],l);
												line[l]=0;
												wmove(win,y,x);
												for (i=0; i<l; i++) waddch(win,32);
												mvwaddstru(win,y,x,line);
												i=j=strlen(line);
											} else Beep();
											wrefresh(win);
											break;
						case 0x36: getch();
											if (h && hist<e-1)
											{
												hist++;
												strncpy(line,h[hist],l);
												line[l]=0;
												wmove(win,y,x);
												for (i=0; i<l; i++) waddch(win,32);
												mvwaddstru(win,y,x,line);
												i=j=strlen(line);
											} else Beep();
											wrefresh(win);
											break;
					}
				break;
			default:
				if (PRINTABLECHAR[in])
				{
					if (i<l)
					{
						if (j!=i)
							for (k=i; k>j; k--)
							{
								line[k]=line[k-1];
								mvwaddch(win,y,x+k,line[k-1]);
							}
						line[j]=in;
						mvwaddch(win,y,x+j,in);
						wrefresh(win);
						i++;
						j++;
					}
				}
				break;
		}
	}
	line[i]=0;
	curs_set(old_curs);
	initmenu();
	move(0,0);
	refresh();
	if (in==10 && line[0])
	{
		strcpy(s,line);
		return 0;
	}
	else
		if (in==10)
			return -1;
		else
			return -2;
}

WINDOW *openask(int yl, int xl, int ys, int xs, char *title, chtype attr)
{
	WINDOW *ask;
	if ((ask=newwin(yl,xl,ys,xs))!=NULL)
	{
		wcolon(ask,attr);
		wkill(ask,attr);
		box(ask,0,0);
		mvwaddstru(ask,0,(xl?xl:COLS)/2-strlen(title)/2,title);
	}
	return ask;
}

char **addhistory(char **hist, int entrys, char *line)
{
	hist=(char **)realloc(hist,sizeof(char *)*(entrys+1));
	hist[entrys]=(char *)malloc(strlen(line)+1);
	strcpy(hist[entrys],line);
	return hist;
}

void Beep()
{
	if (BeepOn)
	{
		beep();
		refresh();
	}
}

void showscrtext(WINDOW *win, LineListType *text, int start, int lines,
		int height)
{
	int i;
	for (i=0; i+start<lines && i<height; i++)
	{
		mvwaddstru(win,i+1,1,text[i+start].line);
		wclrtoeoln(win);
	}
	wrefresh(win);
}

int scrolltext(LineListType *text, int lines, char *title, int question)
{
	WINDOW *win;
	int i, width, height, l=0, in=0, ende=0;
	width=(strlen(title)+2)>21?strlen(title)+2:21;
	for (i=0; i<lines; i++)
		if (strlen(text[i].line)>width) width=strlen(text[i].line);
	height=(lines>LINES-10)?LINES-10:lines;
	if (width-2>COLS) width=COLS-2;
	if ((win=openask(height+2,width+2,7+LINES/2-4-height/2-1,COLS/2-width/2-1,\
			title,COL_Menu))!=NULL)
	{
		if (lines==height)
		{
			mvwaddstru(win,height+1,width-(question?6:13),
					question?"yes/no":"<CR> to leave");
			showscrtext(win,text,l,lines,height);
			while (!ende)
				if (question)
					switch (getchn())
					{
						case 'y':
						case 'Y':
							ende=2;
							break;
						case 'n':
						case 'N':
							ende=1;
							break;
					}
				else
					ende=(getchn()==0xa);
		} else
		{
			mvwaddstru(win,height+1,width-(question?18:25),
					question?"<UP>/<DOWN> yes/no":"<UP>/<DOWN> <CR> to leave");
			showscrtext(win,text,l,lines,height);
			while (!ende)
			{
				switch ((in=getchn()))
				{
					case 0xa:
						if (!question) ende=1;
						break;
					case 'y':
					case 'Y':
						if (question) ende=2;
						break;
					case 'n':
					case 'N':
						if (question) ende=1;
						break;
					case 0x1b:
						in=getchn();
						if (in==0x5b)
							switch ((in=getchn()))
							{
								case 0x41:
									if (l>0)
									{
										l--;
										showscrtext(win,text,l,lines,height);
									} else
										Beep();
									break;
								case 0x42:
									if (l<lines-height)
									{
										l++;
										showscrtext(win,text,l,lines,height);
									} else
										Beep();
									break;
								case 0x31: getch();
									l=0;
									showscrtext(win,text,l,lines,height);
									break;
								case 0x34: getch();
									l=lines-height;
									showscrtext(win,text,l,lines,height);
									break;
							}
						break;
				}
			}
		}
		delwin(win);
		return (ende-1);
	}
	Beep();
	return 0;
}

void showchotext(WINDOW *win, LineListType *text, int high, int lines,
		int height)
{
	int i, l;
	if (lines==height || high<height/2)
		i=0;
	else
		if (high>lines-height/2)
			i=lines-height;
		else
			i=high-height/2;
	for (l=0; i<lines && l<height; i++, l++)
	{
		wcolon(win,i==high?COL_MenuHigh:COL_Menu);
		mvwaddstru(win,l+1,1,text[i].line);
		wclrtoeoln(win);
	}
	wrefresh(win);
}

int scrollchoice(LineListType *text, int lines, char *title,
		int (*key)(int, int))
{
	WINDOW *win;
	int i, width, height, l=0, in=0, ende=0;
	width=(strlen(title)+2)>30?strlen(title)+2:30;
	for (i=0; i<lines; i++)
		if (strlen(text[i].line)>width) width=strlen(text[i].line);
	height=(lines>LINES-10)?LINES-10:lines;
	if ((win=openask(height+2,width+2,7+LINES/2-4-height/2-1,COLS/2-width/2-1,\
			title,COL_Menu))!=NULL)
	{
		mvwaddstru(win,height+1,width-26,"<UP>/<DOWN> <CR> to choose");
		showchotext(win,text,l,lines,height);
		while (!ende)
		{
			switch ((in=getchn()))
			{
				case 0xa:
					ende=1;
					break;
				case 0x1b:
					switch (getchn())
					{
						case 0x1b:
							ende=2;
							break;
						case 0x5b:
							switch ((in=getchn()))
							{
								case 0x41:
									if (l>0)
									{
										l--;
										showchotext(win,text,l,lines,height);
									} else
										Beep();
									break;
								case 0x42:
									if (l<lines-1)
									{
										l++;
										showchotext(win,text,l,lines,height);
									} else
										Beep();
									break;
								case 0x31: getch();
									l=0;
									showchotext(win,text,l,lines,height);
									break;
								case 0x34: getch();
									l=lines-1;
									showchotext(win,text,l,lines,height);
									break;
							}
							break;
						default:
							if (key)
								if ((i=(*key)(in,1))!=-1)
								{
									l=i;
									ende=1;
								}
							break;
					}
					break;
				default:
					if (key)
						if ((i=(*key)(in,0))!=-1)
						{
							l=i;
							ende=1;
						}
					break;
			}
		}
		delwin(win);
	}
	return (ende==1?l:-1);
}

WINDOW *EXTWin;

void EXTWait(char* name)
{
	if ((EXTWin=openask(3,22,LINES/2+1,COLS/2-11,"External Call:",\
			COL_Menu))!=NULL)
	{
		mvwprintw(EXTWin,1,11-strlen(name)/2,"%s", name);
		mvwaddstr(EXTWin,2,4,"Please Wait...");
		wrefresh(EXTWin);
	}
}

void EXTEnd()
{
	if (EXTWin)
		delwin(EXTWin);
}

char *fldlm(char *match, char *result)
{
	int i, j, l=0, lm=strlen(match);
	char **lines=NULL;
	for (i=0; i<maxFld; i++)
		if (strncasecmp(Folder[i].name,match,lm)==0)
		{
			l++;
			lines=(char **)realloc(lines,sizeof(char *)*l);
			lines[l-1]=(char *)malloc(strlen(Folder[i].name)+1);
			strcpy(lines[l-1],Folder[i].name);
		}
	if (l==0)
	{
		result[0]=0;
		return NULL;
	}
	if (l==1)
	{
		strcpy(result,lines[0]);
		free(lines[0]);
		free(lines);
		return result;
	}
	for (i=0; i<strlen(lines[0]); i++)
	{
		result[i]=lines[0][i];
		for (j=1; j<l; j++)
			if (result[i]!=lines[j][i])
				break;
		if (j!=l)
		{
			result[i]=0;
			break;
		}
	}
	for (i=0; i<l; i++) free(lines[i]);
	free(lines);
	return result;
}

int showlog(LineListType **log)
{
	char line[150], *d1;
	int lines=0, mo=0, len=0;
	FILE *f;
	sync();
	*log=NULL;
	if ((f=fopen(LogFile,"rt"))!=NULL)
	{
		fseek(f,logpos,SEEK_SET);
		while (fgets(line,150,f))
		{
			if (line[0]=='*')
			{
				mo++;
				len=strchr(line,']')-line+1;
				if (mo==2) break;
				continue;
			}
			if (mo==1)
			{
				d1=strchr(line,'\n');
				if (d1) *d1=0;
				lines++;
				*log=(LineListType *)realloc(*log,lines*LineListSize);
				(*log)[lines-1].line=(char *)malloc(strlen(line)-len);
				strcpy((*log)[lines-1].line,&line[len+1]);
			}
		}
		fclose(f);
	}
	return lines;
}

int waddstru(WINDOW *win, char *str)
{
	int i;
	for (i=0; i<strlen(str); i++) waddch(win,(unsigned char)str[i]);
	return 0;
}

int mvwaddstru(WINDOW *win, int y, int x, char *str)
{
	int i;
	wmove(win,y,x);
	for (i=0; i<strlen(str); i++) waddch(win,(unsigned char)str[i]);
	return 0;
}

int wclrtoeoln(WINDOW *win)
{
	int x,xl,i;
	getyx(win,i,x);
	getmaxyx(win,i,xl);
	for (i=x; i<xl-1; i++) waddch(win,32);
	return 0;
}

int wclrtoeolu(WINDOW *win)
{
	int x,xl,i;
	getyx(win,i,x);
	getmaxyx(win,i,xl);
	for (i=x; i<xl; i++) waddch(win,32);
	return 0;
}

int wclrnumn(WINDOW *win, int l)
{
	int i;
	for (i=0; i<l; i++) waddch(win,32);
	return 0;
}

char *expandfname=NULL;

int selectfile(const struct dirent *d)
{
	if (strcmp(((struct dirent *)d)->d_name,".")==0) return 0;
	if (strcmp(((struct dirent *)d)->d_name,"..")==0) return 0;
	return (strncmp(((struct dirent *)d)->d_name,
				expandfname,
				strlen(expandfname))==0);
}

void expandFilename(char *file)
{
	struct dirent **ent=NULL;
	int ents=0, i;
	char *path, *d1, title[PATH_MAX];
	struct stat st;
	LineListType *files=NULL;
	extendhome(file);
	if ((d1=strrchr(file,'/')))
	{
		*d1=0;
		if (d1==file)
			path=strdup("/");
		else
			path=strdup(file);
		d1++;
	} else
	{
		d1=file;
		path=strdup(".");
	}
	expandfname=strdup(d1);
	if ((ents=scandir(path,&ent,selectfile,alphasort))>0)
	{
		if (ents==1)
		{
			free(expandfname);
			expandfname=strdup(ent[0]->d_name);
		} else
		{
			files=(LineListType *)malloc(ents*LineListSize);
			for (i=0; i<ents; i++)
			{
				files[i].line=(char *)malloc(strlen(ent[i]->d_name)+2);
				strcpy(files[i].line,ent[i]->d_name);
				if (!stat(files[i].line,&st))
					if (st.st_mode&S_IFDIR) strcat(files[i].line,"/");
			}
			strcpy(title,"Select file from ");
			strcat(title,path);
			title[78]=0;
			if ((i=scrollchoice(files,ents,title,NULL))>=0)
			{
				free(expandfname);
				expandfname=strdup(ent[i]->d_name);
			} else
				Beep();
			touchwin(wTxt);
			wrefresh(wTxt);
			for (i=0; i<ents; i++) free(files[i].line);
			free(files);
		}
	} else
		Beep();
	if (strlen(path)>1)
		sprintf(file,"%s/%s",path,expandfname);
	else
	{
		if (path[0]=='/')
			sprintf(file,"/%s",expandfname);
		else
			strcpy(file,expandfname);
	}
	if (!stat(file,&st))
		if (st.st_mode&S_IFDIR) mksl(file);
	freedirentries(&ent,ents);
	free(path);
	free(expandfname);
}
