/************************************************************************/
/*									*/
/*	File main.c							*/
/*									*/
/************************************************************************/
/*  This is the main entry point of SuperDark. Open all the ressources, */
/* and call the other function. Also look for all the availables	*/
/* modules and launch them						*/
/*									*/
/************************************************************************/

#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/ports.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>
#include <libraries/reqtools.h>
#include <clib/exec_protos.h>
#include <graphics/displayinfo.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <clib/dos_protos.h>
#include <workbench/startup.h>
#include "/includes/struct.h"
#include "/includes/tom_gadget.h"
#include "gid_main.h"

#ifndef	WB_13
struct	Library *CxBase;
#endif
struct	Library	*GadToolsBase;
struct	Library	*IconBase;
struct	Library	*IntuitionBase;
struct	Library	*GfxBase;
struct	Library	*CxBase;
struct	ReqToolsBase *ReqToolsBase;

extern	struct my_data	my_info;
extern	struct	tom_gadget	my_gadg[];
extern	struct	tom_gadget	gadg_alea[];


#define	STRLEN_DARK	5		/* Equivalent to strlen(".dark") */
struct	contexe	big_ctx;

/* Structure qui sauvegarde les parametres */

int	selection=-1;			/* Numero de l'effet selectionne */
int	last_sel=-1;			/* dernier numero selecitonne	 */
BPTR	segment=0;
int	flg_end;			/* Drapeau indiquant la sortie du prog */
UBYTE	flg_debug=FALSE;
char	*p_name;
UBYTE	flg_prog_dark;
UBYTE	flg_port_created;
struct	WBStartup	my_msg;

struct	Process	*process;
extern	struct	appel_proc	data_proc;
char	p_dark[]="That's Dark!";
int	nb_module=0;
char	*p_nom[MAX_NOM];
struct	Node ModulesNodes[MAX_NOM];
struct	List	*mode_liste;

#define	RANDOM	"Random"

char	*p_alea=RANDOM;
struct	Node alea_node={0,0,0,0,
RANDOM};
BPTR	old_lock=-1;
struct	MsgPort	*rep=0;
char	buffer[256];
extern	char	buffer_effet[];
LONG	dir_save=0;

char	p_ver[]="\0$VER: SuperDark  1.5 (30/03/93)";

struct List ModulesList = {
	( struct Node * )&ModulesList.lh_Tail,
	( struct Node * )0l,
	( struct Node * )&ModulesList.lh_Head,0,0 };
BPTR	global_lt=0;

/*********************************************************** aff_error() */

void	aff_error(char *p_texte)
{
	affiche_texte(p_texte,NULL,NULL);

}

/************************************************************ set_ext() */
/* remove evrything */
void	stop()
{
	big_ctx.flg_end=TRUE;
}
/************************************************************ set_ext() */
/* open window */
void	show()
{
	show_win(&big_ctx);
}

/************************************************************ set_ext() */

void	set_ext(char *pc)
{
	pc[strlen(pc)]='.';
}

/************************************************************ unset_ext() */

void	unset_ext(char *pc)
{
	pc[strlen(pc)-STRLEN_DARK]=0;
}

/************************************************************ fin_mod() */

/*****************************************************/
/* This function look for the availables modules in: */
/*   - the directory saved in the .info file as a    */
/*     tool type				     */
/*   - then look in the current directory	     */
/*****************************************************/

int	find_mod(char *name_dir) 
{
	struct Process *process;
	int	flg_err;
	int	etape,i,len;
	struct	FileInfoBlock	*fib;
	char	*pc;
	UBYTE	flg_deuxieme_passe;
	BPTR	lt;

	flg_err=FALSE;
	etape=0;
	lt=0;
	fib=0;
	flg_deuxieme_passe=FALSE;
        process = (struct Process *)FindTask(0);
	do{
		printd("find mod,etape:%ld\n",etape);
		switch(etape){
			case	0:
				/* Allocation memoire pour le FileInfo Block	*/
				/* Je rapelle aue le fib doit etre aligne sur	*/
				/* un mot long....merci les BPTR			*/
				if(fib==0){
					if((fib=(struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),0))==0){
						flg_err=TRUE;
					}
				}
				break;
			case	1:

				/* On cherche dans le repertoire passe dans le	*/
				/* .info, si celui -ci existe..			*/

				if(name_dir!=0){
				   if(*name_dir!=0){
					len=strlen(name_dir);
					if(name_dir[len-1]=='/'){
						name_dir[len-1]=0;
					}
					lt=Lock(name_dir,ACCESS_READ);
					global_lt=lt;
					if(lt!=0){
						old_lock=CurrentDir(lt);
						printd("new dir ok %lx old:%lx\n",lt,old_lock);
					}else{
						printd("Lock de %s failed!\n",name_dir);
					}
				   }
				}
				break;

			case	2:
				/* Si on n'a pas reussi a locke le repertoire donne */
				/* on cherche dans le repertoire courant 	    */
				if(lt==0){
					flg_deuxieme_passe=TRUE;
					lt=process->pr_CurrentDir;
					if(lt==0){
						flg_err=TRUE;
						aff_error("Erreur avec current dir");
					}
				}
				break;
			case 3:
				/* On examine le repertoire */
				printd("Avant le examine:lt:%lx fib:%lx\n",lt,fib);
				if(Examine(lt,fib)==0){
					aff_error("Erreur examine....\n");
					flg_err=TRUE;
				}
				break;
			case 4:
				/* On examine d'abord les fichiers	*/
				while(ExNext(lt,fib)!=NULL){
					
					if(fib->fib_DirEntryType<0){
					    if(strlen(fib->fib_FileName)>5){
						pc=fib->fib_FileName+strlen(fib->fib_FileName)-5;
						/* This is the correction of the 'Usnet' */
						/* bug....so superdark if case indepdt.  */
						if(stricmp(pc,".dark")==0){
							if(nb_module<MAX_NOM-1){
								pc=(char *)malloc(strlen(fib->fib_FileName)+1);
								p_nom[nb_module]=pc;
								strcpy(pc,fib->fib_FileName);
								unset_ext(pc);
								nb_module++;
							}else{
								SPrintF(buffer,"ERROR:Max number of modules exceded(%ld)\n",MAX_NOM);
								aff_error(buffer);
							}
						}
					}
				   }
				}
				break;
			case 5:
				/* Si on n'avait trouve aucun module, on re-essaye */
				/* une deuxieme fois dans le repertoire courant	   */

				if((nb_module==0)&&(flg_deuxieme_passe==FALSE)&&(lt!=0)){
					printd("Deuxieme passage:lt:%x,old_lock:%x\n",lt,old_lock);
					CurrentDir(lt);
					printd("Je fais un CurrentDir....new:%lx\n",lt);
					lt=0;
					etape=2-1;
				}
				break;

		}
		etape++;
	/* Tant qu'il y a des etapes a effectuer	*/
	}while((etape<6)&&(flg_err==FALSE));

	if(nb_module!=0){

		tqsort(p_nom,nb_module);

		p_nom[nb_module]=p_alea;

		for(i=0;i<nb_module;i++){
			ModulesNodes[i].ln_Name=p_nom[i];
			ModulesNodes[i].ln_Type=0;
			AddTail(&ModulesList,&ModulesNodes[i]);
			if(strcmp(p_nom[i],buffer_effet)==0){
				selection=i;
			}
		}

		AddTail(&ModulesList,&alea_node);
		my_info.tempo_end=10;

		if(selection==-1){
			my_info.flg_alea=TRUE;
			selection=nb_module;
		}
		my_gadg[GID_MODULES].value=selection;
	}else{
/*
		flg_err=1;
*/
		if(name_dir!=0){
			SPrintF(buffer,"No dark modules was found in the dir:\n\n%s\n\nHave you put the good directory in the\nTool type DARK DIRECTORY ?\n",name_dir);
		}else{
			SPrintF(buffer,"No dark modules was found!\nHave you put the good directory in the\nTool type DARK DIRECTORY ?\n",name_dir);
		}
		if(old_lock!=-1){
			printd("je remt old_lock:%lx\n",old_lock);
			CurrentDir(old_lock);
		}
		aff_error(buffer);
		selection=-1;
		my_info.flg_alea=FALSE;
	}

	if(fib!=0){
		FreeMem(fib,sizeof(struct FileInfoBlock));
	}
	my_gadg[GID_MODULES].d2=nb_module;
	return(flg_err);
}

/************************************************************ init_port *****/

int	init_port()
{
	struct	MsgPort	*mp;
	struct	appel_proc *ap;

	srand(VBeamPos());
	my_info.sigstart=-1;
	my_info.sigshow=-1;
	my_info.sigstop=-1;
	my_info.signext=-1;
	rep=(struct MsgPort *)CreatePort("Reponse",NULL);
	my_info.flg_alea=FALSE;
	flg_port_created=FALSE;
	if((ap=(struct appel_proc *)FindPort(p_dark))==0){
		mp=&data_proc.mp;
		mp->mp_Node.ln_Name=p_dark;
		mp->mp_Node.ln_Pri=0;
		mp->mp_Node.ln_Type=NT_MSGPORT;
		mp->mp_Flags=PA_IGNORE;
		AddPort(&data_proc.mp);	

		my_info.tempo=100;
		data_proc.p_info=&my_info;
		flg_port_created=TRUE;

		return(FALSE);
	}else{
		printd("Dark deja demarre!\n");

		/**********************************/
		/* On force la fenetre a s'ouvrir */
		/**********************************/
#ifdef	WB_13
		/* En 1.3, sans commodities, on envoi le signal a l'autre */
		/* tache et on sort					  */
		Signal(ap->p_info->task,1<<(ap->p_info->sigshow));
		return(TRUE);
#else
		/* en 2.0, l'autre blanker recevral e msg UNIQUE, et celui */
		/* (le nouveau) sortira lors du CxBroker		   */
		return(FALSE);
#endif
	}
}

/************************************************************ remove_seg() ***/
void	remove_seg()
{
	if(segment!=0){
		Signal(&process->pr_Task,SIG_MAIN_DARK_EXIT);
		WaitPort(rep);
		GetMsg(rep);
		UnLoadSeg(segment);
		segment=0;
		last_sel=-1;
		printd("Segment removed....\n");
	}
}
/*************************************************************** free_mod() **/
void	free_mod()
{
	int	i;
	for(i=0;i<nb_module;i++){
		free(p_nom[i]);
	}
	while(RemHead(&ModulesList));
	nb_module=0;
	remove_seg();
	if(global_lt){
		UnLock(global_lt);
		global_lt=0;
	}
}

/*************************************************************** do_dark() **/

void	do_dark()
{
	int	num_module;
	struct	Task	*mt;
	int	i;
	char	*pc;

	if(((last_sel!=selection)||(segment==0))&&(nb_module!=0)){
		remove_seg();
		num_module=selection%nb_module;
		last_sel=selection;

		data_proc.p_texte=0;
		pc=p_nom[num_module];
		set_ext(pc);
		printd("Je charge le %ld qui est:[%s]\n",num_module,pc);
		segment=LoadSeg(pc);

		if(segment!=0){
	
			/************************************************/
			/* We create a new task, with a given taskpri	*/
			/* Note: be carefull, the processe struct is not*/
			/* at the same adresse than the task struct.	*/
			/* Note2: The task is created with a high	*/
			/* priority, but this priority is changed just	*/
			/* after.					*/
			/************************************************/

			process=(struct Process *)((char *)CreateProc(pc,
							0,
							segment,
							8192)-sizeof(struct Task));
			mt=FindTask(0);
			my_msg.sm_Message.mn_ReplyPort=&data_proc.mp;
			my_msg.sm_Message.mn_ReplyPort=rep;

			my_msg.sm_ToolWindow=0;
			my_msg.sm_ArgList=0;
			my_msg.sm_NumArgs=0;
			process->pr_Task.tc_UserData=mt;
			my_info.task_dark=&process->pr_Task;
			PutMsg(&process->pr_MsgPort,(struct Msg *)&my_msg);
	
			/***********************************************************/
			/* On positionne le code retour, et on attend qu'il change */
			/* d'etat, indiquant que l'init est OK. On ne peut pas     */
			/* de 'meilleur' type de communication, car on n'est pas   */
			/* sur que c'est un module pour dark, et on risquerqais    */
			/* alors de bloquer en attente de reponse		   */
			/***********************************************************/
	
			i=500;
			data_proc.code_ret=-1;
			flg_prog_dark=TRUE;
/*			while((data_proc.code_ret==-1)&&(i-->0)){*/
			while(data_proc.code_ret==-1){
				Delay(1);
			}
			if(data_proc.code_ret==-1){
				aff_error("ERROR:This is not a Dark Module!\n");
				flg_prog_dark=FALSE;
			}else{
				printd("Loading conf\n");
				LoadConfig(p_nom[num_module],data_proc.p_gadg);
			}
#ifdef	WB_13
			/* Si c'est un module qui a besoin du WB2.0 */
			/* il ne faut pas l'executer...		    */
			if((data_proc.code_ret==DARK_WB_20)){
				aff_error("This one need 2.0 to run!\n");
				flg_prog_dark=FALSE;			
			}
#endif
		}else{
			aff_error("segment not found\n");
			selection=-1;
		}
		unset_ext(pc);
	}
}

/*********************************************** Liberation des ressources **/

void	free_all()
{
	remove_seg();
	if(flg_port_created)RemPort(&data_proc.mp);
	if(rep)DeletePort(rep);

	free_input_ev();
	CleanStuff_gadg(&big_ctx);
	if(old_lock!=-1){
		CurrentDir(old_lock);
	}
	if(mode_liste!=0)free_modes(mode_liste);
	free_mod();
	if(IconBase)CloseLibrary(IconBase);
#ifndef	WB_13
	if(CxBase)CloseLibrary(CxBase);
	if(GadToolsBase)CloseLibrary(GadToolsBase);
#endif
	if(IntuitionBase)CloseLibrary(IntuitionBase);
	if(GfxBase)CloseLibrary(GfxBase);
	if(ReqToolsBase)CloseLibrary ((struct Library *)ReqToolsBase);
}

/************************************************************ main     *****/

/************************************************/
/* main function. Open the libs, and if all is	*/
/* ok, call the other functions			*/
/************************************************/

main(argc,argv)
int	argc;
char	*argv[];
{
	int	etape,flg_err,i;
	struct	WBStartup *WBenchMsg;
	struct	WBArg	*wbarg;
	LONG	olddir;
	extern	struct	List	*get_modes();

	i=1;
	while(i<argc){

		if(strcmp(argv[i],"-d")==0){
			flg_debug=TRUE;
		}
		i++;
	}
	p_name=argv[0];
	olddir=-1;

        etape=0;
	flg_err=FALSE;
	while((flg_err==FALSE)&&(etape<7)){
		printd("Etape:%ld\n",etape);
		switch(etape){

		   case 0:

			/* First, we open all the needed library	*/

			IntuitionBase=(struct Library *)OpenLibrary("intuition.library",0);
			GfxBase=(struct Library *)OpenLibrary("graphics.library",0);
			IconBase=(struct Library *)OpenLibrary("icon.library",0);
#ifndef	WB_13
/*			CxBase=OpenLibrary("commodities.library",37L);*/
			GadToolsBase=(struct Library *)OpenLibrary("gadtools.library",0);
			if(GadToolsBase==0){
				flg_err=TRUE;
				aff_error("This doesn't seem to be a\nWB 2.0 or higher\n\nUse SuperDark_1.3\n\n");
			}
			CxBase=OpenLibrary("commodities.library",37L);
#endif
			ReqToolsBase = (struct ReqToolsBase *)OpenLibrary (REQTOOLSNAME, 0);
			break;

			/* initialisation du port de communication */
		   case 1:
			flg_err=init_port();
			break;
			/* chargement des parametres de config */
		   case 2:
			/* Du WB? */
			if(argc==0){
				WBenchMsg=(struct WBStartup *)argv;
				for(i=0,wbarg=WBenchMsg->sm_ArgList;
					i<WBenchMsg->sm_NumArgs;
					i++,wbarg++){
					if((wbarg->wa_Lock)&&(*wbarg->wa_Name)){
						p_name=wbarg->wa_Name;
						dir_save=wbarg->wa_Lock;
						olddir=CurrentDir(dir_save);
						printd("Je fais un CurrentDir..old:%lx new:%lx\n",olddir,dir_save);
					}
				}
				
			}
			LoadConfig(p_name,&my_gadg[GID_TEMPO]);
			my_info.tempo=my_gadg[GID_TEMPO].value;

			/* Rem: les parametres du module aleatoire sont sauvegarde*/
			/* avec ceux du fichier principal, car le mode aleatoire  */
			/* n'ayant pas d'icone...				  */
			LoadConfig(p_name,gadg_alea);
			break;


			/* initialisation de l'input ev */
		   case 3:
#ifdef	WB_13
			flg_err=init_input_ev();
#endif
#ifndef	WB_13
			flg_err=init_input_ev(argc,argv);
#endif
			break;
			/* recherche des modules existants     */
		   case 4:
			flg_err=find_mod(my_gadg[GID_DIR].p_data);
			break;
		   case 5:

			/* chargement de la suite de la config du module aleatoire*/
			load_alea_cfg();
			/* We open the main window	*/
			big_ctx.t_g=my_gadg;
			big_ctx.GList=0;
			big_ctx.p_name=p_name;
			set_font_size();
			break;
		   case 6:

			/* Liste des modes dispo */
			if((mode_liste=get_modes())==0){
				flg_err=TRUE;
			}
			data_proc.ml=mode_liste;
			break;
		   }
		   etape++;
	}
	
	if(flg_err==FALSE){

		/* Si il n'y a aucun module, on ouvre la fentre, pour que  */
		/* l'utilisateur voi qq chose!				   */

		if(nb_module==0){
			InitStuff_gadg(&big_ctx,TRUE);
		}else{
			if(my_gadg[GID_QUIET].value==FALSE){
				affiche_texte("SuperDark Installed...\nPress HotKey for options",NULL,TRUE);
			}
		}
		main_loop(&big_ctx);
		my_gadg[GID_MODULES].value=selection;
		if(big_ctx.flg_save==TRUE){
			SaveConfig(p_name,&my_gadg[GID_DEBUT]);
			save_alea_cfg();
		}
	}
	if(olddir!=-1)CurrentDir(olddir);
	free_all();

}
