#include <exec/types.h>
#include <exec/memory.h>
#include <exec/libraries.h>
#include <dos/dos.h>
#include <dos/rdargs.h>
#include <datatypes/datatypes.h>
#include <datatypes/datatypesclass.h>
#include <datatypes/pictureclass.h>
#include <datatypes/pictureclassext.h>
#include <intuition/intuition.h>
#include <intuition/icclass.h>
#include <graphics/gfx.h>
#include <graphics/displayinfo.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <clib/macros.h>
#include <devices/timer.h>
#include <proto/timer.h>
#include <proto/exec.h>
#include <clib/alib_protos.h>
#include <clib/datatypes_protos.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>
#include <clib/utility_protos.h>
#include <pragmas/datatypes_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/graphics_pragmas.h>
#include <pragmas/intuition_pragmas.h>
#include <pragmas/utility_pragmas.h>

// Global variables ****************************************************

//struct Library *IntuitionBase = NULL;
struct IntuitionBase *IntuitionBase = NULL;
struct Library *GfxBase = NULL;
struct Library *CybergraphicsBase = NULL;
struct Library *DataTypesBase = NULL;
struct Task *mytask;
struct Window *Mywindow;
struct BitMapHeader *mybmhd = NULL;
struct BitMap *mybitmapdt = NULL;
struct BitMap *mybitmapdtReMapped = NULL;
//struct BitMap *Mywindowbitmap = NULL;
Object *mydataobject;
int mywindowX = 0 ;
int mywindowY = 0 ;
int mysignal;
int quit = NULL;
int myinstallertofront = TRUE;
int mycenterX;
int mycenterY;
int myscreenX;
int myscreenY;
int inputpos,myborderless,installerpos,mytile;
int	animwait,animspeed,animframes,animtype;
int calcspeed;
int winbordertop = 1;
int winborderleft = 1;
int mywindowopen = FALSE;
char *myallocmem = 0;
int myopenfile = 0;
int foundwindow = FALSE;
int skipwaitnewfile = FALSE;
int	Cwindowx = 0;
int Cwindowy = 0;
struct Screen *myscreen = 0;
struct Screen *mylockscreen = 0;
STRPTR myprefs = ".prefs";
STRPTR Emptystring = "copy ";
STRPTR Emptystring2 = " to ";
STRPTR Emptystring3 = ".in_use";
STRPTR Emptystring4 = "delete ";
STRPTR Version = "$VER: InstallerFX Version 1.10 (01.10.1997)by Øyvind Falch of Triumph 1997-1998";
STRPTR SearchString = "Install ";
struct Window *otherwindow = NULL;
char mywintitle = NULL;
int Ssearch = TRUE;
char *argallocmem;
char *mypool = NULL;
char *myfilename = NULL;
char *myconfigfile = NULL;
char *mycopystring = NULL;
char *myshowfilename = NULL;
char *mydeletestring = NULL;
int	makestringfailed = TRUE;
int animation = FALSE;
ULONG nomwidth, nomheight;
struct NotifyRequest Filenr  = {0};
BYTE timerdevice = TRUE ;
struct MsgPort *TimerPort = 0;
struct timerequest *TimerReq = 0;
ULONG waitmask;
ULONG sigs;

#define	IDCMP_FLAGS	IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY | IDCMP_IDCMPUPDATE

// ImageBackfill

/*
** $VER: ImageBackFill.h 1.13 (19.3.95)
**
** (W) 1992-95 by Pierre Carrette & Walter Dörwald
*/

struct BackFillOptions
{
	WORD MaxCopyWidth;  // maximum width for the copy
	WORD MaxCopyHeight; // maximum height for the copy
	BOOL CenterX;       // center the tiles horizontally?
	BOOL CenterY;       // center the tiles vertically?
	WORD OffsetX;       // offset to add
	WORD OffsetY;       // offset to add
	BOOL OffsetTitleY;  // add the screen titlebar height to the vertical offset?
};

struct BackFillInfo
{
	struct Hook            Hook;
	struct Screen         *Screen;
	Object                *PictureObject;
	struct BitMapHeader   *BitMapHeader;
	struct BitMap         *BitMap;
	WORD                   CopyWidth;
	WORD                   CopyHeight;
	struct BackFillOptions Options;
};

struct Rectangle myrec;

// ImageBackfill

// Program Start ****************************************************************

// CopyTiledBitMap
/*
** $VER: ImageBackFill.c 1.231 (19.3.95)
**
** (W) 1992-95 by Pierre Carrette & Walter Dörwald
*/

struct BackFillMsg
{
	struct Layer    *Layer;
	struct Rectangle Bounds;
	LONG             OffsetX;
	LONG             OffsetY;
};

// this seems to be a bug (or feature) in SAS/C: -6%5 gives -1 instead of 4

#define MOD(x,y) ((x)<0 ? (y)-((-(x))%(y)) : (x)%(y))
#define RECTSIZEX(r) ((r)->MaxX-(r)->MinX+1)
#define RECTSIZEY(r) ((r)->MaxY-(r)->MinY+1)

/****** CopyTiledBitMap ****************************************************************************
*
*   NAME
*	CopyTiledBitMap() -- fill bitmap with bitmap pattern
*
*   SYNOPSIS
*	CopyTiledBitMap(Src,SrcOffsetX,SrcOffsetY,SrcSizeX,SrcSizeY,Dst,DstBounds)

*	void CopyTiledBitMap(struct BitMap *,WORD,WORD,WORD,WORD,struct BitMap *,struct Rectangle *)
*
*   FUNCTION
*	fills the destination bitmap with repeated (tiled) copies of the source bitmap
*
*   INPUTS
*	Src = source bitmap.
*	SrcOffsetX = offset (in x direction) to use in the blit.
*	SrcOffsetY = offset (in y direction) to use in the blit.
*	             The pixel at position (SrcOffsetX,SrcOffsetY) in the source bitmap
*	             will be the first visible one in the upper left corner of DstBounds.
*	SrcSizeX = width of the source bitmap Src.
*	SrcSizeY = height of the source bitmap Src.
*	Dst = destination bitmap.
*	DstBounds = this rectangle in the destination bitmap will be filled.
*
*   RESULT
*	None.
*
*   EXAMPLE
*	This function is most useful in backfill hooks.
*
*   NOTES
*	The following relations must hold:
*		0 <= SrcOffsetX < SrcSizeX
*		0 <= SrcOffsetY < SrcSizeY
*	I.e. if calculating the offset involves some kind of modulo-operations
*	they have to be done before calling this function
*
*/

void CopyTiledBitMap(struct BitMap *Src,WORD SrcOffsetX,WORD SrcOffsetY,WORD SrcSizeX,WORD SrcSizeY,struct BitMap *Dst,struct Rectangle *DstBounds)
{
	WORD FirstSizeX;  // the width of the rectangle to blit as the first column
	WORD FirstSizeY;  // the height of the rectangle to blit as the first row
	WORD SecondMinX;  // the left edge of the second column
	WORD SecondMinY;  // the top edge of the second column
	WORD SecondSizeX; // the width of the second column
	WORD SecondSizeY; // the height of the second column
	WORD Pos;         // used as starting position in the "exponential" blit
	WORD Size;        // used as bitmap size in the "exponential" blit

	FirstSizeX = MIN(SrcSizeX-SrcOffsetX,RECTSIZEX(DstBounds)); // the width of the first tile, this is either the rest of the tile right to SrcOffsetX or the width of the dest rect, if the rect is narrow
	SecondMinX = DstBounds->MinX+FirstSizeX; // the start for the second tile (if used)
	SecondSizeX = MIN(SrcOffsetX,DstBounds->MaxX-SecondMinX+1); // the width of the second tile (we want the whole tile to be SrcSizeX pixels wide, if we use SrcSizeX-SrcOffsetX pixels for the left part we'll use SrcOffsetX for the right part)

	FirstSizeY = MIN(SrcSizeY-SrcOffsetY,RECTSIZEY(DstBounds)); // the same values are calculated for y direction
	SecondMinY = DstBounds->MinY+FirstSizeY;
	SecondSizeY = MIN(SrcOffsetY,DstBounds->MaxY-SecondMinY+1);

	BltBitMap(Src,SrcOffsetX,SrcOffsetY,Dst,DstBounds->MinX,DstBounds->MinY,FirstSizeX,FirstSizeY,0xC0,-1,NULL); // blit the first piece of the tile
	if (SecondSizeX>0) // if SrcOffset was 0 or the dest rect was to narrow, we won't need a second column
		BltBitMap(Src,0,SrcOffsetY,Dst,SecondMinX,DstBounds->MinY,SecondSizeX,FirstSizeY,0xC0,-1,NULL);
	if (SecondSizeY>0) // is a second row necessary?
	{
		BltBitMap(Src,SrcOffsetX,0,Dst,DstBounds->MinX,SecondMinY,FirstSizeX,SecondSizeY,0xC0,-1,NULL);
		if (SecondSizeX>0)
			BltBitMap(Src,0,0,Dst,SecondMinX,SecondMinY,SecondSizeX,SecondSizeY,0xC0,-1,NULL);
	}

	// this loop generates the first row of the tiles
	for (Pos = DstBounds->MinX+SrcSizeX,Size = MIN(SrcSizeX,DstBounds->MaxX-Pos+1);Pos<=DstBounds->MaxX;)
	{
		BltBitMap(Dst,DstBounds->MinX,DstBounds->MinY,Dst,Pos,DstBounds->MinY,Size,MIN(SrcSizeY,RECTSIZEY(DstBounds)),0xC0,-1,NULL);
		Pos += Size;
		Size = MIN(Size<<1,DstBounds->MaxX-Pos+1);
	}

	// this loop blit the first row down several times to fill the whole dest rect
	for (Pos = DstBounds->MinY+SrcSizeY,Size = MIN(SrcSizeY,DstBounds->MaxY-Pos+1);Pos<=DstBounds->MaxY;)
	{
		BltBitMap(Dst,DstBounds->MinX,DstBounds->MinY,Dst,DstBounds->MinX,Pos,RECTSIZEX(DstBounds),Size,0xC0,-1,NULL);
		Pos += Size;
		Size = MIN(Size<<1,DstBounds->MaxY-Pos+1);
	}
}

// This function must be compiled without stack checking
void WindowPatternBackFillFunc(register __a0 struct Hook *Hook,register __a2 struct RastPort *RP,register __a1 struct BackFillMsg *BFM)
{
	WORD OffsetX; // the offset within the tile in x direction
	WORD OffsetY; // the offset within the tile in y direction

	struct BackFillInfo *BFI = (struct BackFillInfo *)Hook; // get the data for our backfillhook (but __saveds is nonetheless required because this function needs GfxBase)

	struct RastPort cRP;

	cRP = *RP;        // copy the rastport
	cRP.Layer = NULL; // eliminate bogus clipping from our copy

	OffsetX = BFM->Bounds.MinX-BFI->Options.OffsetX; // The first tile normally isn't totally visible => calculate the offset (offset 0 would mean that the left edge of the damage rectangle coincides with the left edge of a tile)
	if (BFI->Options.CenterX) // horizontal centering?
		OffsetX -= (BFI->Screen->Width-BFI->BitMapHeader->bmh_Width)/2;

	OffsetY = BFM->Bounds.MinY-BFI->Options.OffsetY; // The same values are calculated for y direction
	if (BFI->Options.OffsetTitleY) // shift the tiles down?
		OffsetY -= BFI->Screen->BarHeight+1;
	if (BFI->Options.CenterY) // horizontal centering?
		OffsetY -= (BFI->Screen->Height-BFI->BitMapHeader->bmh_Height)/2;

	CopyTiledBitMap(BFI->BitMap,MOD(OffsetX,BFI->BitMapHeader->bmh_Width),MOD(OffsetY,BFI->BitMapHeader->bmh_Height),BFI->CopyWidth,BFI->CopyHeight,cRP.BitMap,&BFM->Bounds);
}

// this function calculates the sizes to be used for the copy of the bitmap
static void CalculateCopySizes(struct BackFillInfo *BFI)
{
	BFI->CopyWidth = (BFI->BitMapHeader->bmh_Width>BFI->Options.MaxCopyWidth) ? BFI->BitMapHeader->bmh_Width : BFI->Options.MaxCopyWidth-BFI->Options.MaxCopyWidth%BFI->BitMapHeader->bmh_Width;
	BFI->CopyHeight = (BFI->BitMapHeader->bmh_Height>BFI->Options.MaxCopyHeight) ? BFI->BitMapHeader->bmh_Height : BFI->Options.MaxCopyHeight-BFI->Options.MaxCopyHeight%BFI->BitMapHeader->bmh_Height;
}
// CopyTiledBitMap

// Get args  ****************************************************************
int MakeStrings () // Make Copy String
{
	int mycounter = 0;
	int mycounter2 = 0;
	STRPTR myargs ;
	myargs = GetArgStr ();
	if (myargs[0] != '\n') {
		myfilename = AllocPooled (mypool,512);
		myconfigfile = AllocPooled (mypool,512);
		mycopystring = AllocPooled (mypool,512);
		myshowfilename = AllocPooled (mypool,512);
		mydeletestring = AllocPooled (mypool,512);
		if (myfilename != NULL || myconfigfile != NULL ||mycopystring != NULL ||myshowfilename != NULL ||mydeletestring != NULL){
// Filename
			while ((myargs[mycounter]) != '\n'){
				myfilename[mycounter] = myargs[mycounter];
				myconfigfile[mycounter] = myargs[mycounter];
				mycounter = mycounter +1;
			}
			while ((myprefs[mycounter2]) != 0){
				myconfigfile[mycounter] = myprefs[mycounter2];
				mycounter = mycounter +1;
				mycounter2 = mycounter2 +1;
			}
// Copystring
			mycounter = 0;
			mycounter2 = 0;
// copy >nil: <nil: 
			while ((Emptystring[mycounter]) != 0){
				mycopystring[mycounter] = Emptystring[mycounter];
				mycounter = mycounter +1;
			}
// filename
			while ((myfilename[mycounter2]) != 0){
				mycopystring[mycounter] = myfilename[mycounter2];
				mycounter = mycounter +1;
				mycounter2 = mycounter2 +1;
			}
// " to "
			mycounter2 = 0;
			while ((Emptystring2[mycounter2]) != 0){
				mycopystring[mycounter] = Emptystring2[mycounter2];
				mycounter = mycounter +1;
				mycounter2 = mycounter2 +1;
			}
// filename 
			mycounter2 = 0;
			while ((myfilename[mycounter2]) != 0){
				mycopystring[mycounter] = myfilename[mycounter2];
				mycounter = mycounter +1;
				mycounter2 = mycounter2 +1;
			}
// ".in_use
			mycounter2 = 0;
			while ((Emptystring3[mycounter2]) != 0){
				mycopystring[mycounter] = Emptystring3[mycounter2];
				mycounter = mycounter +1;
				mycounter2 = mycounter2 +1;
			}
			mycounter = 0;
			mycounter2 = 0;
// filename
			while ((myfilename[mycounter]) != 0){
				myshowfilename[mycounter] = myfilename[mycounter];
				mycounter = mycounter +1;
			}
// ".in_use
			while ((Emptystring3[mycounter2]) != 0){
				myshowfilename[mycounter] = Emptystring3[mycounter2];
				mycounter = mycounter +1;
				mycounter2 = mycounter2 +1;
			}
// Delete String
			mycounter = 0;
			mycounter2 = 0;
// "delete >nil: <nil: "
			while ((Emptystring4[mycounter]) != 0){
				mydeletestring[mycounter] = Emptystring4[mycounter];
				mycounter = mycounter +1;
			}
// filename
			while ((myfilename[mycounter2]) != 0){
				mydeletestring[mycounter] = myfilename[mycounter2];
				mycounter = mycounter +1;
				mycounter2 = mycounter2 +1;
			}
// ".in_use
			mycounter2 = 0;
			while ((Emptystring3[mycounter2]) != 0){
				mydeletestring[mycounter] = Emptystring3[mycounter2];
				mycounter = mycounter +1;
				mycounter2 = mycounter2 +1;
			}
			makestringfailed = FALSE;
		}
	}
	return 0;
}
// checknext window  ****************************************************************
int checkNextwindow () // Find Installer window before move
{
	UBYTE pattern[] = "*installer*";
	UBYTE pat[(sizeof(pattern)*2)+2];

	ParsePatternNoCase(pattern, pat, (sizeof(pattern)*2)+2);
  if(MatchPatternNoCase(pat, ((struct Task *) otherwindow->UserPort->mp_SigTask)->tc_Node.ln_Name))	
		Ssearch = TRUE;
	else
		Ssearch = FALSE;
		
	return 0;
}

// Move Installer Window  ****************************************************************
int calculate_windows ()  // Calculate Installer Window on screen
{
	int install_WX = 0;
	int install_WY = 0;
	int	installc_X = 0;
	int installc_Y = 0;

	install_WX = otherwindow->Width;
	install_WY = otherwindow->Height;
	installc_X = otherwindow->LeftEdge;
	installc_Y = otherwindow->TopEdge;
	
// Top 
	if (installerpos == 1){
		installc_X = ((myscreenX/4) - (install_WX /2)) - installc_X;
		installc_Y = ((myscreenY/4) - (install_WY /2)) - installc_Y;
		}
	else if (installerpos == 2){
		installc_X = ((myscreenX/2) - (install_WX /2)) - installc_X;
		installc_Y = ((myscreenY/4) - (install_WY /2)) - installc_Y;
		}
	else if (installerpos == 3){
		installc_X = (((myscreenX/4)*3) - (install_WX /2)) - installc_X;
		installc_Y = ((myscreenY/4) - (install_WY /2)) - installc_Y;
		}
// Middle
	else if (installerpos == 4){
		installc_X = ((myscreenX/4) - (install_WX /2)) - installc_X;
		installc_Y = ((myscreenY/2) - (install_WY /2)) - installc_Y;
		}
	else if (installerpos == 5){
		installc_X = ((myscreenX/2) - (install_WX /2)) - installc_X;
		installc_Y = ((myscreenY/2) - (install_WY /2)) - installc_Y;
		}
	else if (installerpos == 6){
		installc_X = (((myscreenX/4)*3) - (install_WX /2)) - installc_X;
		installc_Y = ((myscreenY/2) - (install_WY /2)) - installc_Y;
		}
// Bottom
	else if (installerpos == 7){
		installc_X = ((myscreenX/4) - (install_WX /2)) - installc_X;
		installc_Y = (((myscreenY/4)*3) - (install_WY /2)) - installc_Y;
		}
	else if (installerpos == 8){
		installc_X = ((myscreenX/2) - (install_WX /2)) - installc_X;
		installc_Y = (((myscreenY/4)*3) - (install_WY /2)) - installc_Y;
		}
	else if (installerpos == 9){
		installc_X = (((myscreenX/4)*3) - (install_WX /2)) - installc_X;
		installc_Y = (((myscreenY/4)*3) - (install_WY /2)) - installc_Y;
		}
	else if (installerpos == 0) {
		installc_X = 0;
		installc_Y = 0;
		}
	MoveWindow( otherwindow, installc_X, installc_Y );
	WindowToFront (otherwindow);
	return 0;
}
// Move Installer Window  ****************************************************************
int moveInstaller () // Move installer window
{
	struct Screen *lockmove;
	lockmove = LockPubScreen ("Workbench");

	myscreenX = lockmove ->Width;
	myscreenY = lockmove ->Height;

	for (otherwindow = lockmove->FirstWindow; otherwindow; 
		otherwindow = otherwindow->NextWindow) {
		if (otherwindow->Title) {
				checkNextwindow ();
			if (Ssearch !=FALSE){
				calculate_windows ();
				break;
			}			
		}
	}
	UnlockPubScreen (NULL, lockmove);
	return 0;
}

// NOTIFY ***************************************************
int notify(char*waitfile)
{
	struct NotifyRequest nr  = {0};
	nr.nr_Flags = NRF_SEND_SIGNAL;
	nr.nr_stuff.nr_Signal.nr_Task = mytask;
	nr.nr_stuff.nr_Signal.nr_SignalNum = mysignal;
	nr.nr_Name  = waitfile;
	StartNotify ( &nr );
	Wait (1 <<mysignal);
	EndNotify ( &nr);
	return 0;
}

// NOTIFY Anim ***************************************************
int notifyAnim(char*waitfile)
{
	Filenr.nr_Flags = NRF_SEND_SIGNAL;
	Filenr.nr_stuff.nr_Signal.nr_Task = mytask;
	Filenr.nr_stuff.nr_Signal.nr_SignalNum = mysignal;
	Filenr.nr_Name  = waitfile;
	StartNotify ( &Filenr );
	return 0;
}

// Wait Function  ****************************************************************
int CreateTimerWait(void)
{
	timerdevice = TRUE ;
	TimerPort = 0;
	TimerReq = 0;
	waitmask =0 ;
	sigs =0 ;
	
	// Opprette en svarport for timerequest
	TimerPort =  CreateMsgPort();
	if( TimerPort != 0) {
		// Opprette en timerequest som kan sendes til devicen
		TimerReq =  (struct timerequest *) 
		CreateIORequest( TimerPort, sizeof (struct timerequest) );
		if( TimerReq != 0) {
			timerdevice =  OpenDevice( "timer.device", 
			// Åpne et eller annet device
			UNIT_VBLANK, (struct IORequest *) TimerReq, 0 );
			if( timerdevice == 0) {
				TimerReq->tr_node.io_Message.mn_Node.ln_Type =  0;			
			}
		}
	}
	return 0;
}

// Wait Function  ****************************************************************
WaitTimer(void)
{
// timer.device er nå åpen.
//   printf( "sender request for 10 sekunders venting til timer.device...\n" );

	waitmask = 0 ;
	sigs = 0 ;

	waitmask =  (1 << TimerPort->mp_SigBit) | SIGBREAKF_CTRL_C | 1 <<mysignal ;

	TimerReq->tr_node.io_Command =  TR_ADDREQUEST;
	TimerReq->tr_time.tv_secs  =  animwait;
	TimerReq->tr_time.tv_micro = calcspeed;

	SendIO( (struct IORequest *) TimerReq );

//   printf( "request er sendt. Tikk tikk tikk...\n" );

   // Setter opp hvilke bits vi vil vente på.
   // Alle prosesser kan også vente på SIGBREAKF_CTRL_? signalene, som tilsvarer
   // CTRL_C etc.
   // Her kan du legge inn masks for andre ting du vil vente p=å.

//   printf( "Bruker Wait() for å vente på både ctrl-c og svar på requesten\n" );

	sigs =  Wait( waitmask );

   // Husk at vi kan få både ctrl-c + vent ferdig som svar hvis ctrl-c blir
   // trykket akkurat i det timeren er ferdig.

//	printf( "Signalmaske mottatt: %x\n", sigs );

	return 0;
}

// Wait Function  ****************************************************************
CleanupTimerWait(void)
{
  // Rydde opp...
	if (timerdevice == 0)
		CloseDevice( (struct IORequest *)TimerReq );
	if (!TimerReq != 0)
		DeleteIORequest( (struct IORequest *)TimerReq );
	if (!TimerPort != 0)
   	DeleteMsgPort( TimerPort );
//   printf( "ferdig!\n" );
   return 0;
}

// Load file Simple ****************************************************************
int readprefsfile ()
{
	FILE	*fp;
	int 	ant_poster;
	inputpos = 0;
	myborderless = 0;
	installerpos = 0;
	mytile = 0;;
	animspeed = 0;
	animframes = 0;
	animtype = 0;
	animation = FALSE;
	fp= fopen(myconfigfile, "r");
	if (fp != NULL){ 
		ant_poster = fscanf(fp,"%1d%1d%1d%1d%02d%03d%03d%0d3\n",&inputpos,&myborderless,&mytile,&installerpos,&animwait,&animspeed,&animframes,&animtype);
		fclose (fp);
	//		printf ("Can't load prefsfile, using default values.\n");
	}	
	if (inputpos >9 || inputpos < 1)
		inputpos = 1;
	if (myborderless >1 || myborderless <0)
		myborderless = 0;
	if (installerpos >9 || installerpos <0)
		installerpos = 9;
	if (mytile >1 || mytile <0)
		mytile = 0;
	if (animwait  >999 || animwait <0)
		animwait = 0;
	if (animspeed  >99 || animspeed <0)
		animspeed = 0;
	if (animframes  >999 || animframes <0)
		animframes = 0;
	if (animtype  >999 || animtype <0)
		animtype = 0;
	if (animframes >0 && animframes >0)
		animation = TRUE;
	// Extra check for Second and Frames.
	if (animwait >0)
		animspeed = 0;
	if (animwait == 0 && animspeed == 0)
		animwait = 5; 		
	return 0;
}

// Copy File ***************************************************
int mycopyfile()
{
	Execute (mycopystring,NULL,NULL);
	return 0;
}

// Delete File ***************************************************
int mydeletefile()
{
	Execute (mydeletestring,NULL,NULL);
	return 0;
}

// Wait for datatype Calculations *****************************
wait_for_datatype ()
{
	BOOL going = TRUE;
	LONG sigr;	
	struct IntuiMessage *imsg;
	struct TagItem *tstate, *tag;
	struct TagItem *tags;
	ULONG tidata;
	ULONG errnum;
//	ULONG options[NUM_OPTS];

	/* Keep going until were told to stop */

	while (going)

	{
		/* Wait for an event */
		sigr = Wait ((1L << Mywindow->UserPort->mp_SigBit) | SIGBREAKF_CTRL_C);
		
		/* Did we get a break signal */
		if (sigr & SIGBREAKF_CTRL_C)
			going = FALSE;
	
		/* Pull Intuition messages */
		while (imsg = (struct IntuiMessage *) GetMsg (Mywindow->UserPort))
			{
			/* Handle each message */
			switch (imsg->Class)
				{
					case IDCMP_CLOSEWINDOW:
					going = FALSE;
	
					break;
					case IDCMP_VANILLAKEY:
					switch (imsg->Code)
						{
					   	case 'Q':
						  case 'q':
						  case  27:
							going = FALSE;
							break;
						}
						break;
	
					  case IDCMP_IDCMPUPDATE:
						tstate = tags = (struct TagItem *) imsg->IAddress;
						while (tag = NextTagItem (&tstate))
						{
						    tidata = tag->ti_Data;
						    switch (tag->ti_Tag)
						    {
								/* Change in busy state */
								case DTA_Busy:
							    if (tidata)
									SetWindowPointer (Mywindow, WA_BusyPointer, TRUE, TAG_DONE);
							    else
									SetWindowPointer (Mywindow, WA_Pointer, NULL, TAG_DONE);
							    break;
	
								/* Error message */
								case DTA_ErrorLevel:
							    if (tidata)
							    {
									errnum = GetTagData (DTA_ErrorNumber, NULL, tags);
//									PrintErrorMsg (errnum, (STRPTR) options[OPT_NAME]);
							    }
							    break;

								/* Time to refresh */
								case DTA_Sync:
							    /* Refresh the DataType object */
//							    RefreshDTObjectA (mydataobject, Mywindow, NULL, NULL);
							    going = FALSE;
							    break;
						    }
						}
						break;
				}
	
				/* Done with the message, so reply to it */
				ReplyMsg ((struct Message *) imsg);
			}
	}
	return 0;
}

// Get Screen Information and move installer window **************
int get_screen_information ()
{
	struct Screen *getscreenlock;
	getscreenlock = LockPubScreen ("Workbench");
	if (getscreenlock != 0){
		myscreen = getscreenlock;
		myscreenX = getscreenlock ->Width;
		myscreenY = getscreenlock ->Height;
		if (myborderless == FALSE){
			winbordertop = getscreenlock->WBorTop;
			winborderleft = getscreenlock->WBorLeft;
		}
		UnlockPubScreen (NULL, getscreenlock);
	}
	else
		quit = 1;
	return 0;
}

// Calculate Window  ********************************************

int calculate_window ()
{
	GetDTAttrs (mydataobject, PDTA_BitMapHeader,&mybmhd,PDTA_BitMap,&mybitmapdt, TAG_END);

	mywindowX = mybmhd ->bmh_Width;
	mywindowY = mybmhd ->bmh_Height;

	nomwidth = mywindowX;
	nomheight = mywindowY;
	
	// Fix place for anim
	if (animation == TRUE) {
		mywindowX = mywindowX/animframes;
	}
	
// Top 
	if (inputpos == 1){
		mycenterX = ((myscreenX/4) - (mywindowX /2));
		mycenterY = ((myscreenY/4) - (mywindowY /2));
		}
	else if (inputpos == 2){
		mycenterX = ((myscreenX/2) - (mywindowX /2));
		mycenterY = ((myscreenY/4) - (mywindowY /2));
	}
	else if (inputpos == 3){
		mycenterX = (((myscreenX/4)*3) - (mywindowX /2));
		mycenterY = ((myscreenY/4) - (mywindowY /2));
	}
// Middle
	else if (inputpos == 4){
		mycenterX = ((myscreenX/4) - (mywindowX /2));
		mycenterY = ((myscreenY/2) - (mywindowY /2));
		}
	else if (inputpos == 5){
		mycenterX = ((myscreenX/2) - (mywindowX /2));
		mycenterY = ((myscreenY/2) - (mywindowY /2));
	}
	else if (inputpos == 6){
		mycenterX = (((myscreenX/4)*3) - (mywindowX /2));
		mycenterY = ((myscreenY/2) - (mywindowY /2));
	}
// Bottom
	else if (inputpos == 7){
		mycenterX = ((myscreenX/4) - (mywindowX /2));
		mycenterY = (((myscreenY/4)*3) - (mywindowY /2));
		}
	else if (inputpos == 8){
		mycenterX = ((myscreenX/2) - (mywindowX /2));
		mycenterY = (((myscreenY/4)*3) - (mywindowY /2));
	}
	else if (inputpos == 9){
		mycenterX = (((myscreenX/4)*3) - (mywindowX /2));
		mycenterY = (((myscreenY/4)*3) - (mywindowY /2));
	}		
	return 0;
}

// Process Picture **********************************************
int process_picture ()
{
	struct RastPort *MyRastPort;
	struct Screen *MyScreen;
  struct ViewPort *MyViewPort;
	struct ColorMap *MyColorMap;
	int place_Top;
	int place_Left;

	quit = 1;
	get_screen_information ();
	place_Top = winbordertop;
	place_Left = winborderleft;
	if (myborderless ==1) {
		place_Top = 0;
		place_Left = 0;
	}
	mydataobject = NewDTObject(myshowfilename,
															DTA_SourceType,DTST_FILE,
															PDTA_DestMode,MODE_V43,
															DTA_GroupID,GID_PICTURE,
															OBP_Precision,PRECISION_EXACT,
															PDTA_FreeSourceBitMap,TRUE,
															PDTA_Remap,TRUE,
															GA_Top,place_Top,
															GA_Left,place_Left,
															TAG_END ) ;
	if (mydataobject != NULL ) {
		calculate_window ();
		if (mytile ==1 ){
			Mywindow = OpenWindowTags(NULL,
														WA_Left,0,
														WA_Top, 0,
											  	 	WA_InnerWidth,myscreenX,
											  	 	WA_InnerHeight,myscreenY,
											  	 	WA_Borderless,TRUE,
												  	WA_SmartRefresh,TRUE,
											  		WA_IDCMP, IDCMP_FLAGS,
											  	 	TAG_END ) ;
		}
		else if (mytile !=1 ){
			Mywindow = OpenWindowTags(NULL,
														WA_Left,mycenterX,
														WA_Top, mycenterY,
											  	 	WA_InnerWidth,mywindowX,
											  	 	WA_InnerHeight,mywindowY,
											  	 	WA_Borderless,myborderless,
											  	 	WA_SmartRefresh,TRUE,
												    WA_IDCMP,IDCMP_FLAGS,
											  	 	TAG_END ) ;
		}
		
		if (Mywindow != NULL ){	
			mywindowopen = TRUE;
			MyRastPort = Mywindow->RPort;
			MyScreen = Mywindow->WScreen;
  		MyViewPort = &MyScreen->ViewPort;
			MyColorMap = MyViewPort->ColorMap;
			SetDTAttrs (mydataobject, NULL, NULL,
				    			GA_Width,	nomwidth,
				    			GA_Height, nomheight,
							    ICA_TARGET,	ICTARGET_IDCMP,
							    TAG_DONE);

			AddDTObject (Mywindow, NULL, mydataobject, -1);
			wait_for_datatype (); 
			// Refresh the DataType object since wait for datatype skips this.
	    RefreshDTObjectA (mydataobject, Mywindow, NULL, NULL);
			if (mytile == 1) {
				myrec.MinX = 0;
				myrec.MinY = 0;
				myrec.MaxX = myscreenX-1;
				myrec.MaxY = myscreenY-1;
				GetDTAttrs (mydataobject,PDTA_DestBitMap,&mybitmapdtReMapped,TAG_END);
				if (mybitmapdtReMapped != 0){
					CopyTiledBitMap (mybitmapdtReMapped,0,0,mywindowX,mywindowY,MyRastPort->BitMap, &myrec);
				}
				WindowToBack (Mywindow); //Move the background window to back
			}
			// Move the installerwindow after the new window is opened.
			moveInstaller ();			//Move installer Window
			quit = 0;
		}
	}
	return 0;
}

// Process Animation **********************************************
int process_anim ()
{
	struct RastPort *MyRastPort;
	struct Screen *MyScreen;
  struct ViewPort *MyViewPort;
	struct ColorMap *MyColorMap;
	int place_Top;
	int place_Left;
	int mydestX = 0;
	int i = 0;
	int n = 0;	
	quit = 1;
	get_screen_information ();
	place_Top = winbordertop;
	place_Left = winborderleft;
	if (myborderless ==1) {
		place_Top = 0;
		place_Left = 0;
	}
	mydataobject = NewDTObject(myshowfilename,
															DTA_SourceType,DTST_FILE,
															PDTA_DestMode,MODE_V43,
															DTA_GroupID,GID_PICTURE,
															PDTA_Screen,myscreen,
															PDTA_FreeSourceBitMap,TRUE,
															OBP_Precision,PRECISION_EXACT,
															PDTA_Remap,TRUE,
															GA_Top,place_Top,
															GA_Left,place_Left,
															TAG_END ) ;
	if (mydataobject != NULL ) {
		calculate_window ();
		Mywindow = OpenWindowTags(NULL,
													WA_Left,mycenterX,
													WA_Top, mycenterY,
										  	 	WA_InnerWidth,mywindowX,
										  	 	WA_InnerHeight,mywindowY,
										  	 	WA_Borderless,myborderless,
										  	  WA_SmartRefresh,TRUE,
											    WA_IDCMP,IDCMP_FLAGS,
										  	 	TAG_END ) ;
		
		if (Mywindow != NULL ){	
			mywindowopen = TRUE;
			MyRastPort = Mywindow->RPort;
			MyScreen = Mywindow->WScreen;
  		MyViewPort = &MyScreen->ViewPort;
			MyColorMap = MyViewPort->ColorMap;
			// Have to move the installer before the animation but after
			// openwindow
			moveInstaller ();			//Move installer Window
			myrec.MinX = 0;
			myrec.MinY = 0;
			myrec.MaxX = mywindowX;;
			myrec.MaxY = mywindowY;
			if (DoMethod(mydataobject, DTM_PROCLAYOUT, NULL, 1)) {
				GetDTAttrs (mydataobject, PDTA_DestBitMap,&mybitmapdtReMapped, TAG_END); // Getting remapped bitmap
				if (mybitmapdtReMapped != 0){
					//	Alloc Timerdevice
					CreateTimerWait();
					if (timerdevice == 0) {
						//	Filenotify Start.
						notifyAnim (myfilename);		
						skipwaitnewfile = FALSE;
						if (animspeed == 0)
							calcspeed = 0;
						else
							calcspeed = 1000000/animspeed;
						for (n=0;n<=animtype;n++){
							for (i=0;i<=animframes-1;i++){
								BltBitMapRastPort (mybitmapdtReMapped,mydestX,0,MyRastPort,place_Left,place_Top,mywindowX,mywindowY,0x0C0);
								// Timerwait, Waiting for Filenotify + time +ctrl c
								WaitTimer();
								if( sigs & SIGBREAKF_CTRL_C ) {
									// 	printf( "Ctrl-C ble trykket!\n" );
									i = 1000;
									n = 1000;
								}
								//	if( sigs & (1<<TimerPort->mp_SigBit) ) {
								//	printf( "Timer wait ok!\n" );
								//	}
								if( sigs & 1 <<mysignal ) {
									// 	printf( "Filenotify !\n" );		// Aborting loop !
									i = 1000;
									n = 1000;
									skipwaitnewfile = TRUE;
								}
						   // Gjør ikke noe om man tar AbortIO() på en request som er ferdig eller ubrukt!
								AbortIO( (struct IORequest *) TimerReq );					
								mydestX = mydestX + mywindowX;
							}
							mydestX = 0;
						}
						//	Endfilenotify !			
						EndNotify ( &Filenr);
					}
					//	Cleanup Timerdevice
					CleanupTimerWait();
					quit = 0;
					if (timerdevice != 0) {
						skipwaitnewfile = TRUE;
						quit = 1;
					}
				}
			}
		}
	}
	return 0;
}
// My Wait ********************************************
// The program will go throu this loop 2 times when changing picture.

int wait_for_picture ()
{
	// Close window and remove dt object if window is open.
	if (mywindowopen == TRUE) { 
		if (skipwaitnewfile != TRUE)
			notify (myfilename);
		CloseWindow (Mywindow);
		RemoveDTObject (Mywindow, mydataobject);
		DisposeDTObject (mydataobject);
		mywindowopen = FALSE;
		mydeletefile ();
	}

	// A new file have been copied or deleted
	else	{
		mycopyfile ();				//Copy picture
		readprefsfile ();		//Read config file
		if (animation == FALSE) {
			process_picture ();		//Process
			}
		// If prefsfile is an anim type then goto anim
		else {
			process_anim ();
		}	
	}
	return 0;
}

// Main ********************************************************

void main (int argc, char **argv)

{
	mytask = FindTask (NULL);
	mysignal = AllocSignal (-1);
	if (mysignal != -1) {

		IntuitionBase = (struct IntuitionBase*) OpenLibrary("intuition.library", 39);
		if (IntuitionBase != NULL) {

			DataTypesBase = OpenLibrary("datatypes.library", 39);
			if (DataTypesBase != NULL ) {
		
				GfxBase = OpenLibrary("graphics.library",39); 
				if (GfxBase != NULL ) { 

					mypool = CreatePool(MEMF_PUBLIC|MEMF_CLEAR,512,512);
					if (mypool != NULL) {

						MakeStrings ();
						if (makestringfailed == FALSE ) {
							get_screen_information ();
							while (quit == NULL)															// Main wait loop
								wait_for_picture ();
						}
						DeletePool(mypool);
					}
	  		}
			 	CloseLibrary(GfxBase);
			}
			CloseLibrary(DataTypesBase);	
  	}
  	CloseLibrary ((struct Library*) (IntuitionBase));
  }
	FreeSignal (mysignal);
}

