/*
 * 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 <stdlib.h>
#include <ncurses.h>
#include <signal.h>
#include <sys/stat.h>
#include "structs.h"
#include "proc.h"
#include "functs.h"
#include "colors.h"
#include "mbhelp.h"

#define NIL -1

extern sigset_t allmask;
extern WINDOW *wTxt, *wHlp;
extern int col;
extern sig_atomic_t show_time_now;

extern void showtime();

static char NodeType[9][7]=
{
	"Zone",
	"Region",
	"Host",
	"Hub",
	"Pvt",
	"Hold",
	"Down",
	"Node",
	"Point"
};

NLentryType *Entries;
int maxEntries;

void searchstr(FILE *, FILE *, char *, int);
int getentry(FILE *, int, NLentryType *);
void freeentry(NLentryType *);
int chooseone();

void searchstr(FILE *fi, FILE *fl, char *x, int a)
{
	int i, back=0;
	StrIndexType ind;
	NLentryType ent;
	char name[100];
	
	if (a!=NIL)
	{
		fseek(fi,4+StrIndexSize*a,SEEK_SET);
		fread(&ind,StrIndexSize,1,fi);
		for (i=0; i<ind.num && !back; i++)
		{
			getentry(fl,ind.entry[i].pos,&ent);
			strcpy(name,ent.Sysop);
			freeentry(&ent);
			if (strncasecmp(name,x,strlen(x))==0)
			{
				if (i==0)
					searchstr(fi,fl,x,ind.next0);
				else
					searchstr(fi,fl,x,ind.entry[i-1].next);
				maxEntries++;
				Entries=(NLentryType *)realloc(Entries,NLentrySize*maxEntries);
				getentry(fl,ind.entry[i].pos,&Entries[maxEntries-1]);
			} else
				if (strncasecmp(name,x,strlen(x))>0)
				{
					back=1;
					if (i==0)
						searchstr(fi,fl,x,ind.next0);
					else
						searchstr(fi,fl,x,ind.entry[i-1].next);
				}
		}
		if (!back)
			searchstr(fi,fl,x,ind.entry[i-1].next);
	}
} 

int getentry(FILE *fl, int pos, NLentryType *e)
{
	char line[256], *d1, *d2;
	
	fseek(fl,pos,SEEK_SET);
	fgets(line,255,fl);
	d1=strchr(line,'\n');
	if (d1) *d1=0;
	switch (line[0])
	{
		case 'Z': e->Type=0; break;
		case 'R': e->Type=1; break;
		case 'H': e->Type=2; break;
		case 'U': e->Type=3; break;
		case 'V': e->Type=4; break;
		case 'O': e->Type=5; break;
		case 'D': e->Type=6; break;
		case 'N': e->Type=7; break;
		case 'P': e->Type=8; break;
		default : e->Type=255; break;
	}
	d1=strchr(line,',');
	*d1++=0;
	Str2Addr(&line[1],&(e->ad));
	d2=strchr(d1,',');
	*d2++=0;
	e->Box=(char *)malloc(strlen(d1)+1);
	strcpy(e->Box,d1);
	d1=strchr(d2,',');
	*d1++=0;
	e->Pos=(char *)malloc(strlen(d2)+1);
	strcpy(e->Pos,d2);
	d2=strchr(d1,',');
	*d2++=0;
	e->Sysop=(char *)malloc(strlen(d1)+1);
	strcpy(e->Sysop,d1);
	d1=strchr(d2,',');
	*d1++=0;
	e->Phone=(char *)malloc(strlen(d2)+1);
	strcpy(e->Phone,d2);
	d2=strchr(d1,',');
	if (d2)
	{
		*d2++=0;
		e->Flags=(char *)malloc(strlen(d2)+1);
		strcpy(e->Flags,d2);
	} else e->Flags=NULL;
	e->Speed=atoi(d1);
	return 0;
}

int keyentry(char *addr, NLentryType *e)
{
	FILE *fl, *fi;
	char file[PATH_MAX], *d1;
	int pos, prim, ok=0, j, q;
	long long int key;
	struct stat st;
	
	sprintf(file,"%sfnlc.Nodeindex",NodelistPath);
	stat(file,&st);
	prim=st.st_size/sizeof(int);
	if ((fi=fopen(file,"rb"))!=NULL)
	{
		sprintf(file,"%sfnlc.Userlist",NodelistPath);
		if ((fl=fopen(file,"rt"))!=NULL)
		{
			key=getkey(addr);
			j=(key%prim)+1;
			q=(key%79)+1;
			do
			{
				fseek(fi,(j-1)*sizeof(int),SEEK_SET);
				fread(&pos,sizeof(int),1,fi);
				if (pos==-1) break;
				fseek(fl,pos,SEEK_SET);
				fgets(file,255,fl);
				d1=strchr(file,',');
				*d1=0;
				j=((j+q)%prim)+1;
			} while (key!=getkey(&file[1]));
			if (pos!=-1)
				getentry(fl,pos,e);
			else
				ok=1;
			fclose(fl);
		} else
			ok=1;
		fclose(fi);
	} else
		ok=1;
	return ok;
}

int nameentry(char *name, NLentryType *e)
{
	FILE *fl, *fi;
	char file[PATH_MAX], *d1, *n;
	int pos=0, root, notok=0, x;
	
	sprintf(file,"%sfnlc.Nameindex",NodelistPath);
	if ((fi=fopen(file,"rb"))!=NULL)
	{
		sprintf(file,"%sfnlc.Userlist",NodelistPath);
		if ((fl=fopen(file,"rt"))!=NULL)
		{
			n=(char *)malloc(strlen(name)+1);
			strcpy(n,name);
			d1=strchr(n,32);
			if (d1)
			{
				*d1++=0;
				strcpy(file,d1);
				strcat(file," ");
				strcat(file,n);
			} else strcpy(file,n);
			fseek(fi,0,SEEK_SET);
			fread(&root,sizeof(int),1,fi);
			maxEntries=0;
			searchstr(fi,fl,file,root);
			fclose(fl);
			if (maxEntries)
			{
				if ((pos=chooseone())!=-1)
					*e=Entries[pos];
				else
					notok=1;
			} else notok=1;
			free(n);
		} else
			notok=1;
		fclose(fi);
	} else
		notok=1;
	for (x=0; x<maxEntries; x++)
		if (x!=pos || notok) freeentry(&Entries[x]);
	return notok;
}

void freeentry(NLentryType *e)
{
	free(e->Box);
	free(e->Pos);
	free(e->Sysop);
	free(e->Phone);
	free(e->Flags);
}

void listnl(WINDOW *win, int c, char *f)
{
	int x, sl;
	char sysop[COLS/2], box[COLS/2];
	sl=(LINES-9)/2-c;
	if (sl<0) sl=0;
	wcolon(win,COL_Menu);
	werase(win);
	wmove(win,0,0);
	for (x=0; x<COLS; x++) waddch(win,ACS_HLINE);
	mvwaddstr(win,0,COLS/2-9,"Choose one Address");
	for (x=sl; x<LINES-9; x++)
	{
		if (c-(LINES-9)/2+x==maxEntries) break;
		if ((LINES-9)/2==x)
			wcolon(win,COL_MenuHigh);
		strncpy(sysop,Entries[c-(LINES-9)/2+x].Sysop,COLS/2-12);
		sysop[COLS/2-12]=0;
		strncpy(box,Entries[c-(LINES-9)/2+x].Box,COLS/2-12);
		box[COLS/2-12]=0;
		mvwprintw(win,1+x,0,f,sysop,box,
				Entries[c-(LINES-9)/2+x].ad.Zone,\
				Entries[c-(LINES-9)/2+x].ad.Net,\
				Entries[c-(LINES-9)/2+x].ad.Node,\
				Entries[c-(LINES-9)/2+x].ad.Point);
		wcolon(win,COL_Menu);
	}
	wrefresh(win);
}

int chooseone()
{
	WINDOW *wNl, *wTab;
	int curent=0, in=0;
	char format[40], addr[25];
	sigprocmask(SIG_BLOCK,&allmask,NULL);
	if ((wNl=newwin(LINES-8,0,7,0))!=NULL)
	{
		wcolon(wHlp,COL_StatusLine);
		werase(wHlp);
		mvwaddstr(wHlp,0,1,bhelp_nlchoose);
		wrefresh(wHlp);
		sprintf(format,"%%-%us %%-%us %%u:%%u/%%u.%%u",COLS/2-12,COLS/2-12);
		listnl(wNl,curent,format);
		while (in!=10 && in !=27)
		{
			sigprocmask(SIG_UNBLOCK,&allmask,NULL);
			if (show_time_now) showtime();
			in=getchn();
			if (show_time_now) showtime();
			sigprocmask(SIG_BLOCK,&allmask,NULL);
			switch ((char)in)
			{
				case 0x9:
					if ((wTab=openask(6,0,LINES/2-4+7,0,"Node-Info",\
							COL_MenuHigh))!=NULL)
					{
						mvwaddstr(wTab,1,1,NodeType[Entries[curent].Type]);
						mvwaddstr(wTab,2,1,Entries[curent].Sysop);
						mvwaddstr(wTab,3,1,Entries[curent].Box);
						mvwaddstr(wTab,4,1,Entries[curent].Pos);
						sprintf(addr,"%u:%u/%u.%u",Entries[curent].ad.Zone,\
								Entries[curent].ad.Net,\
								Entries[curent].ad.Node,\
								Entries[curent].ad.Point);
						mvwaddstr(wTab,1,COLS-2-strlen(addr),addr);
						mvwaddstr(wTab,2,COLS-2-strlen(Entries[curent].Phone),\
								Entries[curent].Phone);
						sprintf(addr,"%u",Entries[curent].Speed);
						mvwaddstr(wTab,3,COLS-2-strlen(addr),addr);
						mvwaddstr(wTab,4,COLS-2-strlen(Entries[curent].Flags),\
								Entries[curent].Flags);
						wrefresh(wTab);
						getch();
						delwin(wTab);
						touchwin(wNl);
						wrefresh(wNl);
					} else Beep();
					break;
				case 0x1b:
					switch ((in=getchn()))
					{
						case 0x5b:
							switch ((in=getchn()))
							{
								case 0x41:
									if (curent>0)
									{
										curent--;
										listnl(wNl,curent,format);
									} else Beep();
									break;
								case 0x42:
									if (curent<maxEntries-1)
									{
										curent++;
										listnl(wNl,curent,format);
									} else Beep();
									break;
								case 0x35:
									getch();
									if (curent!=0)
									{
										curent-=10;
										if (curent<0) curent=0;
										listnl(wNl,curent,format);
									} else Beep();
									break;
								case 0x36:
									getch();
									if (curent!=maxEntries-1)
									{
										curent+=10;
										if (curent>=maxEntries) curent=maxEntries-1;
										listnl(wNl,curent,format); 
									} else Beep();
									break;
								case 0x31:
									getch();
									curent=0;
									listnl(wNl,curent,format);
									break;
								case 0x34:
									getch();
									curent=maxEntries-1;
									listnl(wNl,curent,format);
									break;
							} break;
					} break;
			}
		}
		delwin(wNl);
		touchwin(wTxt);
		wrefresh(wTxt);
		if (in==10)
			return curent;
	}
	return -1;
}
