#ifndef CC_LIST_H
#define CC_LIST_H
//
// Die OOP-Definition einer 'vollständig unabhängigen' Liste.
//
// 12.03.1992 Andre	Idee, erste Geanken, gelesen (RKM_EXEC)
// 13.03.1992 Andre	ein erster Versuch
//

// Nur unter AmigaOS Intuition und die Displayfunktionen zugänglich machen
#ifdef amigados
extern "C" {
#include <exec/types.h>
#include <exec/lists.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>
#include <graphics/displayinfo.h>
};

// Weiterhin *muß* irgendwo im entsprechende Hauptprogramm IntuitionBase
// und GadToolsBase deklariert und *initialisiert* sein
extern struct IntuitionBase *IntuitionBase;
extern struct GadToolsBase  *GadToolsBase;

// Außerdem müssen noch die beiden nächsten Variablen deklariert und
// initialisiert sein:
extern struct Screen	    *theScreen;
extern APTR		     VisualInfo;
// Diese Initialisierung wird i.a. folgendermassen Durchgeführt:
//
//  if ( NOT( theScreen = LockPubScreen( "Workbench" )))  - oder anderen Namen
//    error(...);
//  if ( NOT( VisualInfo = GetVisualInfo( theScreen, TAG_DONE )))
//    error(...);
#endif

enum copyway
{
   nocopy, copy
};

enum dsply
{
   readonly, readwrite
};

class node
{
   node 	 *succ;      // Eine doppelt verkettete Liste
   node 	 *pred;
   long 	  pri;	     // Die Priorität des Elements (klein: unwichtig)
   char 	 *name;      // Der Name
   unsigned long  pack;      // Gepackte vier Byte als Kurznamen
 public:
			     // Der Konstruktor
   node(char *n, copyway cw=copy, long pr=0, unsigned long pa=0);
   ~node(void);              // Der Destruktor

			     // Methoden der Liste

   node *getsucc(void);      // Holt den Zeiger auf den nächsten Knoten
   node *getpred(void);      // Holt den Zeiger auf den Vorgänger

   void setsucc(node *s);    // Setzt den Nachfolger auf s
   void setpred(node *p);    // Setzt den Vorgaenger auf p

			     // Methoden der Daten

   long getpri(void);        // Ließt die Priorität des Knotens
   char *getname(void);      // Ließt den Namen des Knotens
   unsigned long getpack(void); // Ließt den gepackten Namen des Knotens

   void setpri(long p);      // Setzt die Priorität des Knotens neu
   void setname(char *n, copyway cw=copy); // Setzt den Namen neu
			     // wenn cw auf 'copy' gesetzt ist (was
			     // Voreinstellung ist), wird der Name vor der
			     // Verwendung kopiert. Bei 'nocopy' wird das
			     // Kopieren unterlassen.
   void setpack(unsigned long pa);  // Setzt den gepackten Namen neu
   void setpackchar(char *p); // Setzt den gepackten Namen neu, und zwar
			     // werden dazu die ersten vier Zeichen des
			     // Strings gepackt. Ist der String kürzer als
			     // vier Zeichen, so wird mit Nullen aufgefüllt.

   // Die Funktionen zum Ausgeben
      void print(void);
};


// Und die Klasse der Listen

class list
{
   node     head;	     // Der vordere Anker
   node     tail;	     // Der hintere Anker
 public:
   list(void);               // Der Konstruktor
   ~list(void);              // Der Destruktor

   node *getfirst(void);
   node *getlast(void);

   // Allgemeine Komanndos der Liste

   void insert(node *p, node *the);  // Kettet 'the' nach 'p' in die
			     // Liste ein.
   void remove(node *n);     // Der Knoten 'n' wird aus der Liste entfernt.


   // Spezielle Anfangs- und Endmethoden.

   void addhead(node *n);    // Fügt einen Knoten am Anfang einer Liste ein.
   void addtail(node *n);    // Fügt einen Knoten am Anfang einer Liste ein.

   node *remhead(void);      // Nimmt den ersten Knoten aus der Liste und
			     // gibt ihn zurück.
   node *remtail(void);      // Nimmt den letzten Knoten aus der Liste und
			     // gibt ihn zurück.


   // Spezielle Einfügekomandos

   void enqueuepri(node *n); // Fügt den Knoten aufgrund seiner
			     // Priorität in die Liste ein. Ganz vorne stehen
			     // die Elemente mit kleiner Priorität.
   void enqueuename(node *n); // s.o. Kriterium ist hier die
			     // alphabetische Reihenfolge der Namen.
   void enqueuepack(node *n); // s.o. Hier ist das Sortierkriterium
			     // der gepackte Name.

   // Spezielle Suchkommandos

   node *findpri(long p);    // Sucht die Liste nach einem Element mit
			     // der Priorität 'p' ab, wenn ein solches
			     // existiert, wird es zurückgegeben, wenn nicht
			     // wird NULL zurückgegeben.
   node *findname(char *n);  // s.o. hier jedoch mit Namen
   node *findpack(unsigned long pa); // s.o. aber mit Pack


   // Sortiert kann die Liste auch werden

   void sortpri(void);       // Nach Priorität sortieren
   void sortname(void);      // Nach Name sortieren
   void sortpack(void);      // Nach Pack sortieren


   // Ausgabekommandos

   void print(void);         // Gibt die Liste nach stdout aus.

   // Alles weitere nur unter AmigaOS vorhanden.
#ifdef amigados
 private:
   struct Window *displaywin; // Der Zeiger auf das Display Window.
			     // NULL, wenn das Window geschlossen.
   struct Gadget *g;	     // Zeiger auf das ListGadget
   struct Gadget *glist;     // Die Gadgetliste für GadTools.
   struct Menu	 *menu;      // Die Menues des Fensters
   struct List execlist;     // Die Daten des ScrollerGadget müssen in einer
			     // Liste abgelegt sein. Dies ist sie!

   int change;		     // Gibt an, ob die Liste gerade geändert
			     // wird (dann hat 'change' den Wert 1, sonst 0)

   // Alle folgenden Variablen sind nur dazu da, den Status eines ver-
   // steckten Fensters zu speichern, um dann bei einem 'reveal' wieder
   // an der richtigen Stelle mit der richtigen Größe und den richtigen
   // Daten zu erscheinen.
   int W_hide;		     // gibt an, ob das Fenster versteckt ist:
			     // 0 - nicht versteckt
			     // 1 - versteckt
   int W_xpos, W_ypos, W_height, W_width; // Achtung!! W_height und W_width
			     // sind in Anzahl der Pixel angegeben! (zum
			     // Unterschied im Aufruf von display().
   char *W_wintitle, *W_scrtitle;
   struct MsgPort *W_mp;     // Der shard-Port.
   dsply	   W_ds;     // Anzeigemodus.
   char 	  *W_format; // Format der Liste im Fenster.

   // Die drei nachfolgenden Funktionen nehmen eine besondere Bedeutung ein.
   // Sie funktionieren nur auf dem Amiga, da die Intuition-Oberfläche zum
   // Anzeigen und zur Auswahl eines Listenelements herangezogen wird.
   // Die Parameter: Alle Paremeter, bis auf 'up' und 'msg' sind optional.
   //
   // ds       readonly -> Kann nur angeschaut werden
   //	       readwrite -> Kann angesehen und ausgewählt werden
   //
   // format   gibt an, welche Paramter in welcher Reihenfolge in dem
   //	       Display erscheinen.
   //	       p - Priorität (mit C-Format "%6d")
   //	       a - Packed als Zahl (mit C-Format "%08lx")
   //	       i - Packed als Text (mit C-Format "%4s")
   //	       n - Name (mit C-Format "%s")
   //	       Es werden nur diese Buchstaben erwartet, alle anderen Angaben
   //	       werden überlesen.
   // width    Geben die Breite bzw. die Höhe des Feldes an, in dem die
   // height   Liste dargestellt wird. (Anzahl der !! Zeichen !!)
   //
   // xpos     Gibt die Stelle an, an der das Fenster erscheint.
   // ypos     (Werte in !! Pixel !!)
   //
   // wintitle Der Titel des Windows und der Screen.
   // scrtitle
   //
   // up       Den ShardPort, also den Port, über den das Fenster die
   //	       Messages bekommt. Ist dieser angegeben, wird KEIN eigener
   //	       MessagePost geöffnet
   //
   // msg      Eine IntuiMessage, die über den ShardPort gekommen ist.
   //
   // Die Funktionen im einzelnen:
   // - Die erste Funktion öffnet ein Fenster, zeigt die Daten der Liste
   //	darin an, und wartet je nach Wert von 'ds' entweder darauf, daß das
   //	Fenster geschlossen wird (falls ds==readonly) oder darauf, daß ein
   //	Listenelement ausgewählt wird oder das Fenster geschlossen wird (falls
   //	ds==readwrite). Falls das Fenster geschlossen wird, ohne daß ein
   //	Listenelement ausgewählt wurde, wird NULL zurückgegeben, ansonsten
   //	ein Zeiger auf dieses Element.
   // - Die zweite Funktion öffnet das Fenster und stellt die Daten dar,
   //	wartet aber NICHT auf eine Meldung von dem/der BenutzerIn sondern
   //	springt sofort zurück.
   // - Die Auswahl übernimmt dann die Funktion 'checkdis()', die eine Message
   //	vom ShardPort als Parameter besitzt.
   //	Wenn ein Listenelement ausgewählt wurde, wird ein Zeiger darauf
   //	zurückgegeben.
   //	Wenn die Meldung nicht für das Fenster bestimmt war, so bleibt die
   //	Meldung unangetastet und es wird zusätzlich NULL zurückgegeben.
   //	War die Meldung für dieses Fenster bestimmt, wird sie entsprechend
   //	behandelt, der WindowZeiger in der Meldung auf NULL gesetzt und NULL
   //	zurückgegeben.
   //	  Meldung	    |	  Aktion
   //	---------------------------------------------------------------------
   //	Fenster schliessen  |  Das Fenster wird 'versteckt' (hide)
   // - 'hide()' versteckt das Fenster explizit. Dabei bleiben interne
   //	Datenstrukturen erhalten und die Position des Fensters wird
   //	gespeichert. (Kann auch aufgerufen werden, wenn Fenster schon
   //	versteckt ist.)
   // - 'reveal()' öffnet ein verstecktes Window.
   // - 'closedis()' schließt ein geöffnetes oder verstecktes Window und gibt
   //	sämtliche Recourcen wieder frei.
 private:
   void doformat(char *buffer, char *format, node *n);
   int	domsg(struct IntuiMessage *msg);
   void freeexeclist(void);
   void makeexeclist(char *format);
   node *num2node(int num);
   char *pack2string(unsigned long pa);

 public:
   node *display(dsply ds=readonly, char *format="n",
		 int width=16, int height=16,
		 int xpos=50, int ypos=20,
		 char *wintitle="Display List", char *scrtitle="Display");
   int	display(struct MsgPort *up,
		struct Menu *menu=NULL,
		 dsply ds=readonly, char *format="n",
		 int width=16, int height=16,
		 int xpos=50, int ypos=20,
		 char *wintitle="Display List", char *scrtitle="Display");
   node *checkdis(struct IntuiMessage *msg);
   void hide(void);
   int	reveal(void);
   void closedis(void);
   // Und Funktionen, die es erlauben während das Window angezeigt wird die
   // Liste zu ändern.
   void start_change(void);
   void end_change(void);

   struct MsgPort *getmp(void);
   struct Menu *getmenu(void);
   struct Window *getwin(void);
#endif

};

#endif
