#include	<stdio.h>
#include	<exec/types.h>
#include	<exec/tasks.h>
#include	<exec/ports.h>
#include	<exec/memory.h>
#include	<exec/tasks.h>
#include	<graphics/displayinfo.h>
#include	<graphics/displayinfo.h>
#include	<graphics/gfxmacros.h>
#include	<dos/dosextens.h>
#include	<clib/exec_protos.h>
#include	<hardware/custom.h>
#include	<hardware/dmabits.h>
#include	<intuition/intuitionbase.h>
#include	<intuition/screens.h>
#include	"/includes/struct.h"
#include	"/includes/tom_gadget.h"

#ifndef custom
#define custom (*(struct Custom *)0xDFF000)
#endif	/* custom */
#define DEF_MODE      0
#define DEF_MODE_NAME "HighRes"


static	int	s2depth,width,height;

struct my_data	*p_info;
struct	appel_proc	*p_data_proc;
struct	appel_proc	data_proc;
struct	BitMap		b;
static	struct	Screen		*s;
static	struct	Window	*wnd;
static	int	flg_end=FALSE;

struct	IntuitionBase	*IntuitionBase;
struct	Library	*GfxBase;
extern	struct	tom_gadget	my_gadg[];
extern	void	__saveds	dark();
extern	void	proc_init();
extern	void	proc_end();
extern	char	*p_text_info;
struct ExtNewScreen newscreen = {
  0,0,0,0,0,0,0,NULL,CUSTOMSCREEN|CUSTOMBITMAP,NULL,(UBYTE *)" ",NULL,NULL
};

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

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)
{
	printf(pc);
}
void	My_Print(struct RastPort *rp,UWORD x,UWORD y,char	*pc)
{
	Move(rp,x,y);
	Text(rp,pc,mystrlen(pc));
}

#ifdef	DEBUG
VOID_STDARGS printt(char *FormatString,...)

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

/* Checrche une resolution correspondant aux mieu a nos demandes */
/* si flg_depth=TRUE, alors on cherche la prof max corresp a la	 */
/* resolution demandee						 */

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;
}

/********************************************************** get_modes() *****/

/********************************************************/
/* We get the current modes availables in this computer */
/********************************************************/

struct	List	*get_modes()
{
 struct List *ModeList;
 ULONG DisplayID;
 struct DimensionInfo DimInfo;
 struct NameInfo NameInfo;
 struct ModeNode *ModeNode;

 if (ModeList=AllocMem(sizeof(struct List),MEMF_PUBLIC)) NewList (ModeList);
 else return NULL;

 DisplayID=INVALID_ID;
 while ((DisplayID=NextDisplayInfo(DisplayID))!=INVALID_ID){
  if ((DisplayID&MONITOR_ID_MASK)&&(ModeNotAvailable(DisplayID)==0L)){
   if (GetDisplayInfoData(NULL,(UBYTE *)&DimInfo,sizeof(struct DimensionInfo),
                          DTAG_DIMS,DisplayID)){
    if (DimInfo.MaxDepth>1){
     if (GetDisplayInfoData(NULL,(UBYTE *)&NameInfo,sizeof(struct NameInfo),
                            DTAG_NAME,DisplayID)){
      if (ModeNode=AllocMem(sizeof(struct ModeNode),MEMF_PUBLIC))
       {

	ModeNode->MaxDepth=DimInfo.MaxDepth;
	ModeNode->MinX=DimInfo.Nominal.MinX+1;
	ModeNode->MaxX=DimInfo.Nominal.MaxX+1;
	ModeNode->MinY=DimInfo.Nominal.MinY+1;
	ModeNode->MaxY=DimInfo.Nominal.MaxY+1;

        (void)strcpy(ModeNode->Name,
                     NameInfo.Name);
	ModeNode->mn_Node.ln_Name=ModeNode->Name;
        ModeNode->DisplayID=DisplayID;

	printf("%20s ",NameInfo.Name);
	printf("M.depth:%d mx:%02d my:%02d MX:%03d MY:%03d ",DimInfo.MaxDepth,
				DimInfo.Nominal.MinX,
				DimInfo.Nominal.MinY,
				DimInfo.Nominal.MaxX,
				DimInfo.Nominal.MaxY);
	printf("Flags:%lx\n",ModeNode->DisplayID);

        AddTail (ModeList,&ModeNode->mn_Node);
      }
     }
    }
   }
  }
 }	
 if (ModeList->lh_Head->ln_Succ==NULL)
  if (ModeNode=AllocMem(sizeof(struct ModeNode),MEMF_PUBLIC))
   {
    (void)strcpy(ModeNode->Name,
                     DEF_MODE_NAME);
    ModeNode->mn_Node.ln_Name=ModeNode->Name;
    ModeNode->DisplayID=DEF_MODE;
    ModeNode->MaxX=640;
    ModeNode->MaxY=256;
    ModeNode->MaxDepth=4;

    AddTail (ModeList,&ModeNode->mn_Node);
   }
  else
   {
    FreeMem ((APTR)ModeList,sizeof(struct List));
    return NULL;
   }
 return ModeList;
}

/************************************************************* free_modes() */


/***********************************************/
/* We delete the liste of the available modes */
/***********************************************/

void free_modes(struct List *ModeList)

{
	struct ModeNode *ModeNode;

	while (ModeList->lh_Head->ln_Succ){
		ModeNode=(struct ModeNode *)ModeList->lh_Head;
		RemHead (ModeList);
		FreeMem ((APTR)ModeNode,sizeof(struct ModeNode));
	}
	FreeMem ((APTR)ModeList,sizeof(struct List));
}
/*******************************************************************/
/* 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							   */
/*******************************************************************/

DCloseScreen(struct Screen *s)
{
	if(s)CloseScreen(s);
}
/*******************************************************************/

int blank()
{
  int	i,col;
  struct	Screen	*s2;
  struct ViewPort      *vp2;
  static struct TagItem screen_item[2]={{SA_DisplayID,0},TAG_END};

  /* We set the sprite off, with 2 different methodes:	*/
  /* Software (not always work) and Hardware (tricky..) */

/*
  if (my_gadg[GID_SPRITE].value){
*/
	OFF_SPRITE
	for (i=0L; i<8L; i++){
		 custom.spr[i].ctl=0;
	}
/*
  }else{
*/
/*
  }
*/
 data_proc.s=0;

  s2 = IntuitionBase->FirstScreen;
  vp2 = &s2->ViewPort;
  s2depth = s2->BitMap.Depth;
  
  newscreen.Type|=NS_EXTENDED;
  newscreen.LeftEdge = s2->LeftEdge;
  newscreen.TopEdge = s2->TopEdge;
  newscreen.Width = s2->Width;
  newscreen.Height = s2->Height;
  newscreen.DetailPen = s2->DetailPen;
  newscreen.BlockPen = s2->BlockPen;
  newscreen.Depth = s2depth;
  newscreen.ViewModes = vp2->Modes;
  newscreen.DefaultTitle=NULL;
  newscreen.Extension=screen_item;

  width=newscreen.Width;
  height=newscreen.Height;
  
 if(data_proc.type_screen==SCR_GIVEN){

  if (s) printf("Error! Screen Exists! Quitting...");
  screen_item[0].ti_Data=GetVPModeID(vp2);
  InitBitMap(&b,s2depth,width,height);
  for(i=0;i<s2depth;i++){
	b.Planes[i]=AllocRaster(width,height);
		if(b.Planes[i]==0){
		printf("Big erreur aVEC alloc raster\n");
		return(1);
	}
  }
  BltBitMap(&(s2->BitMap),0,0,&b,0,0,width,height,0xc0,0xff,NULL);
  newscreen.CustomBitMap=&b;

  if ((s = (struct Screen *)OpenScreen(&newscreen)) == NULL)
    printf("[Couldn't Open Screen]",0);

  for(i=0;i<(1<<s2depth);i++){
	col=GetRGB4(s2->ViewPort.ColorMap,i);
	SetRGB4(&(s->ViewPort),i,(col&0xf00)>>8,(col&0xf0)>>4,(col&0xf));
  }

   data_proc.rp= &(s->RastPort);
   data_proc.rps=&(s2->RastPort);
   data_proc.s=s;
   data_proc.width=width;
   data_proc.height=height;
  }
  
}

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

void	off_blank()
{
   int	i;
   if(data_proc.type_screen==SCR_GIVEN){

	if(s!=0)CloseScreen(s);
	for(i=0;i<s2depth;i++){
		if(b.Planes[i]!=0){
			FreeRaster(b.Planes[i],width,height);
		}
	}
  }
/*
  if (my_gadg[GID_SPRITE].value){
*/
	  ON_SPRITE
/*
  }else{
*/
/*
  }
*/
  s=0;
}
/**************************************************************************/
open_win()
{
	if ( ! ( wnd = OpenWindowTags( NULL,
				WA_Left,	100,
				WA_Top,		100,
				WA_Width,	200,
				WA_Height,	100,
				WA_IDCMP,	IDCMP_CLOSEWINDOW|IDCMP_REFRESHWINDOW,
				WA_Flags,	WFLG_SIZEGADGET|WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET|WFLG_SMART_REFRESH,
				WA_Title,	"SuperDark",
				WA_ScreenTitle,	"SuperDark",
				TAG_DONE )))
			return (-1);
	return(0L);
}
close_win()
{
	if(wnd)CloseWindow(wnd);
}
/**************************************************************************/

main()
{

	/****************************************************************/
	/* Recherche du port qui contient les infos relatives a l'ecran */
	/* Ce port permet de passer des donnes de la tache main vers ici*/ 
	/****************************************************************/

	IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0);
	GfxBase=(struct Library *)OpenLibrary("graphics.library",0);
	
	p_data_proc=&data_proc;
	get_modes();

	/*********************************************/
	/* On recupere les informaitons ainsi passee */
	/*********************************************/
	p_info=p_data_proc->p_info;
	p_data_proc->p_gadg=my_gadg;
	p_data_proc->p_texte=p_text_info;
	p_data_proc->type_screen=SCR_OWN;
	proc_init();

	/* Si on n'a pas encore notifie le type de verision */
	if(p_data_proc->code_ret==-1){
		p_data_proc->code_ret=DARK_WB_13;
	}
	blank();

	MyWrite("Avant le do\n");
	MyWrite(pr_buff);
	/* Attend que le main nous reveille */

	if(open_win()==0){
		dark();
	}
	close_win();
	MyWrite("ctrl-C recu, j'averti le main\n");

	proc_end();
	off_blank();
	MyWrite("Signal Exit..\n");
	CloseLibrary((struct Library *)IntuitionBase);
	CloseLibrary(GfxBase);
    return 0;
}

int	__saveds	tst_end()
{
	struct	message	*msg;

	if(flg_end==FALSE){
		if((msg=GetMsg(wnd->UserPort)){
			flg_end=TRUE;
			ReplyMsg(msg);
		}
	}
	return (flg_end);
}

void	__saveds	wait_end()
{
	if(flg_end==FALSE)WaitPort(wnd->UserPort);
}
