/*
** allgemeine Hilfsfunktionen
**
** Copyright (C) 1996 by Stefan Scherer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for non-commerical use and without fee is hereby granted,
** provided that the above copyright notice appear in all copies and that
** both that copyright notice and this permission notice appear in
** supporting documentation.  This software is provided "as is" without
** express or implied warranty.
*/

/*
** $VER: InsertSorted 1.1 (23.3.94)
**
** Sortiertes Einfügen in eine Exec-Liste
**
** Mit dieser Routine kann man mit Exec-Listen sehr einfach eine
** sortierte Liste verwalten.
**
** Bedingung ist: Man darf nur mit InsertSorted() Einträge in die Liste
**                aufnehmen. Entfernen kann man jeden beliebigen Eintrag.
*/

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <exec/types.h>
#include <exec/lists.h>
#include <exec/nodes.h>
#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#include <intuition/screens.h>


/* private Prototypen */

static BOOL singleCheckName (STRPTR teil, STRPTR name);
static BOOL singleCheckDescription (STRPTR teil, STRPTR array[]);


/*
** Um sortieren zu können, muß eine Funktion zur Verfügung gestellt
** werden, um einen Vergleich der Nutzdaten durchzuführen. Diese
** Funktion heißt CompareNodes() und muß folgendermaßen implementiert
** werden:
**
** int CompareNodes( void *such, void *nutz );
**
** Rückgabewerte:
**
**        <0 falls such < nutz
**        =0 falls such = nutz
**        >0 falls such > nutz
*/



/*
** InsertSorted(), fügt einen Node in eine Liste ein und berücksichtigt
** dabei gleich die Sortierung.
*/

void 
InsertSorted (struct List *list, struct Node *node, struct Node *listnode,
	      int (*cmpfunc) (const void *, const void *))
{
  int comp;
  BOOL forward;

  if (IsListEmpty (list))
    {
      AddHead (list, node);
    }
  else
    {
      if (!listnode)
	{
	  listnode = list->lh_Head;
	  forward = TRUE;
	}
      else
	{
	  comp = cmpfunc (node, listnode);
	  if (comp >= 0)
	    forward = TRUE;
	  else
	    forward = FALSE;
	}

      if (forward)
	{
	  /* ja, dann suchen, bis ein größerer Eintrag erscheint */
	  do
	    {
	      comp = cmpfunc (node, listnode);
	      /* wenn noch größer oder gleich, dann zum nächsten */
	      if (comp >= 0)
		listnode = listnode->ln_Succ;

	    }
	  while (listnode->ln_Succ && (comp >= 0));

	  if (comp >= 0)
	    AddTail (list, node);
	  else
	    Insert (list, node, listnode->ln_Pred);
	}
      else
	{
	  /* ja, dann suchen, bis ein kleinergleicher Eintrag erscheint */
	  do
	    {
	      comp = cmpfunc (node, listnode);
	      /* wenn noch größer oder gleich, dann zum vorherigen */
	      if (comp < 0)
		listnode = listnode->ln_Pred;

	    }
	  while (listnode->ln_Pred && (comp < 0));

	  if (comp < 0)
	    AddHead (list, node);
	  else
	    Insert (list, node, listnode);
	}
    }
}


/*
** Durch einen Fehler (?) in MUI V2.2 kann ich den Namen des Public Screens
** nicht in Erfahrung bringen. Jedoch durch die Adresse des Screens kann
** mit dieser Funktion auf den Namen des Public Screens geschlossen werden.
**
** input:    struct Screen * screen
**
** output:   STRPTR name     Name des PublicScreens oder NULL wenn nicht public
*/

STRPTR 
GetPublicScreenName (struct Screen *screen)
{
  struct PubScreenNode *node;
  struct List *publist;
  BOOL searching = TRUE;
  STRPTR result = NULL;
  static char buffer[MAXPUBSCREENNAME + 1];

  /* search the frontmost public screen */
  publist = LockPubScreenList ();

  for (node = (struct PubScreenNode *) publist->lh_Head;
       node->psn_Node.ln_Succ && searching;
       node = (struct PubScreenNode *) node->psn_Node.ln_Succ)
    {
      if (screen == node->psn_Screen)
	{
	  searching = FALSE;
	  strcpy (buffer, node->psn_Node.ln_Name);
	  result = buffer;
	}
    }

  UnlockPubScreenList ();

  return (result);
}




/* Sucht nach dem Teilstring in einem Namen
**
** teil - Suchstring, kann auch ein Teil eines Filenamens sein.
**        wird als "#?teil#?" betrachtet. Zusätzlich kann mit '|' eine
**        erweiterte Angabe gemacht werden. Dann wird nach #?teil1#? und
**        #?teil2#?  gesucht. Natürlich können mehrere '|' eingegeben werden.
** name - der volle Filename
**
** BOOL - Rückgabewert TRUE, wenn gefunden oder FALSE, wenn nicht gefunden
*/

BOOL 
CheckName (STRPTR teil, STRPTR name)
{
  BOOL found = FALSE;
  STRPTR strings[20];
  STRPTR pos;
  int num, i;
  char buffer[256];

  strcpy (buffer, teil);
  strings[0] = buffer;

  /* suchstring 'teil' in einzelne Teilstrings zerlegen */

  for (pos = buffer, num = 0; *pos && num < 20; num++)
    {
      for (strings[num] = pos; *pos && *pos != '|';)
	{
	  pos++;
	}
      if (*pos)
	*pos++ = 0;
    }

  /* nun alle Teilstrings zum Suchen verwenden */

  found = singleCheckName (strings[0], name);
  for (i = 1; found && i < num; i++)
    {
      found &= singleCheckName (strings[i], name);
    }

  return (found);
}

/* Sucht nach dem Teilstring in einem Namen
**
** teil - Suchstring, kann auch ein Teil eines Filenamens sein.
**        wird als "#?teil#?" betrachtet.
** name - der volle Filename
**
** BOOL - Rückgabewert entweder TRUE oder FALSE, ob gefunden oder nicht
*/

static BOOL 
singleCheckName (STRPTR teil, STRPTR name)
{
  BOOL found = FALSE;
  STRPTR start = name;
  WORD i, max;
  WORD tlen, nlen;

  if ((tlen = strlen (teil)) >= (nlen = strlen (name)))
    max = 1;
  else
    max = 1 + nlen - tlen;

  for (i = 0; i < max && !found; i++, start++)
    {
      found = (BOOL) (!strnicmp (teil, start, tlen));
    }

  if (found)
    found = TRUE;
  return (found);
}



/* Sucht nach dem Teilstring in einer Beschreibung
**
** teil  - Suchstring, kann auch ein Teil eines Filenamens sein.
**         wird als "#?teil#?" betrachtet. Zusätzlich können mit '|' getrennt
**         mehrere Suchschlüssel angegeben werden.
** array - Zeigerarray, das mit NULL endet.
**
** BOOL  - Rückgabewert entweder TRUE oder FALSE
*/

BOOL 
CheckNameArray (STRPTR teil, STRPTR array[])
{
  BOOL found = FALSE;
  STRPTR strings[20];
  STRPTR pos;
  int num, i;
  char buffer[256];

  strcpy (buffer, teil);
  strings[0] = buffer;

  /* suchstring 'teil' in einzelne Teilstrings zerlegen */

  for (pos = buffer, num = 0; *pos && num < 20; num++)
    {
      for (strings[num] = pos; *pos && *pos != '|';)
	{
	  pos++;
	}
      if (*pos)
	*pos++ = 0;
    }

  /* nun alle Teilstrings zum Suchen verwenden */

  found = singleCheckDescription (strings[0], array);
  for (i = 1; found && i < num; i++)
    {
      found &= singleCheckDescription (strings[i], array);
    }

  return (found);
}

/* Sucht nach dem Teilstring in einer Beschreibung
**
** teil  - Suchstring, kann auch ein Teil eines Filenamens sein.
**         wird als "#?teil#?" betrachtet.
** array - Zeigerarray, das mit NULL endet.
**
** BOOL  - Rückgabewert entweder TRUE oder FALSE
*/

static BOOL 
singleCheckDescription (STRPTR teil, STRPTR array[])
{
  BOOL found = FALSE;
  STRPTR start;
  WORD i, len, tlen;
  STRPTR arrptr;
  UWORD j;

  tlen = strlen (teil);

  for (j = 0, arrptr = array[j]; arrptr && !found; ++j, arrptr = array[j])
    {
      len = strlen (arrptr);
      for (start = arrptr, i = 0; i < len - tlen + 1 && !found; i++, start++)
	{
	  found = (BOOL) (!strnicmp (teil, start, tlen));
	}
    }

  if (found)
    found = TRUE;
  return (found);
}
