/* Some part of this file is Copyright (C) 1996 - G.Dauphin
 * See the file "license.mMosaic" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */ 

/* Copyright (C) 1998, 1999, 2004 - The VMS Mosaic Project */

#include "../config.h"
#include <Xm/TextF.h>
#include "HTMLP.h"
#include "HTMLPutil.h"
#include "../src/mosaic.h"
#include "HTMLform.h"
#include "../libnut/str-tools.h"

#ifndef DISABLE_TRACE
extern int reportBugs;
extern int htmlwTrace;
#endif


static void ProcessOption( SelectInfo *sptr);

/* Fillout forms.  Cannot be nested. */

/* </FORM> */
void EndForm(HTMLWidget hw, MarkInfo **mptr, PhotoComposeContext *pcc)
{
	if (!pcc->in_form || !pcc->cur_form) { /* It's an error */
		return;
	}

	if (pcc->cw_only) {
		pcc->in_form = False; /* Always put False on end Form */
				      /* because form cannot be nested */
		if (pcc->cur_form->cw_only) {
			if (pcc->cur_form->action)
				free(pcc->cur_form->action);
			if (pcc->cur_form->target)
				free(pcc->cur_form->target);
			if (pcc->cur_form->method)
				free(pcc->cur_form->method);
			if (pcc->cur_form->enctype)
				free(pcc->cur_form->enctype);
			free(pcc->cur_form);
		}
		pcc->cur_form = NULL;
		return;
	}

	/* Here we go to create it really */
	pcc->cur_form->end = pcc->widget_id;
	AddNewForm(hw, pcc->cur_form);
	pcc->cur_form = NULL;
	pcc->in_form = False; /* Always put False on end Form */
}

/* <FORM> */
void BeginForm(HTMLWidget hw, MarkInfo **mptr, PhotoComposeContext *pcc)
{
	MarkInfo *mark = *mptr;

	if (!pcc->cw_only && (pcc->in_form || pcc->cur_form)) {
#ifndef DISABLE_TRACE
		if (htmlwTrace || reportBugs) {
			fprintf(stderr, "Warning: A Form in Form!\n");
		}
#endif
		return;
	}

	/* Create a Form structure */
	pcc->cur_form = (FormInfo *)malloc(sizeof(FormInfo));
	pcc->cur_form->next = NULL;
	pcc->cur_form->hw = (Widget)hw;
	pcc->cur_form->action = ParseMarkTag(mark->start, MT_FORM, "ACTION");
	pcc->cur_form->target = ParseMarkTag(mark->start, MT_FORM, "TARGET");
	pcc->cur_form->method = ParseMarkTag(mark->start, MT_FORM, "METHOD");
	pcc->cur_form->enctype = ParseMarkTag(mark->start, MT_FORM, "ENCTYPE");
	pcc->cur_form->start = pcc->widget_id;
	pcc->cur_form->end = -1;
	pcc->cur_form->button_pressed = NULL;
	pcc->in_form = True;
	if (pcc->cw_only)
		pcc->cur_form->cw_only = 1;
	else
		pcc->cur_form->cw_only = 0;
}


/* Just insert the widget.  Can only be inside a FORM tag.
 * Special case the type=image stuff to become a special IMG tag.
 */
void FormInputField(HTMLWidget hw, MarkInfo **mptr, PhotoComposeContext *pcc)
{
	MarkInfo *mark = *mptr;
	char *tptr2, *tptr, *sptr;
	char *text;

	if (!pcc->in_form)		/* Error */
		return;

	text = mark->start;
	tptr = ParseMarkTag(text, MT_INPUT, "TYPE");

	if (tptr && pcc->cw_only && !my_strcasecmp(tptr, "image")) {
		/* Get width and height of image */
		ImagePlace(hw, *mptr, pcc);
		free (tptr);
		return;
	}

	if (!pcc->cur_form) {		/* Error */
		if (tptr)
			free (tptr);
		return;
	}

	if (!tptr) {
		WidgetPlace(hw, *mptr, pcc);
		return;
	} else if (caseless_equal(tptr, "image")) {
		sptr = ParseMarkTag(text, MT_INPUT, "NAME");
		free(tptr);
		tptr = (char *)malloc(strlen(mark->start) +
				strlen(" ISMAP") + strlen(MT_IMAGE) -
				strlen(MT_INPUT) + 1);
		strcpy(tptr, MT_IMAGE);
		strcat(tptr, (char *) (mark->start + strlen(MT_INPUT)));
		strcat(tptr, " ISMAP");
		tptr2 = mark->start;
		mark->start = tptr;
		ImagePlace(hw, *mptr, pcc);
		mark->start = tptr2;
		/* Save the NAME value so we know which image is which */
		if (sptr && mark->s_picd)
			mark->s_picd->text = sptr;
	} else if (caseless_equal(tptr, "hidden")) {
		/* Hidden inputs have no element associated with them,
		 * just a widget record. */
		pcc->widget_id++;
		(void)MakeWidget(hw, mark->start, pcc, pcc->widget_id);
	} else {
		WidgetPlace(hw, *mptr, pcc);
	}
	free(tptr);
}

/* TEXTAREA is a replacement for INPUT type=text size=rows,cols
 * name REQUIRED
 * rows REQUIRED
 * cols REQUIRED
 */             
void FormTextAreaBegin(HTMLWidget hw, MarkInfo **mptr, PhotoComposeContext *pcc)
{
	char *buf;
	int len;        
	MarkInfo *mark = *mptr;
	char *cptr, *rptr;
	char *text;
	int cols, rows;

	if (!pcc->in_form || !pcc->cur_form)		/* Error */
		return;

	text = (*mptr)->start;
	cols = 40;
	cptr = ParseMarkTag(text, MT_INPUT, "COLS");
	if (cptr) {
		cols = atoi(cptr);
		free(cptr);
	}
	if (cols <= 0)
		cols = 40;

	rows = 4; 
	rptr = ParseMarkTag(text, MT_INPUT, "ROWS");
	if (rptr) {
		rows = atoi(rptr);
		free(rptr);
	}
	if (rows <= 0)
		rows = 4; 

	if (!pcc->text_area_buf) {
		/* Construct the start of a fake INPUT tag. */
		len = strlen(MT_INPUT) + strlen(" type=textarea value=\"\"");
		buf = (char *)malloc(len + strlen(mark->start) + 1);
		strcpy(buf, MT_INPUT);
		strcat(buf, (char *) (mark->start + strlen(MT_TEXTAREA)));
		strcat(buf, " type=textarea");
		strcat(buf, " value=\"");
		pcc->text_area_buf = buf;  
		pcc->ignore = 1;    
	}                      
}

void FormTextAreaEnd(HTMLWidget hw, MarkInfo **mptr, PhotoComposeContext *pcc)
{
	MarkInfo *mark = *mptr;
	char *start;
	char *buf;

	if (!pcc->in_form || !pcc->cur_form || !pcc->text_area_buf)
		return;

	/* Finish a fake INPUT tag. */
	buf = (char *)malloc(strlen(pcc->text_area_buf) + 2); 
	strcpy(buf, pcc->text_area_buf);
	strcat(buf, "\"");
	/* Stick the fake in, saving the real one. */
	start = mark->start;
	mark->start = buf;
	mark->is_end = 0;
	WidgetPlace(hw, mark, pcc);
	/* Free the fake, put the original back */
	free(buf);
	free(pcc->text_area_buf);
	mark->start = start;
	mark->is_end = 1;
	pcc->text_area_buf = NULL;
	pcc->ignore = 0;
}


/* Can only be inside a SELECT tag. */
void FormSelectOptionField(HTMLWidget hw, MarkInfo **mptr,
        PhotoComposeContext *pcc)
{
	MarkInfo *mark = *mptr;
	char *tptr;

	if (!pcc->in_form || !pcc->in_select || !pcc->cur_form)	/* Error */
		return;

	if (pcc->current_select) {
		if (pcc->current_select->option_buf)
			ProcessOption(pcc->current_select);
		pcc->current_select->option_buf = (char *)malloc(1);
		strcpy(pcc->current_select->option_buf, "");
		/* Check if this option starts selected */
		tptr = ParseMarkTag(mark->start, MT_OPTION, "SELECTED");
		if (tptr) {
			pcc->current_select->is_value = 1;
			free(tptr);
		} else {
			pcc->current_select->is_value = 0;
		}       
		/* Check if this option has a different return value field. */
		tptr = ParseMarkTag(mark->start, MT_OPTION, "VALUE");
		if (tptr) {
			pcc->current_select->retval_buf = tptr;
		} else {       
			pcc->current_select->retval_buf = NULL;
		}              
	}                      
}

/* Special INPUT tag.  Allows an option menu or a scrolled list.
 * Due to a restriction in SGML, this can't just be a subset of
 * the INPUT markup.  However, can be treated that way to avoid duplicating
 * code.  As a result combine SELECT and OPTION into a faked up INPUT mark.
 */
void FormSelectBegin(HTMLWidget hw, MarkInfo **mptr, PhotoComposeContext *pcc)
{

	if (!pcc->in_form || !pcc->cur_form)	/* Error */
		return;

	if (!pcc->current_select) {
		pcc->current_select = (SelectInfo *)malloc(sizeof(SelectInfo));
		pcc->current_select->hw = (Widget)hw;
		pcc->current_select->mptr = *mptr;
		pcc->current_select->option_cnt = 0;
		pcc->current_select->returns = NULL;
		pcc->current_select->retval_buf = NULL;
		pcc->current_select->options = NULL;
		pcc->current_select->option_buf = NULL;
		pcc->current_select->value_cnt = 0;
		pcc->current_select->value = NULL;
		pcc->current_select->is_value = -1;
		pcc->ignore = 1;
	}                      
	pcc->in_select = True;
}

void FormSelectEnd(HTMLWidget hw, MarkInfo **mptr, PhotoComposeContext *pcc)
{
	char *start;
	int len;  
	char *buf;  
	char *options, *returns, *value;

	if (!pcc->in_form || !pcc->cur_form || !pcc->current_select)
		return;

        if (pcc->current_select->option_buf)
		ProcessOption(pcc->current_select);
	options = ComposeCommaList(pcc->current_select->options,
			pcc->current_select->option_cnt);
	returns = ComposeCommaList(pcc->current_select->returns,
			pcc->current_select->option_cnt);
	value = ComposeCommaList(pcc->current_select->value,
			pcc->current_select->value_cnt);
	FreeCommaList(pcc->current_select->options,
			pcc->current_select->option_cnt);   
	FreeCommaList(pcc->current_select->returns,
			pcc->current_select->option_cnt);
	FreeCommaList(pcc->current_select->value,
			pcc->current_select->value_cnt);
	/* Construct a fake INPUT tag. */
	len = strlen(MT_INPUT) + strlen(options) +
		strlen(returns) + strlen(value) + 
		strlen(" type=select options=\"\" returns=\"\" value=\"\"");
	buf = (char *)malloc(len + strlen(pcc->current_select->mptr->start) +1);
	strcpy(buf, MT_INPUT);
	strcat(buf, " type=select");
	strcat(buf, " options=\"");
	strcat(buf, options);
	strcat(buf, "\" returns=\"");
	strcat(buf, returns);
	strcat(buf, "\" value=\"");
	strcat(buf, value);
	strcat(buf, "\"");  
	strcat(buf, (char *) (pcc->current_select->mptr->start +
		strlen(MT_SELECT)));
	/* Stick the fake in, saving the real one. */
	start = pcc->current_select->mptr->start;
	pcc->current_select->mptr->start = buf;
	WidgetPlace(hw, pcc->current_select->mptr, pcc);
	/* Free the fake, put the original back */
	free(buf);
	free(options);
	free(returns);
	free(value);
	pcc->current_select->mptr->start = start;
	free((char *)pcc->current_select);
	pcc->current_select = NULL;
	pcc->ignore = 0;
	pcc->in_select = False;
}

/* <BUTTON> */
void FormButtonBegin(HTMLWidget hw, MarkInfo **mptr, PhotoComposeContext *pcc)
{

	if (!pcc->in_form || !pcc->cur_form)	/* Error */
		return;
}

/* </BUTTON> */
void FormButtonEnd(HTMLWidget hw, MarkInfo **mptr, PhotoComposeContext *pcc)
{
}

/* We've just terminated the current OPTION.
 * Put it in the proper place in the SelectInfo structure.
 * Move option_buf into options, and maybe copy into
 * value if is_value is set.    
 */     
static void ProcessOption( SelectInfo *sptr)
{       
        int i, cnt;             
        char **tarray;          
        
        clean_white_space(sptr->option_buf);
        tarray = sptr->options;
        cnt = sptr->option_cnt + 1;
        sptr->options = (char **)malloc(sizeof(char *) * cnt);
        for (i=0; i < (cnt - 1); i++)
                sptr->options[i] = tarray[i];
        if (tarray)
                free((char *)tarray);
        sptr->options[cnt - 1] = sptr->option_buf;
        sptr->option_cnt = cnt;
        tarray = sptr->returns;
        cnt = sptr->option_cnt;
        sptr->returns = (char **)malloc(sizeof(char *) * cnt);
        for (i=0; i < (cnt - 1); i++)
                sptr->returns[i] = tarray[i];
        if (tarray)
                free((char *)tarray);
	/* Use text string if no VALUE specified */
	if (sptr->retval_buf)
	        sptr->returns[cnt - 1] = sptr->retval_buf;
	else
		sptr->returns[cnt - 1] = sptr->option_buf;
        if (sptr->is_value) {
                tarray = sptr->value;
                cnt = sptr->value_cnt + 1;
                sptr->value = (char **)malloc(sizeof(char *) * cnt);
                for (i=0; i < (cnt - 1); i++)
                        sptr->value[i] = tarray[i];
                if (tarray)
                        free((char *)tarray); 
                sptr->value[cnt - 1] = (char *)malloc(
			strlen(sptr->option_buf) + 1);
                strcpy(sptr->value[cnt - 1], sptr->option_buf);
                sptr->value_cnt = cnt;
        }       
}        
