/* simplelist.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2001-2023 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "simplelist.hh"
#include "aguix/lowlevelfunc.h"

List::List()
{
  elements=0;
  first=NULL;
  last=NULL;
  acts=NULL;
  act=NULL;
  enums=0;
}

List::~List()
{
  ListElement *te,*te2;
  te=first;
  while(te!=NULL) {
    te2=te->next;
    delete te;
    te=te2;
  }
  if(acts!=NULL) _freesafe(acts);
}

int List::addElement(void *new_object)
{
  ListElement *elem=new ListElement();
  elem->element=new_object;
  if(last==NULL) {
    first=last=elem;
  } else {
    last->next=elem;
    elem->prev=last;
    last=elem;
  }
  elements++;
  return 0;
}

int List::addElementAt(int pos,void *new_object)
{
  if(pos<0) addElement(new_object);
  else if(pos>=elements) addElement(new_object);
  else {
    int x;
    ListElement *te;
    x=0;
    te=first;
    while((te!=NULL)&&(x!=pos)) {
      te=te->next;
      x++;
    }
    // new_object an die Stelle, wo te liegt
    ListElement *elem=new ListElement();
    elem->element=new_object;
    elem->next=te;
    elem->prev=te->prev;
    if(elem->prev!=NULL) elem->prev->next=elem;
    te->prev=elem;
    if(pos==0) first=elem;
    elements++;
  }
  return 0;
}

int List::removeElement(void *del_object)
{
  if(del_object==NULL) return -1;
  int x;
  ListElement *te;
  x=0;
  te=first;
  while((te!=NULL)&&(te->element!=del_object)) {
    te=te->next;
    x++;
  }
  return removeElementAt(x);
}

int List::removeElementAt(int pos)
{
  if(pos<0) return -1;
  else if(pos>=elements) return -1;
  if(pos==0) {
    return removeFirstElement();
  }
  if(pos==(elements-1)) {
    return removeLastElement();
  }
  int x;
  ListElement *te;
  x=0;
  te=first;
  while((te!=NULL)&&(x!=pos)) {
    te=te->next;
    x++;
  }
  te->prev->next=te->next;
  te->next->prev=te->prev;
  if(act==te) act=NULL;
  for(int i=0;i<enums;i++) if(acts[i]==te) acts[i]=NULL;
  delete te;
  elements--;
  return 0;
}

int List::removeAllElements()
{
  if(elements<1) return -1;
  ListElement *te,*te2;
  te=first;
  while(te!=NULL) {
    te2=te->next;
    delete te;
    te=te2;
  }
  elements=0;
  first=last=NULL;
  act=NULL;
  for(int i=0;i<enums;i++) acts[i]=NULL;
  return 0;
}

int List::removeLastElement()
{
  if(elements<1) return -1;
  if(act==last) act=NULL;
  for(int i=0;i<enums;i++) if(acts[i]==last) acts[i]=NULL;
  if(elements==1) {
    delete last;
    first=last=NULL;
  } else {
    ListElement *te=last;
    last=te->prev;
    last->next=NULL;
    delete te;
  }
  elements--;
  return 0;
}

int List::removeFirstElement()
{
  if(elements<1) return -1;
  if(act==first) act=NULL;
  for(int i=0;i<enums;i++) if(acts[i]==first) acts[i]=NULL;
  if(elements==1) {
    delete first;
    first=last=NULL;
  } else {
    ListElement *te=first;
    first=te->next;
    first->prev=NULL;
    delete te;
  }
  elements--;
  return 0;
}

int List::size() const
{
  return elements;
}

void *List::getFirstElement(int id)
{
  if((id<0)||(id>=enums)) return NULL;
  if(first==NULL) return NULL;
  acts[id]=first;
  return first->element;
}

void *List::getElementAt(int id,int pos)
{
  if((id<0)||(id>=enums)) return NULL;
  if(pos<0) return NULL;
  else if(pos>=elements) return NULL;
  int x;
  ListElement *te;
  x=0;
  te=first;
  while((te!=NULL)&&(x!=pos)) {
    te=te->next;
    x++;
  }
  acts[id]=te;
  return te->element;
}

void *List::getLastElement(int id)
{
  if((id<0)||(id>=enums)) return NULL;
  if(last==NULL) return NULL;
  acts[id]=last;
  return last->element;
}

void *List::getNextElement(int id)
{
  if((id<0)||(id>=enums)) return NULL;
  if(acts[id]==NULL) return NULL;
  acts[id]=acts[id]->next;
  if(acts[id]==NULL) return NULL;
  return acts[id]->element;
}

bool List::hasNextElement( int id )
{
    if ( id < 0 || id >= enums ) return false;
    if ( acts[id] == NULL ) return false;
    if ( acts[id]->next ) return true;
    return false;
}

void *List::getFirstElement()
{
  if(first==NULL) return NULL;
  act=first;
  return first->element;
}

void *List::getElementAt(int pos)
{
  if(pos<0) return NULL;
  else if(pos>=elements) return NULL;
  int x;
  ListElement *te;
  x=0;
  te=first;
  while((te!=NULL)&&(x!=pos)) {
    te=te->next;
    x++;
  }
  act=te;
  return te->element;
}

void *List::getLastElement()
{
  if(last==NULL) return NULL;
  act=last;
  return last->element;
}

void *List::getNextElement()
{
  if(act==NULL) return NULL;
  act=act->next;
  if(act==NULL) return NULL;
  return act->element;
}

ListElement::~ListElement()
{
}

ListElement::ListElement()
{
  element=NULL;
  next=NULL;
  prev=NULL;
}

int List::getIndex(void *obj) const
{
  if(obj==NULL) return -1;
  int x;
  ListElement *te;
  x=0;
  te=first;
  while(te!=NULL) {
    if(te->element==obj) break;
    te=te->next;
    x++;
  }
  if(x>=elements) x=-1;
  return x;
}

void *List::exchangeElement(int pos,void *newobj)
{
  if(pos<0) return NULL;
  if(pos>=elements) return NULL;
  int x;
  ListElement *te;
  x=0;
  te=first;
  while((te!=NULL)&&(x!=pos)) {
    te=te->next;
    x++;
  }
  void *retobj=te->element;
  te->element=newobj;
  return retobj;
}

int List::initEnum()
{
  ListElement **tacts=(ListElement**)_allocsafe(sizeof(ListElement*)*(enums+1));
  for(int i=0;i<enums;i++) tacts[i]=acts[i];
  tacts[enums]=NULL;
  if(acts!=NULL) _freesafe(acts);
  enums++;
  acts=tacts;
  return enums-1;
}

void List::closeEnum(int id)
{
  int i;
  ListElement **tacts;
  if((id<0)||(id>=enums)) return;
  if(enums==1) {
    tacts=NULL;
  } else {
    tacts=(ListElement**)_allocsafe(sizeof(ListElement*)*(enums-1));
    for(i=0;i<id;i++) tacts[i]=acts[i];
    for(i=id+1;i<enums;i++) tacts[i-1]=acts[i];
  }
  _freesafe(acts);
  enums--;
  acts=tacts;
}

void List::sort(int (*relfunc)(void*,void*))
{
  mergeSort(&first,relfunc);
  if(first!=NULL) {
    last=first;
    first->prev=NULL;
    while(last->next!=NULL) {
      last->next->prev=last;
      last=last->next;
    }
  } else last=NULL;
  act=NULL;
  for(int i=0;i<enums;i++) acts[i]=NULL;
}

void List::sort(int (*relfunc)(void*,void*,int),int mode)
{
  mergeSort(&first,relfunc,mode);
  if(first!=NULL) {
    last=first;
    first->prev=NULL;
    while(last->next!=NULL) {
      last->next->prev=last;
      last=last->next;
    }
  } else last=NULL;
  act=NULL;
  for(int i=0;i<enums;i++) acts[i]=NULL;
}

void List::mergeSort(ListElement **liste,int (*relfunc)(void*,void*))
{
  ListElement *sec_liste=NULL;
  if(liste!=NULL) {
    if((*liste)!=NULL) {
      if((*liste)->next!=NULL) {
        sec_liste=split(*liste);
        mergeSort(liste,relfunc);
        mergeSort(&sec_liste,relfunc);
        *liste=merge(*liste,sec_liste,relfunc);
      }
    }
  }
}

void List::mergeSort(ListElement **liste,int (*relfunc)(void*,void*,int),int mode)
{
  ListElement *sec_liste=NULL;
  if(liste!=NULL) {
    if(*liste!=NULL) {
      if((*liste)->next!=NULL) {
        sec_liste=split(*liste);
        mergeSort(liste,relfunc,mode);
        mergeSort(&sec_liste,relfunc,mode);
        *liste=merge(*liste,sec_liste,relfunc,mode);
      }
    }
  }
}

ListElement *List::merge(ListElement *liste1,
                         ListElement *liste2,
		         int (*relfunc)(void*,void*))
{
  ListElement *le1,*le2,*tle,*nl;

  if(liste1==NULL) return liste2;
  else if(liste2==NULL) return liste1;
  le1=liste1;
  le2=liste2;
  if(relfunc(liste2->element,liste1->element)<0) {
    nl=liste2;
    le2=le2->next;
  } else {
    nl=liste1;
    le1=le1->next;
  }
  tle=nl;
  while((le1!=NULL)||(le2!=NULL)) {
    if(le1==NULL) {
      tle->next=le2;
      tle=le2;
      le2=le2->next;
    } else if(le2==NULL) {
      tle->next=le1;
      tle=le1;
      le1=le1->next;
    } else {
      if(relfunc(le2->element,le1->element)<0) {
        tle->next=le2;
	tle=le2;
	le2=le2->next;
      } else {
        tle->next=le1;
	tle=le1;
	le1=le1->next;
      }
    }
  }
  tle->next=NULL;
  return nl;
}

ListElement *List::merge(ListElement *liste1,
                         ListElement *liste2,
	    	         int (*relfunc)(void*,void*,int),
  		         int mode)
{
  ListElement *le1,*le2,*tle,*nl;

  if(liste1==NULL) return liste2;
  else if(liste2==NULL) return liste1;
  le1=liste1;
  le2=liste2;
  if(relfunc(liste2->element,liste1->element,mode)<0) {
    nl=liste2;
    le2=le2->next;
  } else {
    nl=liste1;
    le1=le1->next;
  }
  tle=nl;
  while((le1!=NULL)||(le2!=NULL)) {
    if(le1==NULL) {
      tle->next=le2;
      tle=le2;
      le2=le2->next;
    } else if(le2==NULL) {
      tle->next=le1;
      tle=le1;
      le1=le1->next;
    } else {
      if(relfunc(le2->element,le1->element,mode)<0) {
        tle->next=le2;
	tle=le2;
	le2=le2->next;
      } else {
        tle->next=le1;
	tle=le1;
	le1=le1->next;
      }
    }
  }
  tle->next=NULL;
  return nl;
}

ListElement *List::split(ListElement *liste)
{
  ListElement *sec_element;
  ListElement *le1,*le2,*tle;
  int pos;
  if(liste==NULL) return NULL;
  if(liste->next==NULL) return NULL;
  le1=liste;
  le2=liste->next;
  sec_element=le2;
  tle=le2->next;
  pos=0;
  while(tle!=NULL) {
    if(pos==0) {
      le1->next=tle;
      le1=tle;
    } else {
      le2->next=tle;
      le2=tle;
    }
    tle=tle->next;
    pos=(pos==0)?1:0;
  }
  le1->next=NULL;
  le2->next=NULL;
  return sec_element;
}

/********************************
 List mit Array
 ********************************/

ArrayList::ArrayList()
{
  elements=0;
  arraysize=0;
  array=NULL;
  expandArray();
  actindex=-1;
  acts=NULL;
  enums=0;
}

ArrayList::~ArrayList()
{
  if(array!=NULL) {
    _freesafe(array);
  }
  if(acts!=NULL) _freesafe(acts);
}

void ArrayList::expandArray()
{
  int newsize;
  double td;
  void **newarray;
  int i;
  if(arraysize==0) {
    newsize=128;
  } else {
    if(arraysize<=10000) newsize=arraysize*2;
    else {
      td=((double)arraysize)*1.1;
      newsize=(int)td;
    }
  }
  newarray=(void**)_allocsafe(newsize*sizeof(void*));
  if(arraysize==0) {
    array=newarray;
    arraysize=newsize;
    for(i=0;i<newsize;i++) {
      array[i]=NULL;
    }
  } else {
    for(i=0;i<arraysize;i++) {
      newarray[i]=array[i];
    }
    for(i=arraysize;i<newsize;i++) {
      newarray[i]=NULL;
    }
    _freesafe(array);
    array=newarray;
    arraysize=newsize;
  }
}

int ArrayList::addElement(void *new_object)
{
  if(elements>=arraysize) expandArray();  // Platz schaffen
  array[elements]=new_object;
  elements++;
  return 0;
}

int ArrayList::addElementAt(int pos,void *new_object)
{
  if(pos<0) addElement(new_object);
  else if(pos>=elements) addElement(new_object);
  else {
    if(elements==arraysize) expandArray();
    for(int i=elements-1;i>=pos;i--) {
      if(i<0) printf("Fehler in addElementAt\n");
      array[i+1]=array[i];
    }
    array[pos]=new_object;
    elements++;
  }
  return 0;
}

int ArrayList::removeElement( const void *del_object )
{
  if(del_object==NULL) return -1;
  if(elements<1) return -1;
  int x=0;
  while(array[x]!=del_object) {
    x++;
    if(x==elements) break;
  }
  if(x<elements) {
    return removeElementAt(x);
  }
  return -1;
}

int ArrayList::removeElementAt(int pos)
{
  int i;
  if(pos<0) return -1;
  else if(pos>=elements) return -1;
  if(pos==(elements-1)) {
    return removeLastElement();
  }
  for(i=pos+1;i<elements;i++) {
    array[i-1]=array[i];
  }
  if(actindex==pos) actindex=-1;
  for(i=0;i<enums;i++) if(acts[i]==pos) acts[i]=-1;
  elements--;
  return 0;
}

int ArrayList::removeAllElements()
{
  if(elements<1) return -1;
  elements=0;
  actindex=-1;
  for(int i=0;i<enums;i++) acts[i]=-1;
  return 0;
}

int ArrayList::removeLastElement()
{
  if(elements<1) return -1;
  if(actindex==(elements-1)) actindex=-1;
  for(int i=0;i<enums;i++) if(acts[i]==(elements-1)) acts[i]=-1;
  elements--;
  return 0;
}

int ArrayList::removeFirstElement()
{
  int i;
  if(elements<1) return -1;
  if(actindex==0) actindex=-1;
  for(i=0;i<enums;i++) if(acts[i]==0) acts[i]=-1;
  for(i=1;i<elements;i++) {
    array[i-1]=array[i];
  }
  elements--;
  return 0;
}

int ArrayList::size() const
{
  return elements;
}

void *ArrayList::getFirstElement()
{
  if(elements==0) return NULL;
  actindex=0;
  return array[0];
}

void *ArrayList::getElementAt(int pos)
{
  if(pos<0) return NULL;
  else if(pos>=elements) return NULL;
  actindex=pos;
  return array[pos];
}

void *ArrayList::getLastElement()
{
  if(elements==0) return NULL;
  actindex=elements-1;
  return array[actindex];
}

void *ArrayList::getNextElement()
{
  if(elements==0) return NULL;
  if((actindex<0)||(actindex>=elements)) return NULL;
  actindex++;
  if(actindex>=elements) {
    actindex=-1;
    return NULL;
  }
  return array[actindex];
}

void *ArrayList::getPrevElement()
{
  if(elements==0) return NULL;
  if((actindex<0)||(actindex>=elements)) return NULL;
  actindex--;
  if(actindex<0) {
    actindex=-1;
    return NULL;
  }
  return array[actindex];
}

void *ArrayList::getFirstElement(int id)
{
  if((id<0)||(id>=enums)) return NULL;
  if(elements==0) return NULL;
  acts[id]=0;
  return array[0];
}

void *ArrayList::getElementAt(int id,int pos)
{
  if((id<0)||(id>=enums)) return NULL;
  if(pos<0) return NULL;
  else if(pos>=elements) return NULL;
  acts[id]=pos;
  return array[pos];
}

void *ArrayList::getLastElement(int id)
{
  if((id<0)||(id>=enums)) return NULL;
  if(elements==0) return NULL;
  acts[id]=elements-1;
  return array[elements-1];
}

void *ArrayList::getNextElement(int id)
{
  if((id<0)||(id>=enums)) return NULL;
  if(elements==0) return NULL;
  if((acts[id]<0)||(acts[id]>=elements)) return NULL;
  acts[id]++;
  if(acts[id]>=elements) {
    acts[id]=-1;
    return NULL;
  }
  return array[acts[id]];
}

void *ArrayList::getPrevElement(int id)
{
  if((id<0)||(id>=enums)) return NULL;
  if(elements==0) return NULL;
  if((acts[id]<0)||(acts[id]>=elements)) return NULL;
  acts[id]--;
  if(acts[id]<0) {
    acts[id]=-1;
    return NULL;
  }
  return array[acts[id]];
}

int ArrayList::getIndex(void *obj) const
{
  if(obj==NULL) return -1;
  if(elements<1) return -1;
  int x;
  x=0;
  while(array[x]!=obj) {
    x++;
    if(x==elements) break;
  }
  if(x>=elements) x=-1;
  return x;
}

void *ArrayList::exchangeElement(int pos,void *newobj)
{
  if(pos<0) return NULL;
  if(pos>=elements) return NULL;
  void *retobj=array[pos];
  array[pos]=newobj;
  return retobj;
}

int ArrayList::initEnum()
{
  int *tacts=(int*)_allocsafe(sizeof(int)*(enums+1));
  for(int i=0;i<enums;i++) tacts[i]=acts[i];
  tacts[enums]=-1;
  if(acts!=NULL) _freesafe(acts);
  enums++;
  acts=tacts;
  return enums-1;
}

void ArrayList::closeEnum(int id)
{
  int i;
  int*tacts;
  if((id<0)||(id>=enums)) return;
  if(enums==1) {
    tacts=NULL;
  } else {
    tacts=(int*)_allocsafe(sizeof(int)*(enums-1));
    for(i=0;i<id;i++) tacts[i]=acts[i];
    for(i=id+1;i<enums;i++) tacts[i-1]=acts[i];
  }
  _freesafe(acts);
  enums--;
  acts=tacts;
}

void ArrayList::sort(int (*relfunc)(void*,void*))
{
  if(elements<2) return;  // bei weniger als 2 Elementen ist die Liste ohnehin sortiert
  quicksort(0,elements-1,relfunc);
  actindex=-1;
  for(int i=0;i<enums;i++) acts[i]=-1;
}

void ArrayList::sort(int (*relfunc)(void*,void*,int),int mode)
{
  if(elements<2) return;  // bei weniger als 2 Elementen ist die Liste ohnehin sortiert
  quicksort(0,elements-1,relfunc,mode);
  actindex=-1;
  for(int i=0;i<enums;i++) acts[i]=-1;
}

void ArrayList::quicksort(int p,int r,int (*relfunc)(void*,void*))
{
  int q;
  if(p<r) {
    q=qs_partition(p,r,relfunc);
    quicksort(p,q,relfunc);
    quicksort(q+1,r,relfunc);
  }
}

void ArrayList::quicksort(int p,int r,int (*relfunc)(void*,void*,int),int mode)
{
  int q;
  if(p<r) {
    q=qs_partition(p,r,relfunc,mode);
    quicksort(p,q,relfunc,mode);
    quicksort(q+1,r,relfunc,mode);
  }
}

int ArrayList::qs_partition(int p,int r,int (*relfunc)(void*,void*))
{
  int i,j,tr;
  double t1;
  void *te,*cel;
  i=p-1;
  j=r+1;
//  tr=p;
  t1=(double)rand();
  t1*=r-p;
  t1/=RAND_MAX+1.0;
  tr=p+(int)(t1);
  cel=array[tr];
  for(;;) {
    do {
      j--;
    } while(relfunc(array[j],cel)>0);
    do {
      i++;
    } while(relfunc(array[i],cel)<0);
    if(i<j) {
      te=array[j];
      array[j]=array[i];
      array[i]=te;
    } else return j;
  }
}

int ArrayList::qs_partition(int p,int r,int (*relfunc)(void*,void*,int),int mode)
{
  int i,j,tr;
  double t1;
  void *te,*cel;
  i=p-1;
  j=r+1;
//  tr=p;
  t1=(double)rand();
  t1*=r-p;
  t1/=RAND_MAX+1.0;
  tr=p+(int)(t1);
  cel=array[tr];
  for(;;) {
    do {
      j--;
    } while(relfunc(array[j],cel,mode)>0);
    do {
      i++;
    } while(relfunc(array[i],cel,mode)<0);
    if(i<j) {
      te=array[j];
      array[j]=array[i];
      array[i]=te;
    } else return j;
  }
}
