/*
 *                          P R O D U C E . C
 *
 *  implements the produce command
 *  -  create and show popup
 *  -  send data
 *  -  process answer
 *
 *  Version      : $Revision: 1.6 $
 *
 *  Created      : Fri Jun 24 23:57:09 1994
 *  Author       : Ulrich Drepper <drepper@mydec>
 *
 *  Last modified: Sat Jul 16 22:28:59 1994
 *  Author       : Ulrich Drepper <drepper@mydec>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 1, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */
#if !defined(lint)
static const char *vcid = "$Id: produce.c,v 1.6 1994/07/17 22:25:02 drepper Exp $";
#endif /* lint */

#include <assert.h>
#include <ctype.h>
#if defined(__sun__)
#include <memory.h>
#endif /* __sun__ */
#include <string.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Toggle.h>

#include "empire.h"

/*
 * prototypes of local functions
 */
static void commandInitProduce(void);
static void produceEditAdd(Bool active, XawTextBlock *textBlock, Bool async);
static void callbackProduce(Widget widget, XtPointer closure,
			    XtPointer callData);
static void produceNotify(Widget w, XEvent *event, String *params,
			  Cardinal *numParams);
static Bool processProduce(Bool first, Bool last, char *str, void *data);

/*
 * local variables
 */
static Widget producePopup;
static Widget form;
static Widget sectorText;
static Widget okButton;
static void (*oldEditAdd)(Bool, XawTextBlock *, Bool);

/*
 * exported functions
 */
void
queryCommandProduce(void)
{
    static Bool firstCall = True;
    Position fx, fy;
    Position x, y;

    if (firstCall) {
	commandInitProduce();
	firstCall = False;
    }

    XtVaGetValues(
	commandForm,
	XtNx, &fx,
	XtNy, &fy,
	NULL);

    XtVaGetValues(
	horizPane,
	XtNx, &x,
	XtNy, &y,
	NULL);

    XtTranslateCoords(
	topLevel,
	x+fx, y+fy,
	&x, &y);

    XtVaSetValues(
	producePopup,
	XtNx, x,
	XtNy, y,
	NULL);

    /* prepare edit widget communication */
    oldEditAdd = currentEditAdd;
    oldEditAdd(False, NULL, False);

    currentEditAdd = produceEditAdd;
    currentEditAdd(True, NULL, False);
    
    XawTextSetInsertionPoint(sectorText, 0);
    XtVaSetValues(
	sectorText,
        XtNstring, "",
        NULL);

    XtPopup(producePopup, XtGrabNonexclusive);
    XtAddGrab(showViewport, False, False);
}

Bool
produceCommand(int xMin, int yMin, int xMax, int yMax, Bool redisplay)
{
    int x, y;

    for (y=yMin; y<=yMax; y++) {
	for (x=xMin; x<=xMax; x++) {
	    memset(empire.map[MAP2ARR(x,y)].prodComm, 0, 4);
	}
    }
    
    return sendCmdStr(processProduce, (void*)redisplay, NULL,
 	              "production %d:%d,%d:%d\n", xMin, xMax, yMin, yMax);
}

/*
 * local functions
 */
static void
commandInitProduce(void)
{
    static String textTranslations = 
	"#override\n"
	"<Key>Return: produceNotify()\n"
	"<Key>Linefeed: produceNotify()\n"
	"Ctrl<Key>M: produceNotify()\n"
	"Ctrl<Key>J: produceNotify()\n";
    static XtActionsRec defaultAction[1] = {
	{ "produceNotify", produceNotify },
    };
    XtTranslations textTrans;
    Widget tmp;

    XtAppAddActions(appContext, defaultAction, 1);
    textTrans = XtParseTranslationTable(textTranslations);

    producePopup =  XtVaCreatePopupShell(
	"producepopupshell",
	topLevelShellWidgetClass,
	topLevel,
	NULL);
    form = XtVaCreateManagedWidget(
	"form",
	formWidgetClass,
	producePopup,
	NULL);
    tmp = XtVaCreateManagedWidget(
	"produce",
	labelWidgetClass,
	form,
	NULL);
    tmp = XtVaCreateManagedWidget(
	"sectorlabel",
	labelWidgetClass,
	form,
	NULL);
    sectorText = XtVaCreateManagedWidget(
	"sectortext",
	asciiTextWidgetClass,
	form,
	XtNeditType, XawtextEdit,
	XtNtranslations, textTrans,
	NULL);

    okButton = XtVaCreateManagedWidget(
	"OK",
	commandWidgetClass,
	form,
	NULL);
    XtAddCallback(
	okButton,
	XtNcallback, callbackProduce,
	(XtPointer)True);
    tmp = XtVaCreateManagedWidget(
	"Cancel",
	commandWidgetClass,
	form,
	NULL);
    XtAddCallback(
	tmp,
	XtNcallback, callbackProduce,
	(XtPointer)False);

    XtRealizeWidget(producePopup);
}

/* ARGSUSED */
static void
produceEditAdd(Bool active, XawTextBlock *textBlock, Bool async)
{
    assert(async==False);
    if (textBlock) {
	XtVaSetValues(
	    sectorText,
	    XtNstring, textBlock->ptr,
	    NULL);
	XawTextSetInsertionPoint(sectorText, strlen(textBlock->ptr));
    } else {
	XawTextDisplayCaret(sectorText, active);
	if (active) {
	    XtSetKeyboardFocus(form, sectorText);
	    XtSetKeyboardFocus(vertPane, sectorText);
	}
    }
}

static void
callbackProduce(Widget widget, XtPointer closure, XtPointer callData)
{
    XtPopdown(producePopup);

    currentEditAdd(False, NULL, False);
    currentEditAdd = oldEditAdd;
    oldEditAdd(True, NULL, False);
    
    if ((Bool)closure) {
	char *sector;
	int x1, y1, x2, y2;
	
	XtVaGetValues(
	    sectorText,
	    XtNstring, &sector,
	    NULL);

	if (strToRange(&sector, &x1, &y1, &x2, &y2)) {
	    produceCommand(x1, y1, x2, y2, True);
	}
    }
}

/* ARGSUSED */
static void
produceNotify(Widget w, XEvent *event, String *params,
	      Cardinal *numParams)
{
    XtCallActionProc(okButton, "set", NULL, NULL, 0);
    XtCallActionProc(okButton, "notify", NULL, NULL, 0);
    XtCallActionProc(okButton, "unset", NULL, NULL, 0);
}

/* ARGSUSED */
static Bool
processProduce(Bool first, Bool last, char *str, void *data)
{
#define PRODUCEHEADERLINES 3
    static dataLine = 0;
    static XRectangle rectangle;
    static needRedisplay = False;
    Bool redisplay = (Bool)data;
    int x, y;
    EmpireSector *sector;
    int tmp;
    char typeChar;
    float tmpFloat;
    char *pStart;

    if (first) {
	dataLine = 0;
	needRedisplay = False;
    }

    if (last) {
	if (redisplay && needRedisplay && dataLine > PRODUCEHEADERLINES) {
	    redisplaySectors(mapWidget, rectangle.x, rectangle.y,
			     rectangle.width, rectangle.height);
	}
	return True;
    }

    if (++dataLine<=PRODUCEHEADERLINES || !isspace(str[0])) return True;

    /* First info is coord */
    strToCoord(&str, &x, &y);

    /* combine to minimal rectangle */
    if (dataLine == PRODUCEHEADERLINES+1) {
	rectangle.x = x;
	rectangle.y = y;
	rectangle.width = x;
	rectangle.height = y;
    } else {
	rectangle.x = min(rectangle.x,x);
	rectangle.width = max(rectangle.width,x);
	rectangle.y = min(rectangle.y,y);
	rectangle.height = max(rectangle.height,y);
    }

    /* change to array base */
    x = MAP2ARRX(x);
    y = MAP2ARRY(y);

    /* we can access the sector */
    sector = &empire.map[x+y*empire.rowBytes];

    /* next is the designation */
    while (isspace(*str)) str++;
    typeChar = *str++;
    if (sector->typeChar != typeChar) {
	sector->typeChar = typeChar;
	sector->status = OwnSector;
	sector->typePixmap = getTypePixmap(x, y, OwnSector, False);
	needRedisplay = True;
    }

    /* get efficiency */
    strToInt(&str, &tmp);
    sector->eff = tmp;

    assert(*str == '%');
    str++;

    strToInt(&str, &tmp);        /* do we need wkfc ? */

    if (typeChar == 't' || typeChar == 'r' || typeChar == 'n') {
	strToFloat(&str, &tmpFloat);
	sector->useProd[3] = (int)(tmpFloat*100.0);   /* percent ! */
    } else {
	strToInt(&str, &sector->useProd[3]);
    }

    /* ignore all but first character- */
    while (isspace(*str)) str++;
    if (typeChar == 'r') {
	sector->prodComm[3] = 'z';
    } else if (typeChar == 'p') {
	sector->prodComm[3] = 'y';
    } else {
	sector->prodComm[3] = *str++;
    }
    while (!isspace(*str)) str++;

    strToFloat(&str, &tmpFloat);
    sector->prodEff = (int)(tmpFloat*100.0);   /* percent ! */

    /* next: cost.  but ignore $ */
    while (isspace(*str)) str++;
    assert(*str == '$');
    str++;
    strToInt(&str, &sector->cost);

    switch (typeChar) {
    case 'a':
    case 'g':
    case 'm':
    case 'o':
    case 'u':
	/* only total max */
	break;
    case '%':
    case 'b':
    case 'e':
    case 'j':
    case 'k':
    case 'l':
    case 'p':
	/* have one value */
	strToInt(&str, &sector->useProd[0]);
	sector->prodComm[0] = *str++;
	strToInt(&str, &sector->maxProd[0]);
	assert(*str == sector->prodComm[0]);
	str++;
	break;
    case 'i':
	/* has two values */
	strToInt(&str, &sector->useProd[0]);
	sector->prodComm[0] = *str++;
	strToInt(&str, &sector->useProd[1]);
	sector->prodComm[1] = *str++;
	strToInt(&str, &sector->maxProd[0]);
	assert(*str == sector->prodComm[0]);
	str++;
	strToInt(&str, &sector->maxProd[1]);
	assert(*str == sector->prodComm[1]);
	str++;
	break;
    case '*':
    case 'd':
    case 't':
    case 'r':
	/* has three values */
	strToInt(&str, &sector->useProd[0]);
	sector->prodComm[0] = *str++;
	strToInt(&str, &sector->useProd[1]);
	sector->prodComm[1] = *str++;
	strToInt(&str, &sector->useProd[2]);
	sector->prodComm[2] = *str++;
	strToInt(&str, &sector->maxProd[0]);
	assert(*str == sector->prodComm[0]);
	str++;
	strToInt(&str, &sector->maxProd[1]);
	assert(*str == sector->prodComm[1]);
	str++;
	strToInt(&str, &sector->maxProd[2]);
	assert(*str == sector->prodComm[2]);
	str++;
	break;
    default:
	assert(True == False);
    }
    
    if (typeChar == 't' || typeChar == 'r' || typeChar == 'n') {
	strToFloat(&str, &tmpFloat);
	sector->maxProd[3] = (int)(tmpFloat*100.0);   /* percent ! */
    } else {
	strToInt(&str, &sector->maxProd[3]);
    }

    return True;
}

/*
 * Local Variables:
 *  mode:c
 *  c-indent-level:4
 *  c-continued-statement-offset:4
 *  c-continued-brace-offset:0
 *  c-brace-offset:0
 *  c-imaginary-offset:0
 *  c-argdecl-indent:4
 *  c-label-offset:-2
 * End:
 */
