#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <exec/types.h>
#include <intuition/screens.h>
#include <intuition/intuition.h>
#include <devices/timer.h>

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

#include "EE_view.h"
#include "EE_timer.h"


__chip STATIC UWORD EmptyPointer[] =
{
	0, 0, 0, 0, 0
};

BACK_VIEW BackView;
UBYTE *ChunkyAdr;
ULONG tmpPalette[256*3+2];
LONG dPalette[256*3];


BOOL OpenBackView(VOID)
{
ULONG BackPalette[] = 
{
	0x00020000,
	0x00000000, 0x00000000, 0x00000000,
	0x00000000, 0x00000000, 0x00000000,
	0x00000000
};

  if((BackView.Screen = OpenScreenTags(NULL, SA_Left, 0,
																						 SA_Top, 0,
                                         		 SA_Width, 320,
                                          	 SA_Height, 256,
                                         		 SA_Depth, 1,
                                           	 SA_ShowTitle, FALSE,
																						 SA_Quiet, TRUE,
                                           	 SA_Type, CUSTOMSCREEN,
                                           	 SA_DisplayID, PAL_MONITOR_ID|LORES_KEY,
	                                           SA_Overscan, OSCAN_STANDARD,
  	                                         SA_AutoScroll, FALSE,
                                           	 SA_Draggable, FALSE,
                                           	 SA_Colors32, BackPalette,
                                           	 SA_VideoControl, NULL,
                                           	 SA_MinimizeISG, TRUE,
                                           	 TAG_DONE)) == NULL)
		return FALSE;

	if((BackView.Window = OpenWindowTags(NULL, WA_Left, 0,
																						 WA_Top, 0,
																						 WA_Width, 320,
																						 WA_Height, 200,
																						 WA_CustomScreen, BackView.Screen,
																						 WA_Backdrop, TRUE,
																						 WA_Borderless, TRUE,
																						 WA_NoCareRefresh, TRUE,
																						 WA_Activate, TRUE,
																						 WA_RMBTrap, TRUE,
																						 TAG_DONE)) == NULL)
	{
		CloseScreen(BackView.Screen);
		return FALSE;
	}

	SetPointer(BackView.Window, EmptyPointer, 1, 1, 0, 0);

	return TRUE;
}


VOID CloseBackView(VOID)
{

	if(BackView.Window)
		CloseWindow(BackView.Window);

	if(BackView.Screen)
		CloseScreen(BackView.Screen);
}


DVIEW *OpenView(ULONG Width, ULONG Height, ULONG Depth, ULONG ModeID,
								ULONG *Palette, ULONG Flags)
{
DVIEW *DView;
ULONG Interleaved;
ULONG Left, Top;

	if(Flags & DVF_CENTER)
	{
		if(Width > 320)
			if(Width > 640)
				Left = (1280 - Width) / 2;
			else
				Left = (640 - Width) / 2;
		else
			Left = (320 - Width) /2;

		if(Height > 256)
			Top = (512 - Height) / 2;
		else
			Top = (256 - Height) /2;
	}
	else
	{
		Left = 0;
		Top = 0;
	}

	if((DView = malloc(sizeof(DVIEW))) == NULL)
		return NULL;

	memset(DView, 0, sizeof(DVIEW));

	DView->Width = Width;
	DView->Height = Height;
	DView->Depth = Depth;
	DView->ModeID = ModeID;
	DView->Flags = Flags;

	if(Flags & DVF_INTERLEAVED)
		Interleaved = BMF_INTERLEAVED;
	else
		Interleaved = 0;

  if((DView->BitMap[0] = AllocBitMap(Width, Height, Depth,
                                     BMF_CLEAR | BMF_DISPLAYABLE | Interleaved,
                                     NULL)) == NULL)
	{
		CloseView(DView);
    return NULL;
	}

	if(Interleaved)
	  if(!(GetBitMapAttr(DView->BitMap[0], BMA_FLAGS) & BMF_INTERLEAVED))
  	{
	    CloseView(DView);
  	  return NULL;
	  }

	if(Flags & DVF_DBUFF)
	{
	  if((DView->BitMap[1] = AllocBitMap(Width, Height, Depth,
  	                                   BMF_CLEAR | BMF_DISPLAYABLE | Interleaved,
    	                                 NULL)) == NULL)
		{
			CloseView(DView);
    	return NULL;
		}

		if(Interleaved)
		  if(!(GetBitMapAttr(DView->BitMap[1], BMA_FLAGS) & BMF_INTERLEAVED))
  		{
	    	CloseView(DView);
	  	  return NULL;
		  }
	}

  if((DView->Screen = OpenScreenTags(NULL, SA_Left, Left,
                                           SA_Top, Top,
                                           SA_Width, Width,
                                           SA_Height, Height,
                                           SA_Depth, Depth,
                                           SA_BitMap, DView->BitMap[0],
                                           SA_ShowTitle, FALSE,
																					 SA_Quiet, TRUE,
                                           SA_Type, CUSTOMSCREEN,
                                           SA_DisplayID, ModeID,
                                           SA_Overscan, OSCAN_STANDARD,
                                           SA_AutoScroll, FALSE,
                                           SA_Draggable, FALSE,
                                           SA_Colors32, Palette,
                                           SA_Interleaved, Interleaved,
                                           SA_VideoControl, NULL,
                                           SA_MinimizeISG, TRUE,
                                           TAG_DONE)) == NULL)
  {
    CloseView(DView);
    return NULL;
  }

	DView->VP = &DView->Screen->ViewPort;

	if(Flags & DVF_DBUFF)
	{
	  if((DView->ScreenBuffer[0] = AllocScreenBuffer(DView->Screen,
  	                                               DView->BitMap[0],
    	                                             0)) == NULL)
	  {
  	  CloseView(DView);
    	return NULL;
	  }

  	if((DView->ScreenBuffer[1] = AllocScreenBuffer(DView->Screen,
	                                                 DView->BitMap[1],
	         	                                       0)) == NULL)
	  {
  	  CloseView(DView);
    	return NULL;
	  }

	  if((DView->RP[0] = malloc(sizeof(struct RastPort))) == NULL)
	  {
  	  CloseView(DView);
    	return NULL;
	  }

	  memset(DView->RP[0], 0, sizeof(struct RastPort));
	  InitRastPort(DView->RP[0]);
	  DView->RP[0]->BitMap = DView->BitMap[0];

	  if((DView->RP[1] = malloc(sizeof(struct RastPort))) == NULL)
  	{
    	CloseView(DView);
	    return NULL;
  	}

	  memset(DView->RP[1], 0, sizeof(struct RastPort));
  	InitRastPort(DView->RP[1]);
	  DView->RP[1]->BitMap = DView->BitMap[1];

	  if((DView->SafePort[0] = CreateMsgPort()) == NULL)
  	{
    	CloseView(DView);
	    return NULL;
  	}

	  if((DView->SafePort[1] = CreateMsgPort()) == NULL)
  	{
    	CloseView(DView);
	    return NULL;
  	}

	  if((DView->DisplayPort[0] = CreateMsgPort()) == NULL)
  	{
    	CloseView(DView);
	    return NULL;
  	}

	  if((DView->DisplayPort[1] = CreateMsgPort()) == NULL)
  	{
    	CloseView(DView);
	    return NULL;
  	}

	  DView->ScreenBuffer[0]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = DView->SafePort[0];
  	DView->ScreenBuffer[0]->sb_DBufInfo->dbi_DispMessage.mn_ReplyPort = DView->DisplayPort[0];
	  DView->ScreenBuffer[1]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = DView->SafePort[1];
  	DView->ScreenBuffer[1]->sb_DBufInfo->dbi_DispMessage.mn_ReplyPort = DView->DisplayPort[1];

	  ChangeScreenBuffer(DView->Screen, DView->ScreenBuffer[0]);

	  DView->Display = 0L;
  	DView->Render = 1L;

	  DView->DisplayRP = DView->RP[0];
  	DView->RenderRP = DView->RP[1];
	}
	else
	{
		DView->RP[0] = &DView->Screen->RastPort;

	  DView->Display = 0L;
  	DView->Render = 0L;

	  DView->DisplayRP = DView->RP[0];
  	DView->RenderRP = DView->RP[0];
	}

	if((DView->Window = OpenWindowTags(NULL, WA_Left, 0,
																					 WA_Top, 0,
																					 WA_Width, Width,
																					 WA_Height, Height,
																					 WA_CustomScreen, DView->Screen,
																					 WA_Backdrop, TRUE,
																					 WA_Borderless, TRUE,
																					 WA_NoCareRefresh, TRUE,
																					 WA_Activate, FALSE,
																					 WA_RMBTrap, TRUE,
																					 TAG_DONE)) == NULL)
	{
   	CloseView(DView);
    return NULL;
	}

	DView->WindowRP = DView->Window->RPort;

	SetPointer(DView->Window, EmptyPointer, 1, 1, 0, 0);

	if(Flags & DVF_CHUNKY)
	{
	  if((ChunkyAdr = malloc(Width*Height)) == NULL)
  	{
    	CloseView(DView);
	    return NULL;
  	}

		DView->Chunky = ChunkyAdr;
		DView->C2P = C2P_FI;

		ClearChunky(DView);
	}

	return DView;
}


VOID CloseView(DVIEW *DView)
{

	if(DView->Window)
	{
		ActivateWindow(BackView.Window);
		CloseWindow(DView->Window);
	}

	if(DView->Flags & DVF_CHUNKY)
		if(DView->Chunky != NULL)
		{
			free(DView->Chunky);
			ChunkyAdr = NULL;
		}

	if(DView->Flags & DVF_DBUFF)
	{
		SafeRender(DView);
	  WaitBlit();
  	while(!GetMsg(DView->DisplayPort[DView->Display]))
    	Wait(1L<<(DView->DisplayPort[DView->Display]->mp_SigBit));

	  if(DView->DisplayPort[1])
		{
	  	while(GetMsg(DView->DisplayPort[1]))
				printf("Wait dp1\n");
  	  DeleteMsgPort(DView->DisplayPort[1]);
		}

	  if(DView->DisplayPort[0])
		{
	  	while(GetMsg(DView->DisplayPort[0]))
				printf("Wait dp0\n");
  	  DeleteMsgPort(DView->DisplayPort[0]);
		}

	  if(DView->SafePort[1])
		{
	  	while(GetMsg(DView->SafePort[1]))
				printf("Wait sp1\n");
  	  DeleteMsgPort(DView->SafePort[1]);
		}

	  if(DView->SafePort[0])
		{
	  	while(GetMsg(DView->SafePort[0]))
				printf("Wait sp0\n");
  	  DeleteMsgPort(DView->SafePort[0]);
		}

	  if(DView->ScreenBuffer[1])
  	  FreeScreenBuffer(DView->Screen, DView->ScreenBuffer[1]);

	  if(DView->ScreenBuffer[0])
  	  FreeScreenBuffer(DView->Screen, DView->ScreenBuffer[0]);
	}

  if(DView->Screen)
    CloseScreen(DView->Screen);

	if(DView->Flags & DVF_DBUFF)
	{
	  if(DView->RP[1])
  	  free(DView->RP[1]);

	  if(DView->RP[0])
  	  free(DView->RP[0]);

		WaitBlit();

	  if(DView->BitMap[1])
  	  FreeBitMap(DView->BitMap[1]);
	}

	WaitBlit();

  if(DView->BitMap[0])
 	  FreeBitMap(DView->BitMap[0]);
}


VOID ClearChunky(DVIEW *DView)
{
LONG size;

	if(DView->Flags & DVF_CHUNKY)
		if((size = DView->Width*DView->Height) == 320*200)
			ClearChunky320x200(DView);
		else
			memset(ChunkyAdr, 0, size);
}


VOID SwitchView(DVIEW *DView)
{

	if(DView->Flags & DVF_DBUFF)
	{
	  WaitBlit();

  	while(!GetMsg(DView->DisplayPort[DView->Display]))
    	Wait(1L<<(DView->DisplayPort[DView->Display]->mp_SigBit));

	  DView->Display ^= 1L;
  	DView->Render ^= 1L;

	  DView->DisplayRP = DView->RP[DView->Display];
  	DView->RenderRP = DView->RP[DView->Render];

	  ChangeScreenBuffer(DView->Screen, DView->ScreenBuffer[DView->Display]);
	}
}


VOID SafeRender(DVIEW *DView)
{

	if(DView->Flags & DVF_DBUFF)
	  while(!GetMsg(DView->SafePort[DView->Display]))
  	  Wait(1L<<(DView->SafePort[DView->Display]->mp_SigBit));
}


VOID FadeInPalette(DVIEW *DView, ULONG *Palette,
									 ULONG r, ULONG g, ULONG b, LONG Time)
{
ULONG ColorsNumber;
LONG tmpTime;
LONG i;

	ColorsNumber = Palette[0]>>16;
	tmpPalette[0] = Palette[0];
	for(i=0; i<ColorsNumber; i++)
	{
		tmpPalette[i*3+1] = r;
		tmpPalette[i*3+2] = g;
		tmpPalette[i*3+3] = b;
	}
	tmpPalette[ColorsNumber*3+1] = 0L;

	FadeInSupport1(dPalette, Palette, r, g, b, Time);

	WaitTOF();
	LoadRGB32(DView->VP, tmpPalette);

	XEvent();

	do
	{
		tmpTime = GetCurrentXTime();
		if(tmpTime > Time)
			tmpTime = Time;

		FadeInSupport2(dPalette, tmpPalette, r, g, b, tmpTime);

		WaitTOF();
		LoadRGB32(DView->VP, tmpPalette);
	}
	while(tmpTime < Time);

	WaitTOF();
	LoadRGB32(DView->VP, Palette);
}


VOID FadeOutPalette(DVIEW *DView, ULONG *Palette,
									 ULONG r, ULONG g, ULONG b, LONG Time)
{
ULONG ColorsNumber;
LONG tmpTime;
LONG i;

	ColorsNumber = Palette[0]>>16;
	tmpPalette[0] = Palette[0];
	tmpPalette[ColorsNumber*3+1] = 0L;

	FadeOutSupport1(dPalette, Palette, r, g, b, Time);

	WaitTOF();
	LoadRGB32(DView->VP, Palette);

	XEvent();

	do
	{
		tmpTime = GetCurrentXTime();
		if(tmpTime > Time)
			tmpTime = Time;

		FadeOutSupport2(dPalette, tmpPalette, Palette, tmpTime);

		WaitTOF();
		LoadRGB32(DView->VP, tmpPalette);
	}
	while(tmpTime < Time);

	for(i=0; i<ColorsNumber; i++)
	{
		tmpPalette[i*3+1] = r;
		tmpPalette[i*3+2] = g;
		tmpPalette[i*3+3] = b;
	}
	WaitTOF();
	LoadRGB32(DView->VP, tmpPalette);
}


VOID DissolvePalette(DVIEW *DView, ULONG *Palette1, ULONG *Palette2,
										 LONG Time)
{
ULONG ColorsNumber;
LONG tmpTime;

	ColorsNumber = Palette1[0]>>16;
	tmpPalette[0] = Palette1[0];
	tmpPalette[ColorsNumber*3+1] = 0L;

	DissolveSupport1(dPalette, Palette1, Palette2, Time);

	WaitTOF();
	LoadRGB32(DView->VP, Palette1);

	XEvent();

	do
	{
		tmpTime = GetCurrentXTime();
		if(tmpTime > Time)
			tmpTime = Time;

		DissolveSupport2(dPalette, tmpPalette, Palette1, tmpTime);

		WaitTOF();
		LoadRGB32(DView->VP, tmpPalette);
	}
	while(tmpTime < Time);

	WaitTOF();
	LoadRGB32(DView->VP, Palette2);
}
