/****************************************************************/
/*  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	<exec/types.h>
#include	<exec/tasks.h>
#include	<exec/ports.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/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	Library	*IntuitionBase;
struct	Library	*GfxBase;

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

extern	struct	tom_gadget	my_gadg[]; /* Array of gadget for window configuration */
extern	LONG	dark();			/* The main dark() function		*/
extern	void	proc_init();		/* The initialisation function		*/
extern	void	proc_end();		/* The end function			*/
extern	char	*p_text_info;		/* The text information, show in the    */
					/* info window				*/
void	wait_end();
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
*/

#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 old function should not be used now...			*/
/****************************************************************/

int	find_res(USHORT flg_depth,SHORT *p_depth,SHORT *p_tx,SHORT *p_ty,ULONG *p_d_id)
{
 struct ModeNode *ModeNode;
 struct ModeNode *ModeNodeFound;

 ModeNode=(struct ModeNode *)p_data_proc->ml->lh_Head;
 ModeNodeFound=ModeNode;

 while (ModeNode->mn_Node.ln_Succ)
  {
	if(flg_depth){
		if(*p_depth<ModeNode->MaxDepth){
			*p_depth=ModeNode->MaxDepth;
			if(*p_tx<=ModeNode->MaxX){
				*p_tx=ModeNode->MaxX;
				if(*p_ty<=ModeNode->MaxY){
					*p_ty=ModeNode->MaxY;
				}
			}
			ModeNodeFound=ModeNode;
		}
	}else{
		if(*p_tx<=ModeNode->MaxX){
			*p_tx=ModeNode->MaxX;
			if(*p_ty<=ModeNode->MaxY){
				*p_ty=ModeNode->MaxY;
				if(*p_depth<ModeNode->MaxDepth){
					*p_depth=ModeNode->MaxDepth;
				}
			}
			ModeNodeFound=ModeNode;
		}
	}
	ModeNode=(struct ModeNode *)ModeNode->mn_Node.ln_Succ;
  }
  *p_depth=ModeNodeFound->MaxDepth;

  *p_tx=ModeNodeFound->MaxX;
  *p_ty=ModeNodeFound->MaxY;

  *p_d_id=ModeNodeFound->DisplayID;

  return TRUE;
}

/*******************************************************************/
/* 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;

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

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

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

_main(line)
register	char	*line;
{
    struct	MsgPort	*mp;
    LONG	code_ret;
    int		signal;

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

   IntuitionBase=(struct Library *)OpenLibrary("intuition.library",0);
   GfxBase=(struct Library *)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);

	do{

		/* We are waiting for a signal from superdark...		*/
		/* SIG_MAIN_DARK_DO_DARK mean start to blank screen	*/
		/* SIG_BREAKF_CTRL_C	mean stop the blank		*/
		/* SIG_MAIN_DARK_EXIT	mean exit from this module	*/

		signal=Wait(SIG_MAIN_DARK_DO_DARK|SIG_MAIN_DARK_EXIT|SIGBREAKF_CTRL_C);
		SDprintf("Signal:%lx\n",signal);
		if((signal&SIG_MAIN_DARK_DO_DARK)!=0){
			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					  */

			Signal(my_t->tc_UserData,SIG_DARK_MAIN_STOPPED);
		}
		if(signal&SIGBREAKF_CTRL_C){
			Signal(my_t->tc_UserData,SIG_DARK_MAIN_STOPPED);
		}
	}while((signal&SIG_MAIN_DARK_EXIT)==0);
	proc_end();
	SDprintf("Signal Exit..\n");
     }
    CloseLibrary(IntuitionBase);
    CloseLibrary(GfxBase);
    return 0;
}

/****************************************/
/* 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_BACKDROP|WFLG_BORDERLESS|WFLG_ACTIVATE,
				TAG_DONE);
	if(win){
		ClearPtr(win);
   	}
	return(win);
}

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

int	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	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()
{
	SDwait(0);
}
