/* MPMorph - Amiga Morphing program */
/* Copyright (C) © 1993  Topicsave Limited */

/* 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 2 of the License, or */
/* 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. */

/* mpaddock@cix.compulink.co.uk */

#include "Render.h"

#include "a/Render.h"

extern long __stack = 16000;

/* Display help if available */
void
help(ULONG hnum) {
	if (handle) {
		SetAmigaGuideContextA(handle,hnum,NULL);
		SendAmigaGuideContextA(handle,NULL);
	}
}

void
CopyEGS(int line, UBYTE **er,UBYTE **eg,UBYTE **eb) {
	int j;
	UBYTE *plane;
	plane = ((struct E_EBitMapFull *)EGS_BitMap)->Typekey.PixelMap.Planes.Dest;
	for (j = 0; j<width; ++j) {
		*plane++ = *((*er)++);
		*plane++ = *((*eg)++);
		*plane++ = *((*eb)++);
		++plane;
	}
	EG_CopyBitMapRastPort(EGS_BitMap,EGS_Win->RPort,0,0,width,1,0,line);
}

static UWORD top = 0;

/* add a message to the progress list */
void
AddMessage(UBYTE *message) {
	struct Node *node;
	if ((node = (struct Node *)Mymalloc(sizeof(struct Node))) &&
		 (node->ln_Name = Mystrdup(message))) {
		if (!NoProgress) {
			GT_SetGadgetAttrs(ProgressGadgets[GDX_Info],ProgressWnd,NULL,
   	 						 GTLV_Labels, ~0,
   							 TAG_END);
   	}
		AddTail(&InfoList,node);
		if (!NoProgress) {
			GT_SetGadgetAttrs(ProgressGadgets[GDX_Info],ProgressWnd,NULL,
   	 						 GTLV_Labels, (ULONG)&InfoList,
    							 GTLV_Top, top,
   							 TAG_END);
   	}
  		top++;
	}
	if (PProgressHook) {
		CallHookPkt(PProgressHook,(APTR)3,(APTR)message);
	}
}

struct Hook ProgressHook = {
	0
};

ULONG __saveds __asm ProgressH(register __a0 struct Hook *hook,
								  register __a2 APTR *object,
								  register __a1 APTR *message) {
	switch ((int)object) {
	case (int)MPIP_MAX:
		if (!NoProgress) {
	  	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Line],ProgressWnd,NULL,
   	 							 GTSL_Max,(ULONG)message,TAG_END);
   	}
		if (PProgressHook) {
			CallHookPkt(PProgressHook,object,message);
		}
		break;
	case (int)MPIP_CURR:
		if (!NoProgress) {
	   	GT_SetGadgetAttrs(ProgressGadgets[GDX_Line],ProgressWnd,NULL,
     								GTSL_Level,(ULONG)message,TAG_END);
		}
		if (PProgressHook) {
			CallHookPkt(PProgressHook,object,message);
		}
		break;
	case (int)MPIP_MESSAGE:
		AddMessage((UBYTE *)message);
		break;
	default:
		break;
	}
	return 1;
}

void SetMaxFrame(int Frame) {
	if (!NoProgress) {
	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Frame],ProgressWnd,NULL,
 		 						 GTSL_Min,1,
  								 GTSL_Max,Frame,TAG_END);
	}
}

void SetFrame(int Frame) {
	if (!NoProgress) {
	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Frame],ProgressWnd,NULL,
 		 						 GTSL_Level,(ULONG)Frame,TAG_END);
	}
}

void SetMaxLine(int Line) {
	if (!NoProgress) {
	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Line],ProgressWnd,NULL,
 		 						 GTSL_Min,0,
  								 GTSL_Max,Line,TAG_END);
	}
	if (PProgressHook) {
		CallHookPkt(PProgressHook,(APTR)1,(APTR)Line);
	}
}

void SetLine(int Line) {
	if (!NoProgress) {
	   GT_SetGadgetAttrs(ProgressGadgets[GDX_Line],ProgressWnd,NULL,
 		 						 GTSL_Level,(ULONG)Line,TAG_END);
	}
	if (PProgressHook) {
		CallHookPkt(PProgressHook,(APTR)2,(APTR)Line);
	}
}

/* Frame clicked - irrelevant	*/
int
FrameClicked(void) {
	return 1;
}

/* Line clicked - irrelevant	*/
int
LineClicked(void) {
	return 1;
}

/* Routine for when Stop clicked	*/
int
StopClicked(void) {
   struct EasyStruct EasyStruct = {
      sizeof(struct EasyStruct),
      0,
      NULL,
      NULL,
      NULL,
   };
	UBYTE *title = "MPMorph-render";
	UBYTE *body = "Really quit?";
   struct Window *req;
   UBYTE *gad;
   ULONG ret = 2;
	struct AmigaGuideMsg *agm;
	ULONG signals=0;
	struct rtHandlerInfo *rth;
   /* Disable the window, display a requester and reenable the window */
   DisableWindow();
   if (ReqToolsBase) {
   	if (handle) {
			gad = "_Quit|_Help|_Continue";
   	}
   	else {
			gad = "_Quit|_Continue";
   	}
		while (ret == 2) {
			ret = CALL_HANDLER;
	   	if (rtEZRequestTags(body,gad,NULL,NULL,
   									RT_ReqHandler, &rth,
   									RT_Window, ProgressWnd,
   									RT_Underscore, '_',
   									RTEZ_ReqTitle, title,
   									TAG_END) == CALL_HANDLER) {
				while (ret == CALL_HANDLER) {
   				if (!rth->DoNotWait) {
   					signals = Wait(rth->WaitMask | ASig);
   				}
					ret = rtReqHandlerA(rth,signals,NULL);
		   		if (ret == 2) {
			   		help(H_Really);
			   	}
		   		if (signals & ASig) {
					  	while (agm = GetAmigaGuideMsg(handle)) {
				 			ReplyAmigaGuideMsg(agm);
				 		}
				 	}
				}
   		}
   		else {
   			ret = 0;
   		}
   	}
	}
	else {
		EasyStruct.es_TextFormat = body;
		EasyStruct.es_Title = title;
	   if (handle) {
   		EasyStruct.es_GadgetFormat = "Quit|Help|Continue";
	   }
   	else {
   		EasyStruct.es_GadgetFormat = "Quit|Continue";
	   }
		req = BuildEasyRequestArgs(ProgressWnd,&EasyStruct,NULL,NULL);
	   while ((ret = SysReqHandler(req,NULL,TRUE)) == 2) {
   		help(H_Really);
		  	while (agm = GetAmigaGuideMsg(handle)) {
	 			ReplyAmigaGuideMsg(agm);
	 		}
	   }
   	FreeSysRequest(req);
   }
   EnableWindow();
	return !ret;
}

/* Disables the Progress window
 * Disables the 'Stop' gadget and displays a wait pointer
 */
void
DisableWindow(void) {
	if (ProgressWnd) {
		GT_SetGadgetAttrs(ProgressGadgets[GDX_Stop],ProgressWnd,NULL,GA_Disabled,TRUE,TAG_END);
		SetWindowPointer(ProgressWnd, WA_BusyPointer, TRUE,
								WA_PointerDelay, TRUE,
								TAG_END);
	}
}

/* Enables the Progress window
 * Enables the 'Stop' gadget and clears the pointer
 */
void
EnableWindow(void) {
	if (ProgressWnd) {
		GT_SetGadgetAttrs(ProgressGadgets[GDX_Stop],ProgressWnd,NULL,GA_Disabled,FALSE,TAG_END);
		// Should enable for NoProgress
		SetWindowPointer(ProgressWnd,
								TAG_END);
	}
}

/* Display an error message
 * ErrorMessage	: The main text
 * Gadget			: Text for one gadget
 * extra				: more of the text
 * helpnum			: Number of a help node
 *
 * See the MPMorph source code for more of how this actually works
 */
void
Error(char *ErrorMessage,char *Gadget,char *extra,ULONG helpnum) {
   struct EasyStruct EasyStruct = {
      sizeof(struct EasyStruct),
      0,
      NULL,
      NULL,
      NULL
   };
   UBYTE *title = "MPMorph-render Error";
   struct Window *req;
   UBYTE gad[32] = "Help|";
   UBYTE gad1[32] = "_Help|_";
   ULONG ret = CALL_HANDLER;
	struct AmigaGuideMsg *agm;
	ULONG signals=0;
	struct rtHandlerInfo *rth;
	/* Disable the window and display the requester */
   DisableWindow();
   if (ReqToolsBase) {
   	if (!handle) {
			strcpy(gad1,"_");
   	}
		strcat(gad1,Gadget);
		while (ret) {
			ret = CALL_HANDLER;
	   	if (rtEZRequestTags(ErrorMessage,gad1,NULL,&extra,
   									RT_ReqHandler, &rth,
   									RT_Window, ProgressWnd,
   									RT_Underscore, '_',
   									RTEZ_ReqTitle, title,
   									TAG_END) == CALL_HANDLER) {
				while (ret == CALL_HANDLER) {
   				if (!rth->DoNotWait) {
   					signals = Wait(rth->WaitMask | ASig);
   				}
					ret = rtReqHandlerA(rth,signals,NULL);
		   		if (ret == 1) {
			   		help(helpnum);
			   	}
		   		if (signals & ASig) {
					  	while (agm = GetAmigaGuideMsg(handle)) {
				 			ReplyAmigaGuideMsg(agm);
				 		}
				 	}
				}
   		}
   		else {
   			ret = 0;
   		}
   	}
   }
   else {
		EasyStruct.es_TextFormat = ErrorMessage;
		EasyStruct.es_Title = title;
	   if (handle) {
   		strcat(gad,Gadget);
	   }
   	else {
   		strcpy(gad,Gadget);
	   }
		EasyStruct.es_GadgetFormat = gad;
		req = BuildEasyRequestArgs(ProgressWnd,&EasyStruct,NULL,&extra);
		while (ret) {
			signals  = Wait((1L << req->UserPort->mp_SigBit) | ASig);
			if (signals & (1L << req->UserPort->mp_SigBit)) {
   			ret = SysReqHandler(req,NULL,FALSE);
	   		if (ret == 1) {
		   		help(helpnum);
		   	}
		   }
	   	if (signals & ASig) {
			  	while (agm = GetAmigaGuideMsg(handle)) {
			 		ReplyAmigaGuideMsg(agm);
			 	}
			}
	   }
   	FreeSysRequest(req);
   }
   EnableWindow();
}

/* Tries to execute a Rexx script
 * msgtxt = name of script
 * IgnoreError = TRUE then do not display error message
 * Returns:	error message
 */
LONG
SendRxMsg(char *msgtxt,BOOL IgnoreError) {
	struct MsgPort *reply_port;
	struct MsgPort *rx_port;
	struct RexxMsg *rx_msg;
	LONG 				ret 			= RC_FATAL;
	BOOL				done = FALSE;
	ULONG				Signals;
	struct Message *msg;

	if (reply_port = CreateMsgPort()) {
   	if (rx_msg = CreateRexxMsg(reply_port,"MPM",myhost?myhost->portname:"REXX")) {
      	rx_msg->rm_Args[0] = msgtxt;
			if (FillRexxMsg(rx_msg,1,0)) {
				rx_msg->rm_Action = RXCOMM;
        		Forbid();
        		if (rx_port = (struct MsgPort *)FindPort("REXX")) {
          		PutMsg(rx_port, (struct Message *)rx_msg);
          		Permit();
          		while (!done) {
          			Signals = Wait((1L << reply_port->mp_SigBit) |
			          				   (myhost?(1L << myhost->port->mp_SigBit):0));
          			if (Signals & (1L << reply_port->mp_SigBit)) {
          				if (msg = GetMsg(reply_port)) {
          					ReplyMsg(msg);
          					done = TRUE;
          				}
          			}
						if (myhost && 
							 (Signals & (1L<<myhost->port->mp_SigBit))) {
							ARexxDispatch(myhost);
						}
					}
          		ret = rx_msg->rm_Result1;
		     	}
        		else {
          		Permit();
        		}
        		ClearRexxMsg(rx_msg, 1);
      	}
     		DeleteRexxMsg(rx_msg);
    	}
    	DeleteMsgPort(reply_port);
  	}
	/* Display an error message (if required) */
  	if (!IgnoreError && ret) {
  		Error("Error sending ARexx message\n'%s'","Quit",msgtxt,H_ARexx);
  	}
  	return ret;
}

/* Handle 'Help' key	*/
int
ProgressRawKey(void) {
	switch (ProgressMsg.Code) {
	case 0x5f:
		help(H_Help);
	}
	return 1;
}

long *GetRx(char *title) {
	if (!Stricmp(title,"frame")) {
		return &(Arexx.xf);
	}
	if (!Stricmp(title,"totalframes")) {
		return &(Arexx.xFrames);
	}
	if (!Stricmp(title,"single")) {
		return &(Arexx.xSingle);
	}
	if (!Stricmp(title,"movement")) {
		return &(Arexx.xmove);
	}
	if (!Stricmp(title,"red1")) {
		return &(Arexx.xr);
	}
	if (!Stricmp(title,"green1")) {
		return &(Arexx.xg);
	}
	if (!Stricmp(title,"blue1")) {
		return &(Arexx.xb);
	}
	if (!Stricmp(title,"red2")) {
		return &(Arexx.xr2);
	}
	if (!Stricmp(title,"green2")) {
		return &(Arexx.xg2);
	}
	if (!Stricmp(title,"blue2")) {
		return &(Arexx.xb2);
	}
	if (!Stricmp(title,"produce")) {
		return &(Arexx.xDo);
	}
	if (!Stricmp(title,"rplus")) {
		return &(Arexx.xrplus);
	}
	if (!Stricmp(title,"gplus")) {
		return &(Arexx.xgplus);
	}
	if (!Stricmp(title,"bplus")) {
		return &(Arexx.xbplus);
	}
	if (!Stricmp(title,"rminus")) {
		return &(Arexx.xrminus);
	}
	if (!Stricmp(title,"gminus")) {
		return &(Arexx.xgminus);
	}
	if (!Stricmp(title,"bminus")) {
		return &(Arexx.xbminus);
	}
	if (!Stricmp(title,"dx")) {
		return &(Arexx.xDX);
	}
	if (!Stricmp(title,"dy")) {
		return &(Arexx.xDY);
	}
	if (!Stricmp(title,"start")) {
		return &(Arexx.xStart);
	}
	return 0;
}
