#include <exec/types.h>
#include <exec/lists.h>
#include <exec/libraries.h>
#include <utility/tagitem.h>
#include <devices/timer.h>
#include <dos/dos.h>
#include <intuition/screens.h>
#include <vilintuisup/vilintuisup_protos.h>
#include <vilintuisup/screenmode.h>
#include <vilintuisup.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>

#include <stdlib.h>
#include <string.h>
/*
 *  TagItems to open an autoscroll screen
 */

struct TagItem openscreentags[] = {
    {  TAVIS_SCREEN_MODEID, 0 },
    {  TAVIS_AUTOSCROLL, TRUE },
    {  TAVIS_OPEN_BEHIND, FALSE },
    {  TAVIS_SCREEN_HEIGHT, 0 },    /* to specify a new height */
    {  TAG_DONE, 0 }
};

/*
 *  TagItems for the VillageModeRequest call
 */

struct TagItem requesttags[] = {
    {  TAVIS_MINDEPTH, 8 },
    {  TAVIS_MAXDEPTH, 8 },
    {  TAG_DONE, 0 }
};

/*
 *  Library bases we need ...
 */

struct Library *VilIntuiBase;
struct IntuitionBase *IntuitionBase;

/*
 *  Fills a region in all color modes
 */

void FillVillageRegion(struct Screen *s, int xpos,  int ypos,
					 int width, int height, ULONG color)
{
   int screendepth;                /* how much bits per pixel ?         */
   int bpP;                        /* Bytes per Pixel                   */
   UBYTE *memstart;                /* where the screen starts in memory */
   struct VilFillRecord vilfill;   /* always needed by this function    */

   memstart    = LockVillageScreen(s);

   screendepth = VillageScreenData(s,TAVIS_SD_SCREEN_DEPTH);
   bpP         = (screendepth + 7) >> 3;

   /*
    *  fill up the structure
    */

   vilfill.DestAdr   = (APTR)(memstart + (xpos*bpP + (ypos * (s->Width*bpP))));
   vilfill.DestPitch = s->Width;
   vilfill.Width     = width;
   vilfill.Height    = height;
   vilfill.Color     = color;

   /*
    *  fill up the region
    */

   VillageRectFill(s,&vilfill); /* does it's own WaitVillageBlit() inside */

   /*
    * donn't forget this
    */

   UnLockVillageScreen(s);
}

/*
 * It might be usefull to have a function, which will return the
 * height, width or depth of a DisplayID. The next function will
 * do the job. Specify an ID and the dimension you want to get.
 * After a call the function returns the dimension value or -1.
 */

/*
 * Define more if you want to
 */

#define GDF_HEIGHT  0
#define GDF_WIDTH   1
#define GDF_DEPTH   2

LONG GetDimFromID(ULONG ID, ULONG Tag)
{
   DisplayInfoHandle Handle;
   struct DimensionInfo dimension;

   if (ID != INVALID_ID)
   {  if (Handle = FindDisplayInfo(ID))
      {  if (GetDisplayInfoData(Handle,(UBYTE *)&dimension,sizeof(dimension),DTAG_DIMS,0))
	 {
	    switch(Tag) {

	       case GDF_HEIGHT:
		      return dimension.Nominal.MaxY+1;
		      break;
	       case GDF_WIDTH:
		      return dimension.Nominal.MaxX+1;
		      break;
	       case GDF_DEPTH:
		      return dimension.MaxDepth;
		      break;
	       default:
		      return -1;
		      break;
	    }
	 }
      }
   }
   return -1;
}


/*
 *  the main program
 */

int main(int argc, char *argv[])
{
   struct Screen *s = 0;
   UBYTE *boardmem;
   UBYTE *firstbuffer, *secondbuffer;
   int switchcounter = 4;
   int scrollamount  = 2;

   if (argc >= 2) {  scrollamount = atoi(argv[1]); }
   if (argc >= 3) {  switchcounter = atoi(argv[2]); }

   /*
    * first open all required libraries, notice the 2 behind "vilintuisup.l..."
    * VillageModeRequest was not available in version 1.x !!!
    */

   if (VilIntuiBase = OpenLibrary("vilintuisup.library",2))
   {  if (IntuitionBase = (struct IntuitionBase *)
			  OpenLibrary("intuition.library",37))
      {
	 /*
	  * let the user choose the display mode
	  * remember: every time check against INVALID_ID, not NULL!!
	  */

	 if ((openscreentags[0].ti_Data = VillageModeRequest(requesttags))
	     != INVALID_ID)
	 {
	    /*
	     * The user clicked on "O.K.". In this demo we want to open
	     * an autoscroll screen with double height. For this we have
	     * to supply a height to OpenVillageScreenTagList.
	     *
	     * For that we must get a height from the ID the user has
	     * chosen. The function GetDimFromID will do the job.
	     */

	    openscreentags[3].ti_Data =
		    GetDimFromID(openscreentags[0].ti_Data, GDF_HEIGHT) * 2;

	    /*
	     * all OK to open the screen
	     */

	    if (s = OpenVillageScreenTagList(openscreentags))
	    {
	       /*
		* OK, the screen is open, let's have a look at the height
		* The height is doubled!
		*/

	       Printf("Screen Height %4ld, Width %4ld\n",s->Height, s->Width);

	       /*
		* Before doing anything lock the screen first
		*/

	       boardmem = LockVillageScreen(s);

	       /*
		* Too set colors in 8Bit modes use SetRGB4 as usual
		*/

	       SetRGB4(&(s->ViewPort),0,0,0,0);       /* color 0 = black     */
	       SetRGB4(&(s->ViewPort),1,100,100,100); /* color 1 = dark gray */
	       SetRGB4(&(s->ViewPort),2,255,  0,  0); /* color 2 = red       */
	       SetRGB4(&(s->ViewPort),3,  0,255,  0); /* color 3 = green     */
	       SetRGB4(&(s->ViewPort),4,  0,  0,255); /* color 4 = blue      */

	       /*
		* Now get the pointers to the start of memory and of the memory
		* not visible
		*/

	       firstbuffer  = VillageGetBufAddr(s,0);
	       secondbuffer = VillageGetBufAddr(s,1);

	       /*
		* fill the buffer with "color"
		* this is the slow method, using VillageRectFill is better
		*/

	       memset(firstbuffer, '\x00',s->Height/2*s->Width);
	       memset(secondbuffer,'\x01',s->Height/2*s->Width);

	       /*
		* now switch some times
		*/

	       do
	       {  int i = 0;
		  /*
		   * fills a region with a color out of (red, green, blue)
		   */

		  FillVillageRegion(s,100,100+s->Height/2,s->Width-200,
				      (s->Height/2)-200,(switchcounter % 3)+2);
		  /*
		   * this slows down significantly, but has to be called
		   */

		  WaitVillageBlit();

		  /*
		   * switch to the second buffer
		   */

		  while (i < s->Height/2)
		  {  MoveScreen(s,0,-scrollamount);
		     i += scrollamount;
		     //TimeDelay(UNIT_MICROHZ,0,20000);
		  }

		  // VillageSetDisplayBuf(s,1);

		  /*
		   * fills a region with a color out of (red, green, blue)
		   */

		  FillVillageRegion(s,100,100,s->Width-200,(s->Height/2)-200,
				      4-(switchcounter % 3));
		  /*
		   * this slows down significantly, but has to be called
		   */

		  WaitVillageBlit();

		  /*
		   * switch to the first buffer
		   */

		  while (i > 0)
		  {  MoveScreen(s,0,scrollamount);
		     i -= scrollamount;
		     //TimeDelay(UNIT_MICROHZ,0,20000);
		  }
		  // VillageSetDisplayBuf(s,0);

	       } while (--switchcounter);

	       /*
		* there might be some more useful thing to do left
		*/

	       /*
		* don't forget to UnLock the screen
		*/

	       UnLockVillageScreen(s);

	       /*
		* only close with CloseVillageScreen(), never use CloseScreen()!!
		*/

	       CloseVillageScreen(s);

	    }  /* if (OpenVIllageScreenTagList(openscreentags)) */

	 }  /* the User clicked on "O.K." */

	 CloseLibrary((struct Library *)IntuitionBase);
      }
      CloseLibrary(VilIntuiBase);
   }

   /*
    * if the screen was not open (s == 0) return RETURN_FAIL
    */

   return s ? RETURN_OK : RETURN_FAIL;
}

