/****************************************************************/
/*  File proc_main.c						*/
/*								*/
/*  For superdark project					*/
/*								*/
/* This file have to be linked with evry superdark module. The  */
/* main function make various initialisation, test if superdark */
/* is here, wait for a signal from superdark and then call the	*/
/* dark() function. Read the programmers.doc for more  info.	*/
/*								*/
/*    @Thomas Landspurg 93					*/
/*								*/
/****************************************************************/
/*  17/06/93 : v2.0  CPU timeout information added		*/
/*  20/06/93 : v2.1  SDwait() function added, and SDprintf()	*/
/*                   A 'could be a bug later' removed: sd watch.*/
/*		     can be stopped if the effect was not start.*/
/*		     before					*/
/*								*/
/****************************************************************/

#include	<stdio.h>
#include 	<stdlib.h>
#include	<exec/types.h>
#include	<exec/tasks.h>
#include	<exec/ports.h>
#include	<exec/memory.h>
#include	<graphics/displayinfo.h>
#include	<exec/tasks.h>
#include	<dos/dosextens.h>

#include	<proto/exec.h>
#include	<proto/dos.h>
#include	<proto/graphics.h>
#include	<proto/intuition.h>

#include	"/includes/proc_main_protos.h"
#include	"/includes/struct.h"
#include	"/includes/tom_gadget.h"

#define	VERSION	2

WORD	flg_ctrl_c;
struct	my_data	*p_info;		/* Private use			      */
struct	appel_proc	*p_data_proc;	/* Communication structure with SDark */
struct	Task	*my_t;


struct	MsgPort		*MyPort=NULL;
struct	BlankerMsg	*MyMsg=NULL;

/***********************************************************/
/* These information SHOULD be give by the blanking module */
/***********************************************************/

extern	struct	tom_gadget	my_gadg[]; /* Array of gadget for window configuration */
extern	char	*p_text_info;		/* The text information, show in the    */
					/* info window				*/
void	MyWrite(char	*pc);

UWORD	__chip null_pointer[]={0,0,0,0,0,0};
BPTR	hd=0;
char	pr_buff[100];

/* Note: The folloing SPrintF Routine is taken from the program "FracBlank " */
/* by:									     */UWORD PutChar[2] = {0x16C0,0x4E75};

/* dirty hack to avoid assembler part :-)
   16C0: move.b d0,(a3)+
   4E75: rts
*/
struct	MsgPort	*mp;

#define VOID_STDARGS   void __stdargs

/************************************************************************/
/* This exactly the same function than printf, but printf() can't be	*/
/* used in a blanker. Use the utility program show_info to see the result */
/* NOTE: Always use long with number, like %ld,%lx and NOT %x or %d	*/
/************************************************************************/

VOID_STDARGS SDprintf(char *FormatString,...)

{
	char	buffer[100];
	if(hd){
		RawDoFmt (FormatString,(APTR)((LONG *)&FormatString+1L),
        	   (void *)PutChar,buffer);
		MyWrite(buffer);
	}
}

/************************************************************************/
/* Some variouse function used for debugging..use them at your own risk	*/
/* but do not use any printf function					*/
/************************************************************************/

VOID_STDARGS SPrintF(char *pr_buff,char *FormatString,...)

{
 RawDoFmt (FormatString,(APTR)((LONG *)&FormatString+1L),
           (void *)PutChar,pr_buff);
}

/************************************************************************/

mystrlen(char	*pc)
{
	int	ret;
	ret=0;
	while(*pc++!=0){
		ret++;
	}
	return	ret;
}

/************************************************************************/

void	MyWrite(char	*pc)
{
	if(hd!=0)Write(hd,pc,mystrlen(pc));
}
void	My_Print(struct RastPort *rp,UWORD x,UWORD y,char	*pc)
{
	Move(rp,x,y);
	Text(rp,pc,mystrlen(pc));
}


/*******************************************************************/
/* This function is used instead of CloseScreen, because if we are */
/* in the random mode, we don't close immediatly the screen, but   */
/* we give it back to superdark, so he can use it to create next   */
/* screen							   */
/*******************************************************************/

void	DCloseScreen(struct Screen *s)
{
	struct  Screen *st;

	if(mp!=0){
		st=p_data_proc->scr;
	}else{
		st=NULL;
	}
	if(st!=NULL){
		while(st->FirstWindow)CloseWindow(st->FirstWindow);
		CloseScreen(st);
		p_data_proc->scr=NULL;
	}

	if((mp!=NULL)&&(p_info->flg_alea==TRUE)){
		p_data_proc->scr=s;
	}else{
	    if(s){
		while(s->FirstWindow)CloseWindow(s->FirstWindow);
		CloseScreen(s);
		if(mp)p_data_proc->scr=NULL;
	   }
	}
}

/*******************************************************************/
/* this is used to put say to superdark what is the current screen */
/* struct. So, superdark can put it back even if the effect is not */
/* yet finished. This happen when the module have somehting long   */
/* to do (loading image) and the user want to throw the blanker    */
/*******************************************************************/

void	DGiveScreen(struct Screen *s)
{
	p_data_proc->current_scr=s;
}
/****************************************************************/

void main(void)
{
    struct 	Message *MsgExit=NULL;
    LONG	code_ret;
    int		signal;
    BOOL	Flg_Exit;
    ULONG	sigport;

   /****************************************************************/
   /* Look for the msg port wich contain informaion about superdark*/
   /****************************************************************/

   IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0);
   GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0);

   /* If superdark is not here, we start the blanker alone...Be careful! */
   if((mp=FindPort("That's Dark!"))==0){
		dark();
   }else{
	/*********************************************/
	/* Give and get some info to/from SuperDark  */
	/*********************************************/
	p_data_proc=(struct appel_proc *)mp;
	p_info=p_data_proc->p_info;
	hd=p_data_proc->out_hd;
	p_data_proc->p_gadg=my_gadg;
	p_data_proc->p_texte=p_text_info;
	p_data_proc->type_screen=SCR_OWN;/* By default, we create our own screen */
					 /* can be changed in the proc_init fct  */
	p_data_proc->enable_watchdog=TRUE;
					/* By default, CPU timeout (watchdog) is */
					/* enabled. Can be chaged in proc_init() */
	p_data_proc->proc_main_ver=VERSION;
					/* proc_main version...			*/
	proc_init();			/* Call the program initialisation	*/

	/* Note, this will be used by superdark to see if the module	*/
	/* is started							*/
	if(p_data_proc->code_ret==-1){
		p_data_proc->code_ret=DARK_WB_13;
	}

	my_t=FindTask(0);
	MyWrite("Avant le do\n");
	SPrintF(pr_buff,"Tache mt:%lx\n",my_t);
	MyWrite(pr_buff);

     	MyPort = CreatePort( 0, 0 );
	MyMsg = AllocMem( sizeof( struct BlankerMsg ), MEMF_PUBLIC|MEMF_CLEAR );
	if(MyPort&&MyMsg){
    
	MyMsg->Msg.mn_ReplyPort = MyPort;
	MyMsg->Msg.mn_Length = sizeof( struct BlankerMsg );
	MyMsg->Blanker_Task  = my_t;

	PutMsg( mp, ( struct Message * )MyMsg );

	sigport=1<<MyPort->mp_SigBit;    
	Flg_Exit=FALSE;
	do{

		signal=Wait(sigport|SIGBREAKF_CTRL_C|SIG_MAIN_DARK_WATCHDOG);

		SDprintf("Signal:%lx\n",signal);
		if(signal&sigport){
			while(MyMsg=(struct BlankerMsg *)GetMsg(MyPort)){
				Type_Action	Action;
				Action=MyMsg->Action;
				SDprintf("Message recu,actiob:%ld\n",MyMsg->Action);
			
				switch(Action){
					case	DO_DARK:

						ReplyMsg((struct Message *)MyMsg);
						SDprintf("Signal dark...\n");
						/* Clear old CTRL_C */
						SetSignal(0,SIGBREAKF_CTRL_C);
						flg_ctrl_c=FALSE;

						/* The main call to the dark() function  */
						code_ret=dark();

						/* Note: this code ret is a new thing since V2.0 */
						/* So try to put a return code in your dark()	 */
						/* function,0 if OK, Non zero if error		 */
						p_data_proc->code_ret=code_ret;

						SDprintf("Result:%ld\n",flg_ctrl_c);
						/* If there was an error, wait for the end */
						if(flg_ctrl_c==FALSE)wait_end();
						wait_end();
						MyWrite("ctrl-C receive,dark exited\n");

						/* We have to tell superdark that we have stopped */
						/* the effect					  */
						break;
					case	DO_STOP:
						ReplyMsg((struct Message *)MyMsg);
						break;

					case	DO_EXIT:
						proc_end();
						Flg_Exit=TRUE;
						MsgExit=MyMsg;
						break;
				}
			}
		}
		if(signal&SIG_MAIN_DARK_WATCHDOG){
			p_data_proc->flg_watchdog--;
			SetSignal(0,SIG_MAIN_DARK_WATCHDOG);
		}

	}while(Flg_Exit==FALSE);
	SDprintf("Signal Exit..\n");
	if(MsgExit)ReplyMsg((struct Message *)MsgExit);
	if(MyPort)DeletePort(MyPort);
     }
    }
    CloseLibrary((struct Library *)IntuitionBase);
    CloseLibrary((struct Library *)GfxBase);
}

/****************************************/
/* This function put a null pointer in	*/
/* in a window				*/
/****************************************/

void	ClearPtr(struct Window *win)
{
	SetPointer( win, null_pointer, 1, 1, 0, 0);
}

/************************************************************/
/* This function add a background window in a given screen, */
/* and add a null pointer in this window.		    */
/************************************************************/

struct	Window	*AddWindow(struct Screen *s)
{
     struct Window *win;
     win=OpenWindowTags(	NULL,
				WA_Left,	0,
				WA_Top,		0,
				WA_Width,	s->Width,
				WA_Height,	s->Height,
				WA_CustomScreen,s,
				WA_Flags,	WFLG_SIMPLE_REFRESH|WFLG_BORDERLESS|WFLG_ACTIVATE,
				TAG_DONE);
	if(win){
		ClearPtr(win);
   	}
	return(win);
}

/**************************************************/
/* This function return TRUE if you have to stop, */
/* FALSE elsewehre.				  */
/**************************************************/

int	__saveds tst_end()
{
	ULONG	sig;

	
	sig=SetSignal(0,0);
	if(sig&SIGBREAKF_CTRL_C){
		flg_ctrl_c=TRUE;
		return TRUE;
	}else{
		if(sig&SIG_MAIN_DARK_WATCHDOG){
			p_data_proc->flg_watchdog--;
			SetSignal(0,SIG_MAIN_DARK_WATCHDOG);
		}

		return FALSE;
	}
}

/****************************************************************/
/* Like the exec Wait() function, but take care of the internal */
/* superdark usage. If the return value is exactly 0, this mean */
/* that you have to exit of the blanker				*/
/****************************************************************/

ULONG	__saveds SDwait(ULONG sigmask)
{
	ULONG	sig;

	/* If we have already a ctrl_c,  send a new ctrl_C, to prevent	*/
	/* a deadlock if dark() does not use correctly this fct		*/

	if(flg_ctrl_c){
		Signal(my_t,SIGBREAKF_CTRL_C);
	}
	do{
		sig=Wait(SIGBREAKF_CTRL_C|SIG_MAIN_DARK_DO_DARK|SIG_MAIN_DARK_WATCHDOG|sigmask);
		if(sig&SIG_MAIN_DARK_WATCHDOG){
			p_data_proc->flg_watchdog--;
		}
	}while( (sig&(SIGBREAKF_CTRL_C|sigmask))==0);
	if(sig&SIGBREAKF_CTRL_C){
		flg_ctrl_c=TRUE;
	}
	return(sig&sigmask);
}

/**********************************************************/
/* This function only return, when superdark have to exit */
/**********************************************************/

void	wait_end(void)
{
	SDwait(0);
}
