
// SPDX-License-Identifier: CC-BY-NC-SA-4.0
//
// Copyright (C) 2026 Bit by Bit Signal Processing LLC (https://bxbsp.com)
//
// This work is placed under the "Creative Commons Attribution
// NonCommercial ShareAlike 4.0 International" license, known
// by the shortened acronym "CC-BY-NC-SA-4.0".
//
// This work is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// A CC-BY-NC-SA-4.0 license allows you to use this work for
// noncommercial purposes so long as attribution is made to the
// original author.  Modified versions of this work may be distributed,
// but only under the same license.  For further details, see the
// Creative Commons License "CC-BY-NC-SA-4.0".
//
// You should have received a copy of the CC-BY-NC-SA-4.0 license
// along with this work. If not, see
// <https://creativecommons.org/licenses/by-nc-sa/4.0/>.
//
//

#ifndef LIST_HH
#define LIST_HH

#include "BasicList.hh"
#include <stdio.h>
#include <stdlib.h>

template<class T> class ListElement : BasicListElement
{
  T* data_value;
  int delete_flag;
  
public:

  ListElement* next()     { return (ListElement*) BasicListElement::next(); }
  ListElement* previous() { return (ListElement*) BasicListElement::previous(); }

  T*   data()        { return data_value; }
  void setdata(T* t) { data_value = t; }

  ListElement(T* data, int deleteflag) { data_value = data; delete_flag = deleteflag; }
  virtual ~ListElement() { if(delete_flag && data_value) delete data_value; }
};

template<class T> class List : BasicList
{
public:
  List()  {}
  ~List() {}

  void addAtEnd(T* t, int deleteflag) 
    { 
      addAtEnd(new ListElement<T>(t, deleteflag)); 
    }

  void addAtEnd(ListElement<T>* e) 
    { 
      BasicList::addAtEnd((BasicListElement*) e); 
    }

  void remove(ListElement<T>* e)   
    { 
      BasicList::remove((BasicListElement*) e); 
    }

  //
  // extract is like remove, only data is returned overriding possible 
  // deletion.
  //
  T* extract(ListElement<T>* e)   
    { 
      T* d = e->data();  
      e->setdata(0); 
      BasicList::remove((BasicListElement*) e); 
      return d;
    }

  ListElement<T>*  first()  { return (ListElement<T>*) BasicList::first(); }
  ListElement<T>*  last()   { return (ListElement<T>*) BasicList::last();  }

  void replace_extract(T* orig, T* replacement);
  
  void sort(int firstElementFirstFunction(T* first, T* second));
  int  numInList();
  bool isInList(T* t);
  void extract(T* t);
  void remove(T* t);
  void remove_all();
  T*   getItemInList(int n);
};



template<class T>
void List<T>::extract(T* t)
{
  ListElement<T>* le = first();
  while(le)
    {
      if(le->data()==t)
	{
	  (void)extract(le);
	  break;
	}
      le=le->next();
    }
}


template<class T>
int List<T>::numInList()
{
  int count=0;
  ListElement<T>* le = first();
  while(le)
    {
      count++;
      le=le->next();
    }

  return count;
}



template<class T>
T* List<T>::getItemInList(int n)
{
  int count=0;
  for(ListElement<T>* le=first(); le; le=le->next())
    {
      if(count==n)
	return le->data();
      
      count++;
    }

  return 0;
}


template<class T>
bool List<T>::isInList(T* t)
{
  ListElement<T>* le = first();
  while(le)
    {
      if(le->data()==t)
	return true;
      le=le->next();
    }

  return false;
}


template<class T>
void List<T>::remove(T* t)
{
  ListElement<T>* le = first();
  while(le)
    {
      if(le->data()==t)
	{
	  remove(le);
	  return;
	}
      le=le->next();
    }

  printf("Error in List<T>::remove:  element to remove isn't on list.\n");
  abort();
}


template<class T>
void List<T>::remove_all()
{
  ListElement<T>* le = first();
  while(le)
    {
      remove(le);
      le=first();
    }
}


//
// The extacted data is orig.  If the user wants to delete it, they have it, so they can.
//
template<class T>
void List<T>::replace_extract(T* orig, T* replacement)
{
  ListElement<T>* le = first();
  while(le)
    {
      if(le->data()==orig)
	{
	  le->setdata(replacement);
	  return;
	}
      le=le->next();
    }

  printf("Error in List<T>::replace_extract:  element to remove isn't on list.\n");
  abort();
}


//
// A classic bubble sort.  Not very efficient, but who cares.
//
template<class T>
void List<T>::sort(int firstElementFirstFunction(T* first, T* second))
{
  int exchange;
  ListElement<T>* le;
  ListElement<T>* le2;
  T* t;

  le = first();
  if(!le)
    return;

  exchange = 1;
  while(exchange)
    {
      exchange = 0;

      le = first();
      for(;;)
	{
	  le2 = le->next();
	  if(!le2)
	    break;

	  if(!firstElementFirstFunction(le->data(), le2->data()))
	    {
	      exchange = 1;
	      t = le->data();
	      le->setdata(le2->data());
	      le2->setdata(t);
	    }
	  le = le2;
	}
    }
}

#endif
