// ////////////////////////////////////////////////////////
// Copyright (1994) Columbia University
// Department of Biochemistry and Molecular Biophysics
//
// Author: Weider Chang, Ph.D
// ///////////////////////////////////////////////////////

#include "idxcoltn.h"
#include "wstring.h"
#include "iterator.h"

@implementation WDCIndexedCollection

- free
{
  struct objc_list *temp, *current=_list;
  while (current){
    temp=current;
    current=current->tail;
    free(temp);
  }
  [super free];
}
    

- insertElement:(elt)element atIndex:(unsigned)index;
{
  list_insert_element(&_list, (void*)element.id_u, index);
  return self;  
}

- (elt)removeElementAtIndex:(unsigned)index;
{
  elt element=(elt)(id)list_remove_nth_node(&_list, index);
  return element;
}

- (elt)elementAtIndex:(unsigned)index;
{
  return (elt)(const void*)list_nth(index, _list);
}

//
// need this to break the circlar call in the original implementation.
//

- withElementsCall:(void(*)(elt))aFunc;
{
  struct objc_list* list=_list;
  while (list)
    {
      aFunc((id)list->head);
      list=list->tail;
    }
  return self;
}

// 
// Inprovement of R. A. McCallum's original implementation. Now, this
// method will stop when it reach the first element of a list.
//

- (BOOL) getPrevElement:(elt *)anElementPtr withEnumState: (void**)enumState
{
  /* *(unsigned*)enumState-1 is the index of the element 
     that will be returned */

  if (!(*enumState))
    {
      if (!anElementPtr->id_u)
	*(unsigned*)enumState = [self count]-1;
      else
	return NO;
    }
  else
    (*(unsigned*)enumState)--;
  *anElementPtr = [self elementAtIndex:(*(unsigned*)enumState)];
  return YES;
}

//
// Better implemenetation than R. A. McCallum's original implementation.
// It ease the future maintenance. 
//

- (BOOL) getPrevObject:(id *)anObjectPtr withEnumState: (void**)enumState
{
  elt element;
  if ([self getPrevElement:&element withEnumState:enumState])
    {
      *anObjectPtr=element.id_u;
      return YES;
    }
  return NO;

  //
  // original implementation.
  //

  // *(unsigned*)enumState-1 is the index of the element 
  // that will be returned 

  //if (!(*enumState))
  //  *(unsigned*)enumState = [self count]-1;
  //else
  //  (*(unsigned*)enumState)--;
  //*anObjectPtr = [self elementAtIndex:(*(unsigned*)enumState)].id_u;
  //return YES;
}

/*
  - swapAtIndeces: (unsigned)index1 : (unsigned)index2
{
  id iter;
  elt tmp = [self elementAtIndex:index1];
  void doIt(elt element){
    printf("%s ", [element.id_u cStringValue]);
  }
  [self replaceElementAtIndex:index1 with:[self elementAtIndex:index2]];
  [self withElementsCall:doIt];
  printf("\n");
  [self replaceElementAtIndex:index2 with:tmp];
  [self withElementsCall:doIt];
  printf("\n");
  return self;
}
*/

- swapAtIndeces: (unsigned)index1 : (unsigned)index2;
{
  [self replaceElementAtIndex:index1 
        with:[self replaceElementAtIndex:index2 
	           with:[self elementAtIndex:index1]]];
  return self;
}

  
- (elt) replaceElementAtIndex:(unsigned)index with:(elt)element;
{
  return (id)list_replace_element(&_list, (void*)element.id_u, index);
}

- (BOOL)isExist:object
{
  id tempObject;
  id temp=[[WDCListIterator alloc] initFrom: self];
  BOOL result=NO;
  SEL aSel=0;
  if (![self isEmpty]){
    if ([object respondsTo:@selector(compare:)])
      aSel=@selector(compare:);
    else if ([object respondsTo:@selector(compareObject:)])
      aSel=@selector(compareObject:);
    if (aSel)
      {
	while ([temp goNext])
	  {
	    if ((tempObject=[temp getCurrentObject])
		&& ![tempObject perform:aSel with:object])
	      {
		result=YES;
		break;
	      }
	  }
      }
  }
  else result=NO;
  [temp free]; // **
  return result;
}

@end
