#include <proto/asl.h>

#include "xmris.h"
#include "ConfigScreen.h"

#include "Catalog.h"
#include "Errors.h"

/************************************************************************/

struct AsyncAslMessage ScreenMessage;

static struct List DisplayModes=
{
  (struct Node *)&DisplayModes.lh_Tail,NULL,(struct Node *)&DisplayModes.lh_Head
};

/************************************************************************/

static void FreeDisplayModes(void)

{
  struct DisplayMode *Mode;

  while ((Mode=(struct DisplayMode *)RemHead(&DisplayModes))!=NULL)
    {
      GS_MemoryFree(Mode->dm_Node.ln_Name);
      GS_MemoryFree(Mode);
    }
}

/************************************************************************/

static INLINE int MakeDisplayModes(void)

{
  int Success;

  Success=TRUE;

  {
    struct List *Screens;
    struct PubScreenNode *Screen;

    Screens=LockPubScreenList();
    for (Screen=(struct PubScreenNode *)Screens->lh_Head;
	 Success && Screen->psn_Node.ln_Succ!=NULL;
	 Screen=(struct PubScreenNode *)Screen->psn_Node.ln_Succ)
      {
	struct DisplayMode *Mode;

	if ((Mode=GS_MemoryAlloc(sizeof(*Mode)+strlen(Screen->psn_Node.ln_Name)+1))!=NULL)
	  {
	    Mode->dm_Node.ln_Name=NULL;
	    strcpy((char *)(Mode+1),Screen->psn_Node.ln_Name);
	    AddTail(&DisplayModes,&Mode->dm_Node);
	  }
	else
	  {
	    Success=FALSE;
	  }
      }
    UnlockPubScreenList();
  }

  if (Success)
    {
      struct DisplayMode *Mode;

      if ((Mode=GS_MemoryAlloc(sizeof(*Mode)))!=NULL)
	{
	  char *Name;

	  Name=GetString(MSG_DEFAULT_PUBSCREEN);
	  if ((Mode->dm_Node.ln_Name=GS_MemoryAlloc(strlen(Name)+1))!=NULL)
	    {
	      strcpy(Mode->dm_Node.ln_Name,Name);
	    }
	  AddHead(&DisplayModes,&Mode->dm_Node);
	}
      else
	{
	  Success=FALSE;
	}
    }

  if (Success)
    {
      struct DisplayMode *Mode, *Next;
      UWORD Count;

      Count=0;
      for (Mode=(struct DisplayMode *)DisplayModes.lh_Head;
	   Success && (Next=(struct DisplayMode *)Mode->dm_Node.ln_Succ)!=NULL;
	   Mode=Next)
	{
	  struct Screen *Screen;
	  int Keep;

	  Keep=FALSE;
	  if ((Screen=LockPubScreen(Count==0 ? NULL : (char *)(Mode+1)))!=NULL)
	    {
	      if (display.Screen==NULL || display.Screen->Screen!=Screen || display.Screen->Misc.Foreign)
		{
		  struct DrawInfo *DrawInfo;

		  if ((DrawInfo=GetScreenDrawInfo(Screen))!=NULL)
		    {
		      if (Screen->Width>=WINDOW_WIDTH+Screen->WBorLeft+Screen->WBorRight &&
			  Screen->Height>=WINDOW_HEIGHT+Screen->WBorTop+Screen->WBorBottom+DrawInfo->dri_Font->tf_YSize+1)
			{
			  if (Count!=0)
			    {
			      char *t;

			      t=(char *)(Mode+1);
			      Mode->dm_Node.ln_Name=GS_FormatString(GetString(MSG_CUSTOMMODE_HEADER),&t,NULL,Locale);
			    }
			  if (Mode->dm_Node.ln_Name!=NULL)
			    {
			      ULONG ID;

			      if ((ID=GetVPModeID(&Screen->ViewPort))!=INVALID_ID)
				{
				  if (GetDisplayInfoData(NULL,(UBYTE *)&Mode->dm_DimensionInfo,sizeof(Mode->dm_DimensionInfo),DTAG_DIMS,ID))
				    {
				      Mode->dm_DimensionInfo.Header.DisplayID=0xffff0000 | Count;
				      Mode->dm_PropertyFlags=0;
				      Keep=TRUE;
				    }
				}
			    }
			}
		      FreeScreenDrawInfo(Screen,DrawInfo);
		    }
		}
	      UnlockPubScreen(NULL,Screen);
	      if (!Keep)
		{
		  Remove(&Mode->dm_Node);
		  GS_MemoryFree(Mode->dm_Node.ln_Name);
		  GS_MemoryFree(Mode);
		}
	    }
	  Count++;
	}
    }

  return Success;
}

/************************************************************************/

void OpenConfigScreen(void)

{
  if (ScreenMessage.Requester==NULL)
    {
      if ((AslBase=OpenLibrary((char *)AslName,0))!=NULL)
	{
	  static struct TagItem TagList[]=
	    {
	      {ASLSM_Screen, (ULONG)NULL},	/* 0 */
	      {ASLSM_InitialDisplayWidth, 0},	/* 1 */
	      {ASLSM_InitialDisplayHeight, 0},	/* 2 */
	      {ASLSM_InitialDisplayDepth, 0},	/* 3 */
	      {ASLSM_DoWidth, TRUE},
	      {ASLSM_DoHeight, TRUE},
	      {ASLSM_DoDepth, TRUE},
	      {ASLSM_PropertyMask, 0},
	      {ASLSM_MinWidth, WINDOW_WIDTH},
	      {ASLSM_MinHeight, WINDOW_HEIGHT},
	      {ASLSM_CustomSMList, (ULONG)&DisplayModes},
	      {TAG_DONE}
	    };

	  if (MakeDisplayModes())
	    {
	      ScreenMessage.Message.mn_ReplyPort=&MiscPort;
	      if (display.Screen!=NULL)
		{
		  TagList[0].ti_Data=(ULONG)display.Screen->Screen;
		  TagList[3].ti_Data=display.DrawInfo->dri_Depth;
		}
	      else
		{
		  TagList[0].ti_Data=(ULONG)ErrorWindow->WScreen;
		  TagList[3].ti_Data=8;
		}
	      if (display.window!=NULL)
		{
		  TagList[1].ti_Data=display.window->Width;
		  TagList[2].ti_Data=display.window->Height;
		}
	      else
		{
		  TagList[1].ti_Data=WINDOW_WIDTH+((struct Screen *)TagList[0].ti_Data)->WBorLeft+((struct Screen *)TagList[0].ti_Data)->WBorRight;
		  TagList[2].ti_Data=WINDOW_HEIGHT+ErrorWindow->BorderTop+((struct Screen *)TagList[0].ti_Data)->WBorBottom;
		}
	      ScreenMessage.Requester=AllocAslRequestTags(ASL_ScreenModeRequest,
							  ASLSM_Locale, Locale,
							  ASLSM_InitialDisplayID, GetVPModeID(&((struct Screen *)TagList[0].ti_Data)->ViewPort),
							  ASLSM_TitleText, GetString(MSG_SCREENREQUESTER_TITLE),
							  TAG_MORE, TagList);
	    }
	  if (ScreenMessage.Requester==NULL)
	    {
	      FreeDisplayModes();
	      CloseLibrary(AslBase);
	    }
	}
    }
  if (ScreenMessage.Message.mn_Node.ln_Type==NT_UNKNOWN && ScreenMessage.Requester!=NULL)
    {
      AsyncAslRequest(&ScreenMessage);
    }
}

/************************************************************************/

int ProcessConfigScreen(void)

{
  int Result;

  Result=FALSE;
  if (ScreenMessage.Result)
    {
      char *Description;

      if ((((struct ScreenModeRequester *)ScreenMessage.Requester)->sm_DisplayID & 0xffff0000)==0xffff0000)
	{
	  if (((struct ScreenModeRequester *)ScreenMessage.Requester)->sm_DisplayID==0xffff0000)
	    {
	      Description=NULL;
	      Result=TRUE;
	    }
	  else
	    {
	      struct DisplayMode *Mode;

	      for (Mode=(struct DisplayMode *)DisplayModes.lh_Head;
		   Mode->dm_DimensionInfo.Header.DisplayID!=((struct ScreenModeRequester *)ScreenMessage.Requester)->sm_DisplayID;
		   Mode=(struct DisplayMode *)Mode->dm_Node.ln_Succ)
		;
	      Mode++;
	      if ((Description=GS_FormatString("PUBSCREEN=\"%s\"",&Mode,NULL,NULL))!=NULL)
		{
		  Result=TRUE;
		}
	    }
	}
      else
	{
	  if ((Description=GS_FormatString("MODEID=%lu WIDTH=%lu HEIGHT=%lu DEPTH=%u",&((struct ScreenModeRequester *)ScreenMessage.Requester)->sm_DisplayID,NULL,NULL))!=NULL)
	    {
	      Result=TRUE;
	    }
	}
      if (Result)
	{
	  GS_MemoryFree(ScreenDescription);
	  ScreenDescription=Description;
	}
    }
  else
    {
      if (ScreenMessage.Error!=0)
	{
	  char String[ERRORSTRING_LENGTH];

	  DisplayError(MSG_ASL_ERROR,GetString(MSG_CONFIGSCREEN_ERROR),ErrorString(String,ScreenMessage.Error));
	}
    }
  FreeAslRequest(ScreenMessage.Requester);
  ScreenMessage.Requester=NULL;
  FreeDisplayModes();
  CloseLibrary(AslBase);
  ScreenMessage.Message.mn_Node.ln_Type=NT_UNKNOWN;
  return Result;
}
