/**
 * Scout - The Amiga System Monitor
 *
 *------------------------------------------------------------------
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * You must not use this source code to gain profit of any kind!
 *
 *------------------------------------------------------------------
 *
 * @author Andreas Gelhausen
 * @author Richard Körber <rkoerber@gmx.de>
 */



#include "system_headers.h"

int  smodecnt;

APTR smodemoretext0,smodemoretext1,smodemoretext2,smodemoretext3,smodemoretext4,smodemoretext5;
APTR smodemoretext6,smodemoretext7,smodemoretext8,smodemoretext9,smodemoretext10,smodemoretext11;
APTR smodemoretext12,smodemoretext13,smodemoretext14,smodemoretext15,smodemoretext16,smodemoretext17;
APTR smodemoretext18,smodemoretext19,smodemoretext20;

static APTR SModePool = NULL;

__asm __saveds LONG smodelist_cmpidfunc (register __a1 struct SModeEntry *se1, register __a2 struct SModeEntry *se2)
{
   return (LONG)(se1->sme_smodeid - se2->sme_smodeid);
}

struct Hook smodelist_cmpidhook = {
 {NULL, NULL},
 (ULONG (* )())smodelist_cmpidfunc,
 NULL, NULL
};

__asm __saveds LONG smodelist_cmpresfunc (register __a1 struct SModeEntry *se1, register __a2 struct SModeEntry *se2)
{
   long  eins = 0, zwei = 0;

   IsDec (se1->sme_width, &eins);
   IsDec (se2->sme_width, &zwei);
   if (eins == zwei) {
      IsDec (se1->sme_height, &eins);
      IsDec (se2->sme_height, &zwei);
      if (eins == zwei) {
         IsDec (se1->sme_depth, &eins);
         IsDec (se2->sme_depth, &zwei);
      }
   }
   return eins - zwei;
}

struct Hook smodelist_cmpreshook = {
 {NULL, NULL},
 (ULONG (* )())smodelist_cmpresfunc,
 NULL, NULL
};

__asm __saveds LONG smodelist_cmpnamefunc (register __a1 struct SModeEntry *se1, register __a2 struct SModeEntry *se2)
{
   LONG cmp;

   cmp = strcmpi(se1->sme_name, se2->sme_name);
   if (cmp == 0) cmp = (LONG)(se1->sme_smodeid - se2->sme_smodeid);

   return cmp;
}

struct Hook smodelist_cmpnamehook = {
 {NULL, NULL},
 (ULONG (* )())smodelist_cmpnamefunc,
 NULL, NULL
};


__asm __saveds LONG smodelist_dspfunc(register __a2 char **array, register __a1 struct SModeEntry *smodeentry, register __a0 struct Hook *hook)
{
   if (smodeentry) {
      *array++ = smodeentry->sme_id;
      *array++ = smodeentry->sme_width;
      *array++ = smodeentry->sme_height;
      *array++ = smodeentry->sme_depth;
      *array   = smodeentry->sme_name;
   } else {
      *array++ = ESC "bModeID";
      *array++ = ESC "bWidth";
      *array++ = ESC "bHeight";
      *array++ = ESC "bDepth";
      *array   = ESC "bScreenMode";
   }
   return (0);
}

struct Hook smodelist_dsphook = {
 {NULL, NULL},
 (ULONG (* )())smodelist_dspfunc,
 NULL, NULL
};

void FreeSMode (void)
{
    MyFreePoolStructs(&SModePool, smodetext, NULL, smodelist);
}

void GetSModeEntry (struct SModeEntry *smentry, ULONG id) {

   struct NameInfo idname;
   struct DimensionInfo iddim;

   if (! smentry->sme_smodeid) {
      smentry->sme_smodeid = id;
      _sprintf (smentry->sme_id, "$%08lx", id);
   }

   GetDisplayInfoData(NULL,(UBYTE *)&iddim,sizeof(struct DimensionInfo),DTAG_DIMS,id);
   _sprintf (smentry->sme_width,  "%5ld" ,iddim.Nominal.MaxX-iddim.Nominal.MinX+1);
   _sprintf (smentry->sme_height, "%5ld" ,iddim.Nominal.MaxY-iddim.Nominal.MinY+1);
   _sprintf (smentry->sme_depth,  "%5ld" ,(iddim.MaxDepth==32 ? 24 : iddim.MaxDepth));

   if(GetDisplayInfoData(NULL,(UBYTE *)&idname,sizeof(struct NameInfo),DTAG_NAME,id)) {
      strncpy (smentry->sme_name,idname.Name,DISPLAYNAMELEN);
   } else {
      struct MonitorInfo idmon;
      struct DisplayInfo iddisp;

      if(GetDisplayInfoData(NULL,(UBYTE *)&idmon,sizeof(struct MonitorInfo),DTAG_MNTR,id)) {
         if(GetDisplayInfoData(NULL,(UBYTE *)&iddisp,sizeof(struct DisplayInfo),DTAG_DISP,id)) {
            ULONG  prop = iddisp.PropertyFlags;
            WORD   xres = iddim.Nominal.MaxX - iddim.Nominal.MinX;
            STRPTR namebuf = smentry->sme_name;

            //? if(idmon.Mspc) ...

            NameCopy(namebuf,idmon.Mspc->ms_Node.xln_Name);
            if(namebuf[0]=='E') {
              if(!strcmp(namebuf,"EURO72:")) strcpy(namebuf,"EURO:72Hz ");
              if(!strcmp(namebuf,"EURO36:")) strcpy(namebuf,"EURO:36Hz ");
            }

                 if(xres > 1200) strcat(namebuf,"SuperHighRes");
            else if(xres > 600)  strcat(namebuf,"HighRes");
            else if(xres > 300)  strcat(namebuf,"LowRes");
            else                 strcat(namebuf,"ExtraLowRes");

            if(prop&DIPF_IS_DUALPF        ) {
               strcat(namebuf," DualPF"   );
               if(prop&DIPF_IS_PF2PRI) strcat(namebuf,"2");
            }
            if(prop&DIPF_IS_HAM           ) strcat(namebuf," HAM"      );
            if(prop&DIPF_IS_EXTRAHALFBRITE) strcat(namebuf," EHB"      );
            if(prop&DIPF_IS_LACE          ) strcat(namebuf," Interlace");
            if(prop&DIPF_IS_SCANDBL       ) strcat(namebuf," DblScan"  );

         } else {
            strncpy (smentry->sme_name,idmon.Mspc->ms_Node.xln_Name,DISPLAYNAMELEN);
         }
      } else {
         strcpy(smentry->sme_name," < ??? >");
      }
   }
}

int GetSMode (struct SModeEntry **first) {
   struct  SModeEntry   *smentry,*previous = NULL;

   int smcnt = 0;
   *first = 0;

   if (!SModePool) SModePool = tbCreatePool(MEMF_CLEAR, 4096, 4096);

   if (clientstate) {
      if (SendDaemon ("GetSModeList")) {
         while ((smentry = tbAllocPooled(SModePool, sizeof(struct SModeEntry))) \
           && (ReceiveDecodedEntry ((UBYTE *) smentry, sizeof (struct SModeEntry)))) {
            IsHex (smentry->sme_id, (LONG *)&smentry->sme_smodeid);

            if (! *first)
               *first = smentry;
            if (previous)
               previous->sme_next = smentry;

            smcnt++;
            previous = smentry;
         }
      }
   } else {
      ULONG currid = INVALID_ID;

      while((currid=NextDisplayInfo(currid)) != INVALID_ID)
      {
         if(smentry = tbAllocPooled(SModePool, sizeof(struct SModeEntry))) {
            GetSModeEntry(smentry,currid);

            if (! *first)
               *first = smentry;
            if (previous)
               previous->sme_next = smentry;

            smcnt++;
            previous = smentry;
         }
      }
   }
   return (smcnt);
}

void PrintSMode (char *filename) {
   int   i=1;
   BPTR  handle;
   struct SModeEntry *entryp = NULL;

   handle = HandlePrintStart (filename);
   if ((handle) && (PrintOneLine (handle, "\n  ModeID    Wdth  Hght  Dpth  ScreenMode\n\n"))) {
      if (! WI_SMode) {
         i = GetSMode (&entryp);
      }
      if (i) {
         for (i=0;;i++) {
            if (WI_SMode)
               DoMethod (smodelist,MUIM_List_GetEntry,i,&entryp);
            if (!entryp) break;

            _sprintf (tmpstr2, " %s %5s %5s %2s  %s\n", entryp->sme_id, entryp->sme_width, entryp->sme_height, entryp->sme_depth, entryp->sme_name);
            if (! (PrintOneLine (handle, tmpstr2)))
               break;

            if (! WI_SMode)
               entryp = entryp->sme_next;
         }
      }
   }
   HandlePrintStop();
}

void ShowSMode (void) {
   struct   SModeEntry   *sm;

   ApplicationSleep();
   set(smodelist,MUIA_List_Quiet,TRUE);
   set(smodelist,MUIA_List_CompareHook,smodelist_cmphook_ptr);
   set(BT_SModeMore, MUIA_Disabled, TRUE);
   FreeSMode();

   smodecnt = GetSMode (&sm);

   while (sm) {
      InsertSortedEntry (smodelist, (APTR *) &sm);
      sm = sm->sme_next;
   }

   SetCountText (smodecount, smodecnt);
   AwakeApplication();
   set(smodelist,MUIA_List_Quiet,FALSE);
}

void SendSModeList (void) {
   struct   SModeEntry   *sm;

   FreeSMode();
   GetSMode (&sm);

   while (sm) {
      SendEncodedEntry ((UBYTE *) sm, sizeof (struct SModeEntry));
      sm = sm->sme_next;
   }
   FreeSMode();
}

void GetSModeMore (struct SModeEntry *sm) {
   unsigned char     *title = "SCREENMODE: ";
   struct   WinFree  *ptr;
   ULONG    id = sm->sme_smodeid;
   struct   DisplayInfo   iddisp;
   struct   DimensionInfo iddims;
   struct   MonitorInfo   idmntr;
   struct   NameInfo      idname;

   GetDisplayInfoData(NULL,(UBYTE *)&iddisp,sizeof(struct DisplayInfo)  ,DTAG_DISP,id);
   GetDisplayInfoData(NULL,(UBYTE *)&iddims,sizeof(struct DimensionInfo),DTAG_DIMS,id);
   GetDisplayInfoData(NULL,(UBYTE *)&idmntr,sizeof(struct MonitorInfo)  ,DTAG_MNTR,id);

   if (ptr = AllocWinFree()) {
      ptr->wf_Window = (APTR) WindowObject,
      MUIA_Window_SizeGadget, TRUE,
      MUIA_HelpNode, ScreenModeText,
      MUIA_Window_ID, MakeDetailID('.','S','M','D'),
      WindowContents, VGroup,
         Child, ColGroup(2),
            Child, MyLabel2 ("Name:"),
            Child, smodemoretext0 = MyTextObject(),
            Child, MyLabel2 ("Monitor:"),
            Child, smodemoretext6 = MyTextObject(),
            Child, MyLabel2 ("Compatibility:"),
            Child, HGroup,
               Child, smodemoretext16 = MyTextObject2(),
               Child, MyLabel2 ("="),
               Child, smodemoretext17 = MyTextObject(),
            End,
         End,
         Child, HGroup,
            Child, VGroup,
               Child, MyLabel2 ("ModeID:\nPreferred:"),
               Child, MyLabel2 ("Property:"),
               Child, MyLabel2 ("NotAvail:"),
               Child, MyLabel2 ("PixelSpeed:\nTicks/Pixel:"),
               Child, MyLabel2 ("StdSprites:\nTicks/Pixel:"),
               Child, MyLabel2 ("Palette:\nRGB bits:"),
               Child, MyLabel2 ("MouseTicks:"),
            End,
            Child, VGroup, MUIA_Group_SameWidth, TRUE, MUIA_Weight, 0,
               Child, smodemoretext15 = MyTextObject(),
               Child, smodemoretext1  = KeyButtonF ('l', iddisp.PropertyFlags),
               Child, smodemoretext2  = KeyButtonF ('w', iddisp.NotAvailable),
               Child, smodemoretext3  = MyTextObject(),
               Child, smodemoretext4  = MyTextObject(),
               Child, smodemoretext5  = MyTextObject(),
               Child, smodemoretext20 = MyTextObject(),
            End,
            Child, HSpace(0),
            Child, VGroup,
               Child, MyLabel2 ("MinRaster:\nMaxRaster:"),
               Child, MyLabel2 ("Nominal:\nOffset:"),
               Child, MyLabel2 ("TxtOScan:\nOffset:"),
               Child, MyLabel2 ("StdOScan:\nOffset:"),
               Child, MyLabel2 ("MaxOScan:\nOffset:"),
               Child, MyLabel2 ("VideoOScan:\nOffset:"),
            End,
            Child, VGroup, MUIA_Group_SameWidth, TRUE, MUIA_Weight, 0,
               Child, smodemoretext8  = MyTextObject(),
               Child, smodemoretext9  = MyTextObject(),
               Child, smodemoretext11 = MyTextObject(),
               Child, smodemoretext10 = MyTextObject(),
               Child, smodemoretext13 = MyTextObject(),
               Child, smodemoretext12 = MyTextObject(),
            End,
            Child, HSpace(0),
            Child, VGroup,
               Child, MyLabel2 ("Depth:\nColors:"),
               Child, MyLabel2 ("H freq.:\nV freq.:"),
               Child, MyLabel2 ("TotalRows:\nColorClocks:\n=\nMinRow:"),
               Child, MyLabel2 ("ViewPosition:\nDefault VP:\nViewResolution:\nVP Range min:\nmax:"),
            End,
            Child, VGroup, MUIA_Group_SameWidth, TRUE, MUIA_Weight, 0,
               Child, smodemoretext19 = MyTextObject(),
               Child, smodemoretext18 = MyTextObject(),
               Child, smodemoretext7  = MyTextObject(),
               Child, smodemoretext14 = MyTextObject(),
            End,
         End,
      End, End;

      if (ptr->wf_Window) {
         char   colors[20];
         ULONG  fh, fv;
         STRPTR compathelp;
         UWORD  dep  = iddims.MaxDepth;
         ULONG  prop = iddisp.PropertyFlags;
         ULONG  tcc  = idmntr.TotalColorClocks*280;

         if(GetDisplayInfoData(NULL,(UBYTE *)&idname,sizeof(struct NameInfo),DTAG_NAME,id)) {
            MySetContents (smodemoretext0, "%s", idname.Name);
         } else {
            MySetContents (smodemoretext0, ESC "8%s", sm->sme_name);
         }
         MySetContents(smodemoretext6,"$%08lx \"%s\" (OpenCnt=%ld)", idmntr.Mspc, idmntr.Mspc->ms_Node.xln_Name, (WORD)idmntr.Mspc->ms_OpenCount);

         HandleFlagsButtonPressed(smodemoretext1, ptr, "(SCREENMODE)", "PropertyFlags", prop                , (struct LongFlag *)&dip_flags    , NULL, 'l');
         HandleFlagsButtonPressed(smodemoretext2, ptr, "(SCREENMODE)", "NotAvailable",  iddisp.NotAvailable , (struct LongFlag *)&diavail_flags, NULL, 'w');

         fv = 1000000L / (idmntr.TotalColorClocks * 28);
         fh = (fv * 100) / idmntr.TotalRows;

         if(prop&DIPF_IS_DUALPF) {
            _sprintf(colors,"2x%ld",1<<(dep>>1));
         } else if(prop&DIPF_IS_HAM) {
            _sprintf(colors,"[%ld]",1<<(3*(dep-2)));
         } else if(dep>24) {
            strcpy(colors,"> 16.8M");
         } else {
            _sprintf(colors,"%ld",1<<dep);
         }

         MySetContents(smodemoretext3, ESC "r%ld ns\n%ld x %ld", iddisp.PixelSpeed, iddisp.Resolution.x, iddisp.Resolution.y);
         MySetContents(smodemoretext4, ESC "r%ld\n%ld x %ld", iddisp.NumStdSprites, iddisp.SpriteResolution.x, iddisp.SpriteResolution.y);
         MySetContents(smodemoretext5, ESC "r%ld\n%ld:%ld:%ld", iddisp.PaletteRange, iddisp.RedBits, iddisp.GreenBits, iddisp.BlueBits);
         MySetContents(smodemoretext7, ESC "r%ld\n%ld\n%ld.%03ld µs\n%ld", idmntr.TotalRows, idmntr.TotalColorClocks, tcc/1000, tcc%1000, idmntr.MinRow);
         MySetContents(smodemoretext8, ESC "c%5ld x %5ld\n%5ld x %5ld", iddims.MinRasterWidth, iddims.MinRasterHeight, iddims.MaxRasterWidth, iddims.MaxRasterHeight);
         MySetContents(smodemoretext9, ESC "c%4ld x %4ld\n%4ld x %4ld", iddims.Nominal.MaxX-iddims.Nominal.MinX+1, iddims.Nominal.MaxY-iddims.Nominal.MinY+1, iddims.Nominal.MinX, iddims.Nominal.MinY);
         MySetContents(smodemoretext10, ESC "c%4ld x %4ld\n%4ld x %4ld", iddims.StdOScan.MaxX-iddims.StdOScan.MinX+1, iddims.StdOScan.MaxY-iddims.StdOScan.MinY+1, iddims.StdOScan.MinX, iddims.StdOScan.MinY);
         MySetContents(smodemoretext11, ESC "c%4ld x %4ld\n%4ld x %4ld", iddims.TxtOScan.MaxX-iddims.TxtOScan.MinX+1, iddims.TxtOScan.MaxY-iddims.TxtOScan.MinY+1, iddims.TxtOScan.MinX, iddims.TxtOScan.MinY);
         MySetContents(smodemoretext12, ESC "c%4ld x %4ld\n%4ld x %4ld", iddims.VideoOScan.MaxX-iddims.VideoOScan.MinX+1, iddims.VideoOScan.MaxY-iddims.VideoOScan.MinY+1, iddims.VideoOScan.MinX, iddims.VideoOScan.MinY);
         MySetContents(smodemoretext13, ESC "c%4ld x %4ld\n%4ld x %4ld", iddims.MaxOScan.MaxX-iddims.MaxOScan.MinX+1, iddims.MaxOScan.MaxY-iddims.MaxOScan.MinY+1, iddims.MaxOScan.MinX, iddims.MaxOScan.MinY);
         MySetContents(smodemoretext14, ESC "c%4ld x %4ld\n%4ld x %4ld\n%4ld x %4ld\n%4ld x %4ld\n%4ld x %4ld", idmntr.ViewPosition.x, idmntr.ViewPosition.y, idmntr.DefaultViewPosition.x, idmntr.DefaultViewPosition.y, idmntr.ViewResolution.x, idmntr.ViewResolution.y, idmntr.ViewPositionRange.MinX, idmntr.ViewPositionRange.MinY, idmntr.ViewPositionRange.MaxX, idmntr.ViewPositionRange.MaxY);
         MySetContents(smodemoretext15, ESC "r$%08lx\n$%08lx", id, idmntr.PreferredModeID);
         MySetContents(smodemoretext16, "%2ld", idmntr.Compatibility);
         MySetContents(smodemoretext18, ESC "r%ld kHz\n%ld Hz",fv/10,fh);
         MySetContents(smodemoretext19, ESC "r%ld\n%s",dep,colors);
         MySetContents(smodemoretext20, ESC "r%ld x %ld", idmntr.MouseTicks.x, idmntr.MouseTicks.y);

         switch(idmntr.Compatibility)
         {
           case MCOMPAT_MIXED:
              compathelp = "MCOMPAT_MIXED: can share display with other MIXED";
              break;
           case MCOMPAT_SELF:
              compathelp = "MCOMPAT_SELF: can share only within monitor";
              break;
           case MCOMPAT_NOBODY:
              compathelp = "MCOMPAT_NOBODY: only one viewport";
              break;
           default:
              compathelp = ESC "8< ??? >";
         }
         MySetContents(smodemoretext17,"%s",compathelp);

//*         MySetContents (smodemoretext3, ESC "r$%08x\n" ESC "c%s\n%d\n" ESC "r$%08x\n$%08x", bc, GetCxNodeType(CxObjType((CxObj *)bc)),bc->mco_Node.ln_Pri, bc->mco_Task, bc->mco_Port);
//*         MySetContentsHealed (cxmoretext5, "%s", nonetest (GetTaskName (bc->mco_Task)));

         HandleWindowOpen (ptr, title, sm->sme_name);
         HandleWindowClose (ptr);
      }
   }
}


APTR SModeSortList[] = {
   &smodelist_cmpidhook,
   &smodelist_cmpnamehook,
   &smodelist_cmpreshook,
   NULL
};

static const char *CYA_SModeSortText[] = {
   "ModeID",
   "name",
   "resolution",
   NULL
};

APTR WI_SMode, smodelist, smodetext, smodecount, CY_SModeSort;
int  smodesortstate = 0;
APTR BT_SModeUpdate, BT_SModePrint, BT_SModeMore, BT_SModeExit;

char smode_title[WINDOWTITLELEN];

void SModeWindow (BOOL state) {
   if (state) {
      if (WI_SMode) {
         ShowSMode();
      } else {
         WI_SMode = WindowObject,
         MUIA_Window_Title, MyGetWindowTitle (smode_title, "SCREENMODE"),
         MUIA_HelpNode, ScreenModeText,
         MUIA_Window_ID, MakeListID('S','M','D','E'),
         WindowContents, VGroup,
            Child, smodelist = MyListviewObject ("DELTA=8,DELTA=8,DELTA=8,DELTA=8,",&smodelist_dsphook),
            Child, MyBelowSortedListview (&smodetext, &smodecount, &CY_SModeSort, CYA_SModeSortText, smodesortstate),
            Child, MyVSpace(2),
            Child, HGroup, MUIA_Group_SameSize, TRUE,
               Child, BT_SModeUpdate     = KeyButtonA (UpdateText   ,ID_SMODEUPDATE),
               Child, BT_SModePrint      = KeyButtonA (PrintText    ,ID_SMODEPRINT),
               Child, BT_SModeMore       = KeyButtonA (MoreText     ,ID_SMODEMORE),
               Child, BT_SModeExit       = KeyButtonA (ExitText     ,ID_SMODEEXIT),
            End,
         End, End;

         if (WI_SMode) {
            DoMethod (AP_Scout,OM_ADDMEMBER,WI_SMode);
            DoMethod (WI_SMode,MUIM_Window_SetCycleChain,smodelist,CY_SModeSort,BT_SModeUpdate,BT_SModePrint,BT_SModeMore,BT_SModeExit,NULL);
            DoMethod (CY_SModeSort, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, AP_Scout, 2, MUIM_Application_ReturnID, ID_SMODESORT);

            SetCloseRequest (WI_SMode,ID_SMODEEXIT);
            SetListActive (smodelist,ID_SMODELV_ACTIVE);
            SetListviewDoubleClick (smodelist,ID_SMODEMORE);

            ShowSMode();

            SetWindowOpen (WI_SMode,smodelist,ID_SMODEEXIT);
         }
      }
   } else if ((! state) && (WI_SMode)) {
      SetWindowClose (WI_SMode,TRUE);
      FreeSMode();
      DoMethod (AP_Scout,OM_REMMEMBER,WI_SMode);
      MUI_DisposeObject (WI_SMode);
      WI_SMode = NULL;
      smodelist = NULL;
   }
}

