/************************************************************************
 *                                                                      *
 *  ModeP - replace graphic.library's BestModeID()                      *
 *                                                                      *
 *  written by Andreas R. Kleinert                                      *
 *  Andreas_Kleinert@t-online.de                                        *
 *                                                                      *
 *  No Assembler - 100 percent C                                        *
 *                                                                      *
 * V1.0 :                                                               *
 *        - first release                                               *
 *                                                                      *
 ************************************************************************/

#define __USE_SYSBASE

#include <exec/memory.h>
#include <intuition/intuitionbase.h>
#include <libraries/gadtools.h>
#include <graphics/gfxbase.h>

#include <cybergraphics/cybergraphics.h>

#include <vilintuisup.h>
#include <vilintuisup/ScreenMode.h>

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

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <proto/cybergraphics.h>
#include <vilintuisup/vilintuisup_protos.h>
#include <vilintuisup/vilintuisup_pragmas.h>

#define N (NULL)

struct IntuitionBase *IntuitionBase = N;
struct GfxBase       *GfxBase       = N;
struct Library       *CyberGfxBase  = N;
struct Library       *VilIntuiBase  = N;


APTR __far NewBestModeVec;
long __far __asm (*OrigBestModeVec)(register __a0 struct TagItem *tags_a0,
                                    register __a6 struct GfxBase *GfxBase_a6);


ULONG __saveds __asm NewBestMode(register __a0 struct TagItem *tags_a0,
                                 register __a6 struct GfxBase *GfxBase_a6)
{
 struct TagItem *tags    = tags_a0;
 struct GfxBase *GfxBase = GfxBase_a6;
 ULONG mode_id = N, old = FALSE;


 if(FindTagItem(BIDTAG_DIPFMustHave,    tags)) old = TRUE;
 if(FindTagItem(BIDTAG_DIPFMustNotHave, tags)) old = TRUE;
 if(FindTagItem(BIDTAG_ViewPort,        tags)) old = TRUE;
 if(FindTagItem(BIDTAG_MonitorID,       tags)) old = TRUE;
 if(FindTagItem(BIDTAG_SourceID,        tags)) old = TRUE;
 if(FindTagItem(BIDTAG_RedBits,         tags)) old = TRUE;
 if(FindTagItem(BIDTAG_BlueBits,        tags)) old = TRUE;
 if(FindTagItem(BIDTAG_GreenBits,       tags)) old = TRUE;

 if(old)
  {
   mode_id = OrigBestModeVec(tags, GfxBase);
  }else
  {
   struct TagItem *tag;

   ULONG width, height, depth;

   tag = FindTagItem(BIDTAG_NominalWidth, tags);
   if(tag)
    {
     width = tag->ti_Data;
    }else
    {
     tag = FindTagItem(BIDTAG_DesiredWidth, tags);
     if(tag) width = tag->ti_Data;
      else return(INVALID_ID);
    }

   tag = FindTagItem(BIDTAG_NominalHeight, tags);
   if(tag)
    {
     height = tag->ti_Data;
    }else
    {
     tag = FindTagItem(BIDTAG_DesiredHeight, tags);
     if(tag) height = tag->ti_Data;
      else return(INVALID_ID);
    }

   tag = FindTagItem(BIDTAG_Depth, tags);
   if(tag) depth = tag->ti_Data;
    else   depth = 1;
 
   if(CyberGfxBase)
    {
     struct TagItem modetags [4];

     modetags[0].ti_Tag  = CYBRBIDTG_Depth;
     modetags[1].ti_Tag  = CYBRBIDTG_NominalWidth;
     modetags[2].ti_Tag  = CYBRBIDTG_NominalHeight;
     modetags[3].ti_Tag  = TAG_END;

     if(depth < 8) modetags[0].ti_Data = 8;
      else         modetags[0].ti_Data = depth;
                   modetags[1].ti_Data = width;
                   modetags[2].ti_Data = height;
                   modetags[3].ti_Data = N;

     mode_id = BestCModeIDTagList(&modetags[0]);
    }else
    {
     if(VilIntuiBase)
      {
       struct TagItem modetags [4];

       modetags[0].ti_Tag  = TAVIS_SCREEN_WIDTH;
       modetags[1].ti_Tag  = TAVIS_SCREEN_HEIGHT;
       modetags[2].ti_Tag  = TAVIS_SCREEN_DEPTH;
       modetags[3].ti_Tag  = TAG_END;

                     modetags[0].ti_Data = width;
                     modetags[1].ti_Data = height;
       if(depth < 8) modetags[2].ti_Data = 8;
        else         modetags[2].ti_Data = depth;
                     modetags[3].ti_Data = N;

       mode_id = VillageBestModeID(&modetags[0]);
      }
    }

   if(   (mode_id == 0L) || (mode_id == INVALID_ID)
      || (ModeNotAvailable(mode_id))                )
    {
     /* Uses OverScan values for checking.         */
     /* Assumes an ECS-System, but checks for AGA. */

     /* with AGA, all resolutions work upto 8 Bit, so check */
     if(GfxBase->ChipRevBits0 & (1<<GFXB_AA_ALICE) ) depth = 1;

          if(width > 724 && depth < 3)   mode_id = SUPER_KEY;
     else if(width > 362 && depth < 5)   mode_id = HIRES_KEY;
     else                                mode_id = LORES_KEY;

     if(!ModeNotAvailable(mode_id | PAL_MONITOR_ID))    /* for PAL  Systems */
      {
       if(height > 283) mode_id |= LACE;

       mode_id |= PAL_MONITOR_ID;
      }else
      {
       if(!ModeNotAvailable(mode_id | NTSC_MONITOR_ID)) /* for NTSC Systems */
        {
         if(height > 241) mode_id |= LACE;

         mode_id |= NTSC_MONITOR_ID;
        }
      }
    }
  }

 return(mode_id);
}

/* *************************************************** */
/* *                                                 * */
/* * Compiler Stuff for BackgroundIO                 * */
/* *                                                 * */
/* *************************************************** */

long  __stack        = 8192;
char *__procname     = "ModeP";
long  __priority     = 1;
long  __BackGroundIO = 1;           /* TRUE : We DO BackGroundIO !     */

extern BPTR _Backstdout;            /* NULL, if started from Workbench */

void __regargs __chkabort(void) { }
void __regargs _CXBRK(void)     { }

char vertext [] = "\0$VER: ModeP V1.0";


typedef unsigned long (*FUNCCAST)();

long main(long argc, char **argv)
{
 long retval = 0;

 APTR task;

 Forbid();
 task = FindTask(N);
 Permit();

 if(task) SetTaskPri(task, __priority);


 CyberGfxBase = (APTR) OpenLibrary("cybergraphics.library", 40);
 VilIntuiBase = (APTR) OpenLibrary("vilintuisup.library", 1);


 IntuitionBase = (APTR) OpenLibrary("intuition.library", 39);
 if(IntuitionBase)
  {
   UtilityBase = (APTR) OpenLibrary("utility.library", 37);
   if(UtilityBase)
    {
     GfxBase = (APTR) OpenLibrary("graphics.library", 39);
     if(GfxBase)
      {
       OrigBestModeVec = (long (* __asm )(register __a0 struct TagItem *tags_a0,
                                          register __a6 struct GfxBase *GfxBase_a6)) SetFunction((APTR)GfxBase, -0x41a, (APTR)NewBestMode);
       if(OrigBestModeVec)
        {
         if(task) SetTaskPri(task, -10);
         Wait(SIGBREAKF_CTRL_C);
         if(task) SetTaskPri(task, 1);

         NewBestModeVec= (APTR) SetFunction((APTR)GfxBase, -0x41a, (APTR)OrigBestModeVec);

         if(NewBestModeVec!=NewBestMode)
          {
           ULONG idcmp = N;
           struct EasyStruct estr;

           estr.es_StructSize   = sizeof(struct EasyStruct);
           estr.es_Flags        = N;
           estr.es_Title        = "ModeP Request";
           estr.es_TextFormat   = "Error while removing from system !\n"
                                  "There were more patches !"
                                  "Do a reset soon !";
           estr.es_GadgetFormat = "Ok";

           EasyRequestArgs(N, &estr, (ULONG *) &idcmp, N);
          }

         CloseLibrary((struct Library *) GfxBase);
      
        }else retval = 20;

      }else retval = 20;

     CloseLibrary((struct Library *) UtilityBase);

    }else retval = 20;

   CloseLibrary((struct Library *) IntuitionBase);

  }else retval = 20;

 if(VilIntuiBase) CloseLibrary((struct Library *) VilIntuiBase);
 if(CyberGfxBase) CloseLibrary((struct Library *) CyberGfxBase);

 return(retval);
}
