/*
 * Bioinfo Animal Pictures Archive - Search CGI script
 * APAsrch2.c - Using GET method
 * Resulting program : APAsrch2.cgi
 * Kim, Jinsuk  [jskim@bioinfo.kordic.re.kr]
 */

#include "APAsrch2.h"

void PrintMsg(content, align, color)
	char *content;
	char *align;
	char *color;
{
	printf("<p align=\"%s\"><font color=\"%s\">", align, color);
	printf("<b>%s</b></font><p>\n", content);
}

void InsertDelimeter(s) /* insert delimeter for names */
        char *s;
{
	char buf[256];
	int len;
	int i, j;
	int idx[256];

	len = strlen(s);

	/* upper char = 1, lower char = 0, else = -1
	   ex)	DKMMNature-Reptile-PoisonousLizard-GilaMonster.gif
		1111100000_1000000_100000000100000_10001000000_000
		where _ = -1
	*/
	for (i=0; i<len; i++)
	{
		if (s[i] >= 65 && s[i] <= 90)		/* upper case */
			idx[i] =  1;
		else if (s[i] >= 97 && s[i] <= 122)	/* lower case */
			idx[i] =  0;
		else
			idx[i] = -1;
	}

	buf[0] = s[0];
	for (i=1, j=1; i<len-1; i++, j++)
	{
		if ( (idx[i]==1) && ((idx[i-1]+idx[i]+idx[i+1])==1))
		{
			buf[j++] = '#';
			buf[j] = s[i];
		}
		else
			buf[j] = s[i];
	}
	buf[j++] = s[i]; buf[j] = '\0';

	strcpy(s, buf);
}

void strlower(string) /* small capitalize a string */
	char *string;
{
	char c;
	int i;

	for(i=0; i<strlen(string); i++) {
		if ( isalpha(string[i]) && isupper(string[i]) )
			string[i] = string[i] + 32;
	}
}

void DelSpace(string)
        char    *string;
{
        char *ptr;

        while (ptr = (char *) strstr(string, " "))
        {
                *(ptr) = '\0';
                strcat(string, ptr+1);
                DelSpace(string);
        }
}

void Space2Star(string)
        char    *string;
{
        char *ptr;

        while (ptr = (char *) strstr(string, " "))
        {
                *(ptr) = '*';
        }
}


void APAsrch(entries, i)
	getentry *entries;
	int i;
{
	int x, y;	/* general purposes */
	int num_fnd=0;	/* number of retrieval in a index file */
	char *query, buf[255];

	typedef struct
	{
		int	name[MAX_DIR_NUM];
		int	num;
	}dir;

	dir Dir;

	Dir.num = 0;
	for (x=0; x<MAX_DIR_NUM; x++)
	{
		Dir.name[x] = 0;
	}

	for (x = 0; x <= i; x++)
	{
		if (!strcasecmp(entries[x].name, "qt"))
		{
			query = (char *)malloc(strlen(entries[x].val)+1);
			strcpy(query, entries[x].val);
			trim(query);
			continue;
		}
		if (!strncasecmp(entries[x].name, "dir", 3))
		{
			Dir.name[Dir.num] = atoi(entries[x].val);
			Dir.num++;
			continue;
		}
	}

 	printf("<UL>\n");
	if (Dir.num > 0 && Dir.name[0] > 0)
	{
		for (x=0; x<Dir.num; x++)
		{
			sprintf(buf, "%s%d", LIST, Dir.name[x]);
			num_fnd += DirListSearch(query, buf, Dir.name[x]);
		}
	}
	else
	{
		for (x=0; x<MAX_DIR_NUM; x++)
		{
			sprintf(buf, "%s%d", LIST, x+1);
			num_fnd += DirListSearch(query, buf, x+1);
		}
	}
       	printf("</UL>\n");

	if (num_fnd <= 0)
	{
		printf("<p><dl><dd><font size=+1>Sorry, currently this archive has no ");
		printf("<B><I><font color=brown>%s</font></I></B> image\n", query); 
		if (Dir.num == 1)
			printf(" in directory %d.<p>");
		else if (Dir.num == 0)
		{
			printf(" in directories ");
			for (x=1; x<=MAX_DIR_NUM; x++)
			{
				if (x == MAX_DIR_NUM)
					printf("and %d.", x);
				else
					printf("%d, ", x);
			}
		}
		else
		{
			printf(" in directories ");
			for (x=0; x<Dir.num; x++)
			{
				if (x == Dir.num - 1)
					printf("and %d.", Dir.name[x]);
				else
					printf("%d, ", Dir.name[x]);
			}
		}

		printf("<p><ul><li>Try <font color=blue><b>SINGULAR</b></font> noun.\n (Ex. <tt>DOGS -> DOG, WOLVES -> WOLF</tt>)\n");
		printf("<li>Try <font color=blue><b>SYNONYM</b></font>.\n (Ex. <tt>BLACK PUMA -> PANTHER, MOUNTAIN LION -> COUGAR</tt>)\n");
		printf("<li>Try <font color=blue><b>BROADER</b></font> term.\n (Ex. <tt>MONITOR -> LIZARD</tt>)\n");
		printf("<li>Try <font color=blue><b>PARTIAL</b></font> term.\n (Ex. <tt>PUPPY -> PUPP, CROCODILE-> CROC</tt>)\n");
		printf("<li>NO HELP? Hmmm... Try <a href=\"namelist.html\"><b>KEYWORD LIST</b></a> for this archive.\n");
		printf("</ul></font><p></dd></dl>\n");
	}
	else {
		printf("<hr><p align=center>");
		printf("<font size=+1><font color=blue>%d</font> image(s) of ", num_fnd);
		printf("<B><I><font color=brown>%s</font></B></I> found\n", query);
		if (Dir.num == 1)
			printf(" in directory %d.<p>");
		else if (Dir.num == 0)
		{
			printf(" in directories ");
			for (x=1; x<=MAX_DIR_NUM; x++)
			{
				if (x == MAX_DIR_NUM)
					printf("and %d ", x);
				else
					printf("%d, ", x);
			}
		}
		else
		{
			printf(" in directories ");
			for (x=0; x<Dir.num; x++)
			{
				if (x == Dir.num - 1)
					printf("and %d ", Dir.name[x]);
				else
					printf("%d, ", Dir.name[x]);
			}
		}
		printf("</font></p>\n");
	}
}


int DirListSearch(query, fname, dir_num)
	char *query;
	char *fname;
	int dir_num;
{
	int k = 0;
	int fsize;	/* file size in Kbytes */
	char q_buf[256], buf[256], target[256];

	FILE *fp;	/* file pointers to open index files */
	/* File Open Error detection */
	if ( (fp=fopen(fname, "r")) == NULL )
	{
		printf("<B>List file open error.</B><P>\n");
		printf("Contact <A HREF=\"mailto:%s\">", WEB_MASTER);
		printf("<I>Web master</I></A>.<P>\n");
		exit(1);
	}
	fgets( buf, 256, fp);	/* remove first line of LIST1 */

	strcpy(buf, query);
	Space2Star(buf);

	strcpy(q_buf, "*");
	strcat(q_buf, buf);
	strcat(q_buf, "*");
	strlower(q_buf);

	while (!feof(fp))
	{
		fscanf(fp, "%d %s", &fsize, target);
		strcpy(buf, target);
		InsertDelimeter(buf);
		strlower(buf);
		if ( CompareString(q_buf, buf) && \
			!strstr(buf, ".txt") && \
			!strstr(buf, ".html") )
		{
			printf("<li>[<a ");
			printf("href=\"%s?email=&srcFile=%s%d/%s\">",\
				CGI_UU2MAIL, ARCH_DIR, dir_num, target);
			printf("uu2mail</a>] ");
			if (fsize <= 40)
				printf("[<a href=\"%s?img=%s%d/%s&scaleFactor=2\">Preview 1/2</a>] ", CGI_PREVIEW, ARCH_DIR, dir_num, target);
			else if (fsize > 40 && fsize <= 160)
				printf("[<a href=\"preview.cgi?img=%s%d/%s&width=320\">Preview 1/4</a>] ", ARCH_DIR, dir_num, target);
			else if (fsize > 160)
				printf("[<a href=\"preview.cgi?img=%s%d/%s&scaleFactor=8\">Preview 1/8</a>] ", ARCH_DIR, dir_num, target);
			else
				printf("[Preview] ");
			printf("[<a href=\"ViewImg.cgi?img=%s%d/%s\">",\
				ARCH_DIR, dir_num, target);
			printf("%s%d/%s</a>]", ARCH_DIR, dir_num, target);
			printf(" (%dKb)\n", fsize);
			k++;
		}
	}
	fclose(fp);

	return k;
}

int main()
{
	FILE		*fp;
	getentry	entries[MAX_ENTRY_NUM];
	long int	i, x, y, flag;
	char		query[256];

	typedef struct
	{
		int	name[MAX_DIR_NUM];
		int	num;
	}dir;

	dir Dir;

	Dir.num = 0;
	for (x=0; x<MAX_DIR_NUM; x++)
	{
		Dir.name[x] = 0;
	}

	strcpy(query, "\0");
	printf("content-type: text/html\n\n");	/* HTML Header */

#ifdef FILEOUT
	printf("Debugging Mode\n");
	i = 2;
	strcpy(entries[0].name, "qt");
	strcpy(entries[0].val, "tiger");
	strcpy(entries[1].name, "dir");
	strcpy(entries[1].val, "1");
	strcpy(entries[2].name, "dir");
	strcpy(entries[2].val, "2");
#else
	i = ProcessGetMethod( entries );
#endif

	for (x=0; x<=i; x++)
	{
		if (!strcasecmp(entries[x].name, "qt"))
		{
			strcpy(query, entries[x].val);
			trim(query);
		}
		if (!strncasecmp(entries[x].name, "dir", 3))
		{
			Dir.name[Dir.num] = atoi(entries[x].val);
			Dir.num++;
			continue;
		}
	}

	printf("<HTML>");
       	printf("<HEAD>\n");
	if ( strlen(query) > 0)
       		printf("<TITLE>Bioinfo Animal Pictures Archive Search \"%s\"</TITLE>\n", query);
	else
       		printf("<TITLE>Bioinfo Animal Pictures Archive Search</TITLE>\n");
       	printf("</HEAD>\n");

	printf("<body bgcolor=\"white\">\n");
	printf("<center><IMG SRC=\"APAsrch.gif\"></center>\n");
        printf("<HR SIZE=5>\n");

	printf("<center>\n");
	printf("<FORM METHOD=\"GET\" ACTION=\"%s\">\n", CGI_APA_SEARCH);
	printf("<b>Search directories ");
	for (flag=0, x=0; x<MAX_DIR_NUM; x++)
	{
		printf(" <input type=\"checkbox\" name=\"dir\" value=\"%d\"", x+1);
		for (y=0; y < Dir.num; y++)
		{
			if (Dir.name[y] == x+1)
				flag = 1;
		}
		if (Dir.num == 0)
			flag = 1;
		if (flag)
			printf(" checked>");
		else
			printf(">");
		printf("%d\n", x+1);
		flag = 0;
	}
	printf("</b>\n");
	printf("<br><INPUT NAME=\"qt\" SIZE=40 VALUE=\"%s\">\n", query);
	printf("<INPUT TYPE=submit VALUE=\"Search\"><br>\n");
	printf("<B>Tips:</B>");
	printf("Case-insensitive; Able to use wild card characters <tt>*</tt> and <tt>?</tt>;<br>Singular noun search; \n");
	printf("Examples - <font color=brown><tt>WOLF<font color=blue>*</font>HOWL</tt>, ");
	printf("<tt>ALLIGAT<font color=blue>?</font>R</tt></font>\n");
	printf("</FORM>\n<P>\n<HR SIZE=5>\n");

	printf("</center>\n");

	if ( strlen(query) > 0)
	{
		APAsrch(entries, i);
	}
	else {
		printf("<p align=center><font color=brown size=+1><b>Enter Search Keyword</b></font>\n");
	}

        printf("<HR SIZE=5>\n");

	printf("<CENTER><P>\n");
	printf("[ <A HREF=\"%s\">BIOINFO HOME</A> ]<BR>\n", BIOINFO_HOME);
	printf("[ <A HREF=\"%s\">Animal Pictures Archive Home</A> ]<BR>\n",\
		APA_HOME);
	printf("[ <A HREF=\"%s\">Animal Movies</A> ]<BR>\n", MOVIE_HOME);
	printf("<HR WIDTH=400 SIZE=5>\n");
	printf("<HR WIDTH=300 SIZE=5>\n");
	printf("<HR WIDTH=200 SIZE=5>\n");

	if((fp=fopen(ACC_NUM_FILE, "r"))==NULL)
                printf("<I>OOPS! Counter File Open Error</I>");
	else
	{
		fscanf(fp,"%d",&x);
		fclose(fp);
		printf("%d<p>\n", x);
	}

	printf("</CENTER>\n");
	printf("</HTML>");

	if((fp=fopen(ACC_NUM_FILE, "w"))==NULL)
                printf("<I>OOPS! Counter File Open Error</I>");
	else
	{
		fprintf(fp,"%d\n",x+1);
		fclose(fp);
	}

	/* query logging */
	if((fp=fopen(QUERY_LOG_FILE, "a"))==NULL)
                printf("<I>OOPS! Log File Open Error</I>");
	else
	{
		fprintf(fp,"%d %s\n", x, query);
		fclose(fp);
	}

	exit(0);
}

/*
 * Wild Card Comparison
 * armian@stissbs.kordic.re.kr
 */

int
CompareString(str1, str2)
char    *str1, *str2;
{
        int     ret;
        char    *ptr1, *ptr2;

        if (str1[0] == '\0' && str2[0] == '\0')
        {
                return 1;
        }

        if (str1[0] == '\0' || str2[0] == '\0')
        {
                return 0;
        }

        if (str1[0] == str2[0])
        {
                ret = CompareString(&str1[1], &str2[1]);
        }
        else if (str1[0] == '?')
        {
                ret = CompareString(&str1[1], &str2[1]);
        }
        else if (str1[0] == '*')
        {
                ptr1 = &str1[1];
                while(1)
                {
                        if (*ptr1 == '\0')
                        {
                                return 1;
                        }

                        if (*ptr1 == '*' || *ptr1 == '?')
                        {
                                ptr1++;
                        }
                        else
                        {
                                break;
                        }
                }

                while(1)
                {
                        ptr2 = (char *) strchr(str2, *ptr1);

                        if (ptr2 == NULL)
                        {
                                return 0;
                        }

                        ret = CompareString(ptr1, ptr2);

                        if (ret)
                                return ret;
                        else
                                str2++;

                }
        }
        else
        {
                return 0;
        }

        return ret;

}

/* NCSA Web Library */
void 
getword(char *word, char *line, char stop)
{
	int             x = 0, y;

	for (x = 0; ((line[x]) && (line[x] != stop)); x++)
		word[x] = line[x];

	word[x] = '\0';
	if (line[x])
		++x;
	y = 0;

	while (line[y++] = line[x++]);
}

char           *
makeword(char *line, char stop)
{
	int             x = 0, y;
	char           *word = (char *) malloc(sizeof(char) * (strlen(line) + 1));

	for (x = 0; ((line[x]) && (line[x] != stop)); x++)
		word[x] = line[x];

	word[x] = '\0';
	if (line[x])
		++x;
	y = 0;

	while (line[y++] = line[x++]);
	return word;
}

char           *
fmakeword(FILE * f, char stop, int *cl)
{
	int             wsize;
	char           *word;
	int             ll;

	wsize = 102400;
	ll = 0;
	word = (char *) malloc(sizeof(char) * (wsize + 1));

	while (1)
	{
		word[ll] = (char) fgetc(f);
		if (ll == wsize)
		{
			word[ll + 1] = '\0';
			wsize += 102400;
			word = (char *) realloc(word, sizeof(char) * (wsize + 1));
		}
		--(*cl);
		if ((word[ll] == stop) || (feof(f)) || (!(*cl)))
		{
			if (word[ll] != stop)
				ll++;
			word[ll] = '\0';
			return word;
		}
		++ll;
	}
}

char 
x2c(char *what)
{
	register char   digit;

	digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
	digit *= 16;
	digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
	return (digit);
}

void 
unescape_url(char *url)
{
	register int    x, y;

	for (x = 0, y = 0; url[y]; ++x, ++y)
	{
		if ((url[x] = url[y]) == '%')
		{
			url[x] = x2c(&url[y + 1]);
			y += 2;
		}
	}
	url[x] = '\0';
}

void 
plustospace(char *str)
{
	register int    x;

	for (x = 0; str[x]; x++)
		if (str[x] == '+')
			str[x] = ' ';
}

int 
rind(char *s, char c)
{
	register int    x;
	for (x = strlen(s) - 1; x != -1; x--)
		if (s[x] == c)
			return x;
	return -1;
}

int 
getline(char *s, int n, FILE * f)
{
	register int    i = 0;

	while (1)
	{
		s[i] = (char) fgetc(f);

		if (s[i] == CR)
			s[i] = fgetc(f);

		if ((s[i] == 0x4) || (s[i] == LF) || (i == (n - 1)))
		{
			s[i] = '\0';
			return (feof(f) ? 1 : 0);
		}
		++i;
	}
}

void 
send_fd(FILE * f, FILE * fd)
{
	int             num_chars = 0;
	char            c;

	while (1)
	{
		c = fgetc(f);
		if (feof(f))
			return;
		fputc(c, fd);
	}
}

/* coded by armian@www.kordic.re.kr */
int
ProcessGetMethod(entries)
getentry	*entries;
{
	char	*cl;
	int	x, m;

	if (strcmp(getenv("REQUEST_METHOD"), "GET"))
        {
                printf("This script should be referenced with a METHOD of GET.\n");
                printf("If you don't understand this, see this ");
                printf("<A HREF=\"http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/Docs/fill-out-forms/overview.html\">forms overview</A>.%c", 10);
                exit(1);
        }

        cl = getenv("QUERY_STRING");
        if ( strlen(cl) <= 0 )
        {
/*
                printf("No query information to decode.\n");
*/
                return -1;
        }

        for (x = 0; cl[0] != '\0'; x++)
        {
                m = x;
                getword(entries[x].val, cl, '&');
                plustospace(entries[x].val);
                unescape_url(entries[x].val);
                getword(entries[x].name, entries[x].val, '=');
        }

	return m;
}
