// FILE: LineList.cc -- Implementation of a list of lines of text.
//   BY: John Zelle

// LineList is maintained as a doubly-linked list.

#include 
#include 
#include 
#include "LineList.h"

// List Node structure
struct LineList::ListNode
{ char*                data;
  LineList::ListNode*  next;
  LineList::ListNode*  prev;
};
typedef LineList::ListNode* NodePtr;

// A LineList object has a pointer to the head of the chain, and a pointer
// to the "current" line.
//     NodePtr _head
//     NodePtr _current


LineList::LineList()
{ _head = new ListNode;     // Header Node of doubly-linked list
  _current = new ListNode;  //  Footer Node of doubly-linked list

  _head->data = NULL;
  _head->prev = NULL;
  _head->next = _current;

  _current->data = NULL;
  _current->next = NULL;
  _current->prev = _head;
}

LineList::LineList(const LineList& value)
{ cerr << "Error: Attempt to pass a LineList by value";
  exit(1);
}

LineList::~LineList()
{ NodePtr ptr,tmp;
  
  ptr = _head;
  while(ptr != NULL)
    { if (ptr->data)
         delete [] ptr->data;
      tmp = ptr;
      ptr = ptr->next;
      delete tmp;  
    }
}

void LineList::insert(char* line)
{ 
  // First make a copy of the line on the heap.
  char* copy = new char[strlen(line)+1];
  strcpy(copy, line);
  
  // Create and fill in fields of Node
  NodePtr Node = new ListNode;
  Node->data = copy;
  Node->next = _current;
  Node->prev = _current->prev;
  
  // Splice Node into proper sequence on next and prev chains.
  _current->prev->next = Node;
  _current->prev = Node;
} 

void LineList::remove()
{ 
	if (_current->data != NULL)
	{
		NodePtr tmp = _current;			// Temporary pointer used to remove current data
		_current = _current->next;		// Adjust current pointer to successor
		
		tmp->next->prev = tmp->prev;	// Make next node point to prev node
		tmp->prev->next = tmp->next;	// Make prev node point to next node
		
		delete [] tmp->data;			// Remove allocated structure 'data' from the heap
		delete tmp;						// Remove the allocated structure from the heap
	}				
}
  
void LineList::display() const
{
  NodePtr tmp;

  tmp = _current;
  while (tmp->next != NULL)
    { cout << tmp->data << endl;
      tmp = tmp->next;
    }
  cout << "<>" << endl;
}

void LineList::display_current() const
{
	if (_current->next != NULL)
		cout << _current->data << endl;	// Display the data field of the 'current' object
	else
		cout << "<>" << endl;		// Do not display the NULL of the footer
}

void LineList::advance(int n)
{
  while(_current->next != NULL && n>0)
    { _current = _current->next;
      n--;
    }
}

void LineList::backup(int n)
{
	while (_current->prev->data != NULL && n<0)
	{
		_current = _current->prev;
		n++;
	}
}

ostream& operator<<(ostream& stream, const LineList& list)
{ NodePtr ptr = list._head;

  cout << "" << endl;
  while ( ptr != NULL )
    { cout << ptr->data << endl;
      ptr = ptr->next;
    }
  cout << "" << endl;
  return stream;
}