//#define DEBUG

#include "MP.h"
#include <debug.h>
#include <exec/lists.h>

extern struct MPSem *MPSem;

// LockPubScreenList
extern struct List * __asm (*OldLockPubScreenList)(register __a6 struct Library *);
extern void __asm (*OldUnlockPubScreenList)(register __a6 struct Library *);
  
struct List PubScreenList;
LONG PubListNest=0; // If Zero then Init 

#define PSNF_FAKE (1<<15) // Fake psn_Flags

struct List *IntuitionPubScreenList;

struct List * __saveds __asm NewLockPubScreenList(register __a6 struct IntuitionBase *IBase)
{
  struct PubScreenNode *psn,*npsn;
  struct DefaultNode *dnode;
  struct List *list;
  struct Task faketask={0};
  struct Screen *fakescr;
  
  char tnamebuffer[52];
  char *tname;
  
  tname=SetupTaskName(tnamebuffer,", LPSL",50);
  
DEBUG_CODE(
  DKP("LockPubScreenList()\n");
  )  

  ObtainSemaphoreShared(&MPSem->ListSem); 
  ObtainSemaphore(&MPSem->NodeSem);
  
  IntuitionPubScreenList=list=OldLockPubScreenList((struct Library *)IBase);

  /* Clone Old PS list */
  
  if(PubListNest==0)
  {
    // The OS nests calls to LockPubScreenList()/UnlockPubScreenList() only create the list when PubListNest==0

    /* Make PSNodes for MP's pubscreens */
    
    dnode=(struct DefaultNode *)MPSem->PromotionList[PL_PUBLICSCREENS].lh_Head;
  
    psn=(APTR)list->lh_Head;
    
    if(psn->psn_Node.ln_Succ)
    {
      while(dnode->Def_Node.ln_Succ)
      {
        if(!FindName(list,dnode->Def_Node.ln_Name))
        { /* Avoid Duplicates */
          if(npsn=AllocVec(sizeof(*npsn),MEMF_PUBLIC|MEMF_CLEAR))
          {
            if(fakescr=AllocVec(sizeof(*fakescr),MEMF_PUBLIC|MEMF_CLEAR))
            {
              /* Screen */
              fakescr->Width=dnode->Width;
              fakescr->Height=dnode->Height;
              fakescr->Title=dnode->Def_Node.ln_Name;
              fakescr->RastPort.BitMap=&fakescr->BitMap;
              fakescr->BitMap.Depth=dnode->Depth;
              
              npsn->psn_Node.ln_Name=dnode->Def_Node.ln_Name; // Safe to reference name since lists are protected till UnlockPubScreenList() 
              npsn->psn_Flags=PSNF_FAKE;
              npsn->psn_SigTask=&faketask;
              npsn->psn_Screen=fakescr; // Hmmm
              AddTail(list,(struct Node *)npsn);
            }
            else
            {
              FreeVec(npsn);
            }
          }
        }
        dnode=(struct DefaultNode *)dnode->Def_Node.ln_Succ;
      }
    }
  }
  else
  {
    // nested
  }


/*
  {
    LONG *l,q;
    
    l=0;
    
    *l=0;
  }*/
  
  PubListNest++; // Some dumb apps call LockPubScreen() inside LockPubScreenList()/UnlockPubScreenList()
  
  SetTaskName(tname);
  
  return(list);
}

void __saveds __asm NewUnlockPubScreenList(register __a6 struct IntuitionBase *IBase)
{
  struct PubScreenNode *psn,*p2;
  
  PubListNest--;
  
  
  if(PubListNest==0)
  {
    psn=(APTR)IntuitionPubScreenList->lh_Head;
    
    while(psn->psn_Node.ln_Succ)
    {
      DKP("psn=%8lx %s\n",psn,psn->psn_Node.ln_Name);
      if(psn->psn_Flags & PSNF_FAKE)
      {
        DKP("  free psn\n");
        p2=(APTR)psn->psn_Node.ln_Succ;
        Remove((APTR)psn);
        FreeVec(psn->psn_Screen);  // screen is fake to!
        FreeVec(psn);
        psn=p2;
      }
      else
      {
        psn=(APTR)psn->psn_Node.ln_Succ;
      }
    }
  }
  
  OldUnlockPubScreenList((struct Library *)IBase);
  
  
DEBUG_CODE(
  DKP("UnlockPubScreenList()\n");
  )  

  ReleaseSemaphore(&MPSem->NodeSem);      
  ReleaseSemaphore(&MPSem->ListSem);
}
