// C++ code Copyright (C) David R. Evans G4AMJ/NQ0I

#include <stdio.h>
#include <stdlib.h>
#include <iostream.h>
#include <math.h>

#include <defines.h>
#include <list.h>

glist::glist() { first = last = recent = 0; index = list_length = 0; }

// destructor. This is not the same as clearing the list.
glist::~glist()
{ while (first)
  { link *temp_ptr = first;
	 first = first -> next;
	 delete temp_ptr;
  }
}

// list += pointer_to_data
void glist::operator+=(void *ptr)
{ link *temp_ptr;
  heap_check(temp_ptr = new link);
  temp_ptr -> data = ptr;
  temp_ptr -> next = 0;
  if (!first) then                    // list is empty
  { first = temp_ptr;
    first -> previous = 0;
    last = first;
  }
  else
  { temp_ptr -> previous = last;
    last -> next = temp_ptr;
    last = temp_ptr;
  };
  list_length++;
  recent = last;
  index = list_length;
}

// list[index]  index is wrt 1
void* glist::operator[](const int in_index)
{ link *temp_ptr, *starting_point;
  if ((in_index > list_length) || (in_index < 1)) then return 0;  // range error

  int distance_1 = in_index - 1, distance_2 = list_length - in_index,
      distance_3 = index - in_index, distance, direction;

  if (distance_1 < distance_2) then
  { distance = distance_1; starting_point = first; direction = 1; }
  else
  { distance = distance_2; starting_point = last; direction = 0; }
  if (abs(distance_3) < distance) then
  { distance = abs(distance_3); starting_point = recent;
    direction = (distance_3 < 0);
  }
  temp_ptr = starting_point;
  for (int n = 1; n <= distance; n++)
    temp_ptr = ((direction) ? (temp_ptr -> next) : (temp_ptr -> previous));
  index = in_index;
  recent = temp_ptr;
  return temp_ptr -> data;
}

// list -= pointer_to_data. This deletes ONLY the entry from the list, not
//    the data themselves.
void glist::operator-=(void *ptr)
{ link *temp_ptr = recent;
  if (temp_ptr -> data != ptr) then
  { temp_ptr = first;
	 while ((temp_ptr) && (temp_ptr -> data != ptr)) temp_ptr = temp_ptr -> next;
	 if (!(temp_ptr)) then return;    // couldn't find it
  };

  if (!(temp_ptr -> previous)) then    // first in list
  { if (!(temp_ptr -> next)) then      // only one item in list
	 { delete temp_ptr;
		first = last = recent = NULL; index = list_length = 0;
		return;
	 };
	 temp_ptr -> next -> previous = 0;    // more than one item
	 first = temp_ptr -> next;
	 delete temp_ptr;
	 recent = first; index = 1; list_length--;
	 return;
  };

  if (!(temp_ptr -> next)) then    // last in list
  { temp_ptr -> previous -> next = 0;
	 last = temp_ptr -> previous;
	 delete temp_ptr;
	 recent = last; index = --list_length;
	 return;
  };

  temp_ptr -> previous -> next = temp_ptr -> next;    // middle of list
  temp_ptr -> next -> previous = temp_ptr -> previous;
  delete temp_ptr;
  recent = first; index = 1; list_length--;
  return;
}

// list = list
void glist::operator=(glist& rhs)
{ clear();
  for (int n = 1; n <= rhs.length(); n++)
		*this += rhs[n];
}

// clear the list
void glist::clear(void)
{ while (first)
	 *this -= (*this)[1];
  recent = NULL; index = list_length = 0;
}

// clear the list and destroy the objects in the list
void glist::clear_and_destroy(void)
{ while (first)
  { void* vp = (*this)[1];
	 *this -= (*this)[1];
	 delete vp;
  }
  recent = NULL; index = list_length = 0;
}

