#ifndef APP_List_H
#define APP_List_H
/******************************************************************************
 **
 **	C++ Class Library for the Amiga© system software.
 **
 **	Copyright (C) 1994 by Armin Vogt  **  EMail: armin@uni-paderborn.de
 **	All Rights Reserved.
 **
 **	$VER: apphome:APlusPlus/exec/List.h 1.04 (04.05.94) $
 **	
 ******************************************************************************/


extern "C" {
#ifdef __GNUG__
#include <inline/exec.h>
#include <clib/alib_protos.h>
#endif

#ifdef __SASC
#include <proto/exec.h>
#endif

#include <exec/lists.h>
}
#include <iostream.h>


class MinListC;

class MinNodeC : private MinNode
{
   friend MinListC;
   private:
      /** set a node to a state when its repeated remove cannot cause pointer trash.
       ** (succ and pred point to the node itself, so Remove() cannot afflict other memory)
       **/
      void neutralize() { mln_Succ = mln_Pred = this; }

   public:
      MinNodeC() { neutralize(); }           // allowes removing an unattached node
      virtual ~MinNodeC();
      MinNodeC *succ() { return (MinNodeC*)(mln_Succ->mln_Succ==NULL?NULL:mln_Succ); }
      MinNodeC *pred() { return (MinNodeC*)(mln_Pred->mln_Pred==NULL?NULL:mln_Pred); }
      void remove() { Remove((Node*)(MinNode*)this); neutralize(); }
      BOOL isLonelyNode() { return (succ()==this); }

      virtual BOOL applyMinNodeC(void *any);    // your subclass should overwrite this
      MinListC *findList(void);    // get the MinListC object that this is linked to.
};


void MinListC__Destruct(MinListC *list);
BOOL MinListC__Member(MinListC *list,MinNodeC *find);
MinNodeC *MinListC__RemoveSafely(MinListC *list,MinNodeC *node);


class MinListC : private MinList
{
   public:
      MinListC() { NewList((List*)(MinList*)this); }
      virtual ~MinListC();

      BOOL empty() { return (mlh_Head->mln_Succ==0); }
      BOOL isEmpty() { return empty(); }
      MinNodeC *head() { return (MinNodeC*)( empty() ? NULL : mlh_Head ); }
      MinNodeC *tail() { return (MinNodeC*)( empty() ? NULL : mlh_TailPred ); }

      void addHead(MinNodeC *node) { AddHead((List*)(MinList*)this,(Node*)(MinNode*)node); }
      void addTail(MinNodeC *node) { AddTail((List*)(MinList*)this,(Node*)(MinNode*)node); }

      MinNodeC *remHead() { MinNodeC *node = (MinNodeC*)RemHead((List*)(MinList*)this);
                            if (node) node->neutralize(); return node; }
      MinNodeC *remTail() { MinNodeC *node = (MinNodeC*)RemTail((List*)(MinList*)this);
                            if (node) node->neutralize(); return node; }

      BOOL member(MinNodeC *node) { return MinListC__Member(this,node); }
      MinNodeC *remove(MinNodeC *node) { return MinListC__RemoveSafely(this,node); }
      void insert(MinNodeC *node,MinNodeC *pred);  // insert new node before pred

      BOOL apply(void *any);
      // run the applyMinNodeC on all list nodes with <any> as parameter.
      // Stops if applyNodeC returned FALSE, and returns FALSE!!! else returns TRUE.
};

class ListC;

class NodeC : private Node
{
   private:
      void neutralize() { ln_Succ = ln_Pred = this; }

   protected:
      UBYTE*& name_ref() { return (UBYTE*&)ln_Name; }

   public:
      NodeC(BYTE pri = 0, UBYTE type = NT_USER) { ln_Pri = pri; ln_Name = NULL; ln_Type = type; }
      NodeC(BYTE pri, const UBYTE* name = 0, UBYTE type = NT_USER)
            { ln_Pri = pri; ln_Name = (char*)name; ln_Type = type; }
      NodeC(const UBYTE* name, UBYTE type = NT_USER)
            { ln_Pri = 0; ln_Name = (char*)name; ln_Type = type; }
      virtual ~NodeC();         // removes node from any list

      NodeC *succ() { return (NodeC*)(ln_Succ->ln_Succ==NULL?NULL:ln_Succ); }
      NodeC *pred() { return (NodeC*)(ln_Pred->ln_Pred==NULL?NULL:ln_Pred); }
      void remove() { Remove((Node*)this); neutralize(); }
      BOOL isLonelyNode() { return (ln_Succ==this); }

      virtual BOOL applyNodeC(void *any);       // your subclass should overwrite this

      BYTE priority() { return ln_Pri; }              // read priority
      void setPriority(BYTE pri) { ln_Pri = pri; }    // write priority

      const UBYTE* name() { return (UBYTE*)ln_Name; }                      // read name
      void setName(const UBYTE* set_name) { ln_Name = (char*)set_name; }   // write name

      UBYTE type() { return ln_Type; }                // read type
      void setType(UBYTE type) { ln_Type = type; }    // write type

      UBYTE& type_ref() { return ln_Type; }

      ListC *findList() { return (ListC*) ((MinNodeC*)(List*)this)->findList(); }

      //operator MinNodeC* () { return (MinNodeC*)(MinNode*)(Node*)this; }
};


/**********************************************************************************************
         » ListC class «
   encapsulates the EXEC list.
 **********************************************************************************************/
class ListC : private List
{
   public:
      ListC(UBYTE type = 0) { NewList((List*)this); lh_Type = type; }
      virtual ~ListC();

      BOOL empty() { return (lh_Head->ln_Succ==0); }
      BOOL isEmpty() { return empty(); }     // synonym for empty()
      NodeC *head() { return (NodeC*)( empty() ? NULL : lh_Head ); }
      NodeC *tail() { return (NodeC*)( empty() ? NULL : lh_TailPred ); }

      ListC& addHead(NodeC *node) { AddHead((List*)this,(Node*)node); return *this; }
      ListC& addTail(NodeC *node) { AddTail((List*)this,(Node*)node); return *this; }
      ListC& enqueue(NodeC *node) { Enqueue((List*)this,(Node*)node); return *this; }
      void   insert(NodeC *node,NodeC *pred);  // insert new node before pred
      NodeC *remHead() { return (NodeC*) ((MinListC*)this)->remHead(); }
      NodeC *remTail() { return (NodeC*) ((MinListC*)this)->remTail(); }
      NodeC *remove(NodeC *node) { return (NodeC*)MinListC__RemoveSafely((MinListC*)this,(MinNodeC*)node); }

      BOOL member(NodeC *node)
            { return MinListC__Member((MinListC*)this,(MinNodeC*)node); }
      NodeC *findName(const UBYTE* name)
            { return (NodeC*)FindName((List*)this,(UBYTE*)name); }

      BOOL apply(void *any);
};


inline void MinListC::insert(MinNodeC *node,MinNodeC *pred)
{
   if (!member(node) && member(pred))  // must not insert already inserted node or behind non-member!
      Insert((List*)this,(Node*)node,(Node*)pred);
}

inline void ListC::insert(NodeC *node,NodeC *pred)
{
   if (!member(node) && member(pred))  // must not insert already inserted node or behind non-member!
      Insert((List*)this,(Node*)node,(Node*)pred);
}

/** Give your node type and a pointer to your list and you will get a pointer "node" to
 ** your node type in the subsequent loop body. Of course your node type must be derived
 ** from MinNode or Node class as must your list be derived from MinList or List class.
 ** This loop does NOT allow to delete the node object within the loop, since the successor
 ** could not be read from an invalid node! Also FOREACHOF() within another FOREACHOF loop
 ** shadowes the first node. Instead use the macro with explicit variable name.
 ** This hides the type conflict with the return type of the list classes in the absence of
 ** parameterized classes (templates). As soon as templates are available all list classes
 ** will be doubled with template classes.
 **/
#define FOREACHOF(type,list) for(type *node=(type*)((list)->head());node;node=(type*)node->succ())
#define FOREACHOFNAME(type,list,node) for(type *node=(type*)((list)->head());node;node=(type*)node->succ())


/** This loop allows deleting the object addressed in 'node'.
 ** Add NEXTSAFE behind your loop body (behind the closing brace if there is one)
 **/
#define FOREACHSAFE(type,list) for(type *node=(type*)((list)->head()),*next=NULL;node;node=next) \
   { next=(type*)node->succ();

#define NEXTSAFE }

#endif	/* APP_List_H */
