
//#define DEBUG
#include <debug.h>

#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/utility.h>
  
#include <math.h>
#include <stdlib.h>

#include <graphics/modeid.h>
#include <extras/macros/exec.h>
#include <tagitemmacros.h>

#include "mp.h"

LONG MyAbs(LONG L);

ULONG ValidDisplayID(ULONG DispID);
ULONG ValidMonitorID(ULONG DispID);

extern struct MPSem *MPSem;

LONG MyAbs(LONG L)
{
  if(L<0)
    return(-L);
  return(L);
}


  
ULONG MyBestModeID(Tag Tags, ... )
{
  struct TagItem *taglist,*tag,*tstate;
  ULONG id,bestid,bestscore,score,disq; //(disqualified)
  ULONG data,
        sourceid,
        monitorid=MONITOR_ID_MASK,
        depth,
        dipfmusthave,
        dipfmustnothave;
  LONG  nwidth,
        nheight,
        dwidth,
        dheight;
  struct DisplayInfo    dis;      
  struct DimensionInfo  dim;
  
  depth=  dipfmusthave= dipfmustnothave=  nwidth=  nheight=  dwidth=  dheight=0;  
  
  taglist=(APTR)&Tags;

DEBUG_CODE(DKP("MyBestModeID()\n"););

  ProcessTagList(taglist,tag,tstate)
  {
    data=tag->ti_Data;
    switch(tag->ti_Tag)
    {
      case BIDTAG_SourceID:
        sourceid=data;
DEBUG_CODE(DKP("BIDTAG_SourceID 0x%08lx\n",data););
        if(GetDisplayInfoData(0,(APTR)&dis,sizeof(dis),DTAG_DISP,sourceid))
        {
          dipfmusthave=(dis.PropertyFlags & (DIPF_IS_DUALPF | DIPF_IS_PF2PRI | DIPF_IS_HAM | DIPF_IS_EXTRAHALFBRITE));
        }
        
        if(GetDisplayInfoData(0,(APTR)&dim,sizeof(dim),DTAG_DIMS,sourceid))
        {
          dwidth  =nwidth  =(dim.Nominal.MaxX-dim.Nominal.MinX);
          dheight =nheight =(dim.Nominal.MaxY-dim.Nominal.MinY);
        }   
        break;
      case BIDTAG_MonitorID:
DEBUG_CODE(DKP("BIDTAG_MonitorID 0x%08lx\n",data););
        monitorid=ValidMonitorID(data);//                                                              (4.62.10)
        break;
      case BIDTAG_Depth:
DEBUG_CODE(DKP("BIDTAG_Depth %ld\n",data););
        depth=min(data,32);
        break;
      case BIDTAG_DIPFMustHave:
DEBUG_CODE(DKP("BIDTAG_DIPFMustHave 0x%08lx\n",data););
        dipfmusthave=data;
        break;
      case BIDTAG_DIPFMustNotHave:
DEBUG_CODE(DKP("BIDTAG_DIPFMustNotHave 0x%08lx\n",data););
        dipfmustnothave=data;
        break;
      case BIDTAG_DesiredWidth:
DEBUG_CODE(DKP("BIDTAG_DesiredWidth %ld\n",data););
        dwidth=data;
        break;
      case BIDTAG_DesiredHeight:
DEBUG_CODE(DKP("BIDTAG_DesiredHeight %ld\n",data););
        dheight=data;
        break;
      case BIDTAG_NominalWidth:
DEBUG_CODE(DKP("BIDTAG_NominalWidth %ld\n",data););
        nwidth=data;
        break;
      case BIDTAG_NominalHeight:
DEBUG_CODE(DKP("BIDTAG_NominalHeight %ld\n",data););
        nheight=data;     
        break;
    }
  }
  
  if(!nwidth)
    nwidth=dwidth;
  
  if(!nheight)
    nheight=dheight;

/*  if(!dwidth)//                                                                                      (4.62.13)
    dwidth=nwidth;//                                                                                   (4.62.13)
  //                                                                                                   (4.62.13)
  if(!dheight)//                                                                                       (4.62.13)
    dheight=nheight;//                                                                                 (4.62.13)
*///                                                                                                   (4.62.13)

  bestscore=0;
  bestid=
  id=INVALID_ID;
  
  while(INVALID_ID != (id=NextDisplayInfo(id)))
  {
    disq=0;
    score=0;

DEBUG_CODE(DKP("\n");DKP("  Comparing 0x%08lx\n",id););

    if(GetDisplayInfoData(0,(APTR)&dis,sizeof(dis),DTAG_DISP,id))
    {
DEBUG_CODE(DKP("    PropertyFlags 0x%08lx   MustHave 0x%08lx   MustNotHave 0x%08lx\n",id,dipfmusthave,dipfmustnothave););      
      /* make sure it has dipfmusthave flags */
      if(dipfmusthave != (dipfmusthave & dis.PropertyFlags))
      {
DEBUG_CODE(DKP("      Missing Flags\n"););
        disq=1;
      }
      
      /* make sure it doesn't have dipfmustnothave flags */
      if(dipfmustnothave & dis.PropertyFlags)
      {
DEBUG_CODE(DKP("      Has unwanted Flags\n"););
        disq=1;
      }
    }

    if(monitorid!=MONITOR_ID_MASK)
    {
      if(monitorid != (id & MONITOR_ID_MASK))
      {
DEBUG_CODE(DKP("    Invalid Monitor\n"););
        disq=1;
      }
    }
    
    if(GetDisplayInfoData(0,(APTR)&dim,sizeof(dim),DTAG_DIMS,id))
    {
      LONG width,height,ws,hs,ds;
      
      width   =dim.Nominal.MaxX - dim.Nominal.MinX + 1;
      height  =dim.Nominal.MaxY - dim.Nominal.MinY + 1;
      
      ws=65536-MyAbs(nwidth  - width);
      hs=65536-MyAbs(nheight - height);
      ds=0;

      if(depth>0)
      {
        if(depth>dim.MaxDepth)
        {
DEBUG_CODE(DKP("    Invalid Depth\n");); 
          disq=1;
        }
        else
        {
          if(depth<9) // register
          {
            if(dim.MaxDepth<9) // weed out true color screens
            {
              ds=65536;
            }
          }
          else // truecolor
          {
            if(dim.MaxDepth>8) // weed out register screens
            {
              ds=65536-(abs(dim.MaxDepth-depth)*2048);
            }
          }
        }
      }
      
      score+=ws+hs+ds;
      
DEBUG_CODE(DKP("    Width %ld (%ld)   Height %ld (%ld)  Depth %ld (%ld) (Score)\n",width,ws,height,hs,dim.MaxDepth,ds););      
    }
    
    if(!disq)
    {
DEBUG_CODE(DKP("    -- Score:%ld\n",score););
      
      if(score>bestscore)
      {
        bestid=id;
        bestscore=score;
      }
    }
    else
    {
DEBUG_CODE(DKP("    Disqualified\n"););
    }
  }
  
  DEBUG_CODE(DKP("  BestMode 0x%08lx\n",bestid););
  
  return(bestid);  
}



ULONG ValidMonitorID(ULONG DispID)//                                                                   (4.62.9)
{
  ULONG id;
  
  DispID &= MONITOR_ID_MASK;
  id=NextDisplayInfo(INVALID_ID);

  while(id!=INVALID_ID)
  {
    if((id & MONITOR_ID_MASK) == DispID)
      return(DispID);
    id=NextDisplayInfo(id);
  }
  return(MONITOR_ID_MASK);
}

/*
ULONG ValidDisplayID(ULONG DispID)
{
  ULONG previd=(INVALID_ID & MONITOR_ID_MASK),
        id,mid;
  
  id=NextDisplayInfo(INVALID_ID);

  while(id!=INVALID_ID)
  {
    if(id == DispID)
      return(DispID);
      
    id=NextDisplayInfo(id);
  }
  
  return(INVALID_ID);
}*/