//#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 

struct PubScreenNode BuggyPSN;

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

  ObtainSemaphoreShared(&MPSem->ListSem); 
  ObtainSemaphore(&MPSem->NodeSem);
  
  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
    NewList(&PubScreenList);

    psn=(struct PubScreenNode *)list->lh_Head;
    while(psn->psn_Node.ln_Succ)
    {
      if(npsn=AllocVec(sizeof(*npsn),MEMF_PUBLIC))
      {
        *npsn=*psn;
        AddTail(&PubScreenList,(struct Node *)npsn);
      }
      
      psn=(struct PubScreenNode *)psn->psn_Node.ln_Succ;
    }
    
    /* Make PSNodes for MP's pubscreens */
    
    dnode=(struct DefaultNode *)MPSem->PromotionList[PL_PUBLICSCREENS].lh_Head;
  
    while(dnode->Def_Node.ln_Succ)
    {
      if(!FindName(&PubScreenList,dnode->Def_Node.ln_Name))
      { /* Avoid Duplicates */
        if(npsn=AllocVec(sizeof(*npsn),MEMF_PUBLIC|MEMF_CLEAR))
        {
          npsn->psn_Node.ln_Name=dnode->Def_Node.ln_Name; // Safe to reference name since lists are protected till UnlockPubScreenList() 
          AddTail(&PubScreenList,(struct Node *)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(&PubScreenList);
}

void __saveds __asm NewUnlockPubScreenList(register __a6 struct IntuitionBase *IBase)
{
  struct PubScreenNode *psn;
  char tnamebuffer[52];
  char *tname;
  
  tname=SetupTaskName(tnamebuffer," in NewUnlockPubScreenList()",50);


  BuggyPSN.psn_Node.ln_Name="Bad LockPubScreenList() Access";
   //                        1234567890123456789012345678901234567890
   //                                 0         0         0         0
  PubListNest--;
  
  if(PubListNest==0)
  {
    while(psn=(struct PubScreenNode *)RemHead(&PubScreenList))
    {
      FreeVec(psn);
    }
    // Add bug alert 
    AddHead(&PubScreenList,(struct Node *)(&BuggyPSN));
  }
  
  OldUnlockPubScreenList((struct Library *)IBase);
  
  
DEBUG_CODE(
  DKP("UnlockPubScreenList()\n");
  )  

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