// Filename:   dllist.C
// Contents:   the doubly linked list object methods
// Author: Greg Shaw
// Created:    8/2/93

/*
This file 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, or (at your option) any
later version.

In addition to the permissions in the GNU General Public License, the
Free Software Foundation gives you unlimited permission to link the
compiled version of this file with other programs, and to distribute
those programs without any restriction coming from the use of this
file.  (The General Public License restrictions do apply in other
respects; for example, they cover modification of the file, and
distribution when not linked into another program.)

This file 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; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

#ifndef _DLLIST_C_
#define _DLLIST_C_

#include "bbshdr.h"

// Method: constructor
// Purpose:    initialize the object to a known state
// Input:  none
// Output: none
// Author: Greg Shaw
// Created:    8/2/93

dllist::dllist()
{
	head=tail=NULL;
	numrec = 0;
	sortstate = 0;
	here = NULL;
};


// Method: destructor
// Purpose:    clean up after the object
// Input:  none
// Output: none
// Author: Greg Shaw
// Created:    8/2/93

dllist::~dllist()
{
	clear_list();
};


// Method: add
// Purpose:    add a record to the object
// Input:  rec - the record to add to the object
// Output: none
// Author: Greg Shaw
// Created:    8/2/93

int dllist::add(FInfo *rec)
{
	FInfo  *newrec;

	if (newrec = (FInfo *)malloc(sizeof(FInfo)), newrec == NULL)
	{
		ap_log("dllist: Unable to malloc new FInfo record.");
		return(-1);
	}
	strcpy(newrec->name,rec->name);
	strcpy(newrec->sdesc,rec->sdesc);
	strcpy(newrec->uploader,rec->uploader);
	newrec->avail = rec->avail;
	newrec->date = rec->date;
	newrec->filepos = rec->filepos;
	newrec->numdls = rec->numdls;
	newrec->size = rec->size;
	newrec->previous = NULL;
	newrec->next = NULL;
	if (head == NULL)
	{
		head = newrec;
		tail=newrec;
	}
	else
	{
		newrec->previous = tail;
		tail->next = newrec;
		tail = newrec;
	}
	numrec++;
	return(0);
};


// Function:   clear
// Purpose:    add a record to the object
// Input:  rec - the record to add to the object
// Output: none
// Author: Greg Shaw
// Created:    8/2/93

int dllist::clear_list(void)
{
	FInfo  *tmprec, *tmprec2;

	tmprec = head;
	while (tmprec != NULL)
	{
		tmprec2 = tmprec;
		tmprec = tmprec->next;
		free(tmprec2);
	}
	numrec = 0;
	head = tail = NULL;
	return(0);
};


// Function:   find
// Purpose:    find a file name in list
// Input:  str - file name to look for
// Output: none
// Author: Greg Shaw
// Created:    8/2/93

FInfo *dllist::find(char *str)
{
	FInfo *rec;
	int    found;

	found = 0;
	rec = head;
	while (!found && rec != NULL)
	{
		if (strcmp(rec->name,str) == 0)
			found++;
		else
			rec = rec->next;
	}
	return(rec);
};


// Function:   sort
// Purpose:    sort the list by a key
// Input:  type - the type of sorting to do:
//         1 - sort by date
//         2 - sort by name
// Output: none
// Author: Greg Shaw
// Created:    8/2/93

int dllist::sort(int type)
{
	if (numrec > 0)
	{
		switch(type)
		{
			case 0:
				return(-1);
			case 1:             // numeric by date
				sel_sort(0,head);
				break;
			case 2:             // alpha by name
				sel_sort(1,head);

		}
	}
	return(0);
};


// Function:   sort
// Purpose:    sort the list by a key
// Input:  head - the start of the list
// Output: none
// Author: Greg Shaw
// Created:    8/2/93
// Notes:  this uses a selection sort method

int dllist::sel_sort(int type, FInfo *list)
{
	FInfo  *loop1, *loop2, *smallest, *tmp, *listnext;

	loop1 = head;               // start of list
	while (loop1->next != NULL) // until end - 1
	{
		smallest = loop1;
		loop2 = loop1->next;
		while (loop2 != NULL)
		{
			if (type)
			{
				if (strcmp(loop2->name,smallest->name) < 0)
					smallest = loop2;
			}
			else
			{
				if (loop2->date < smallest->date)
					smallest = loop2;
			}
			loop2 = loop2->next;
		}
		listnext = loop1->next;
		if (smallest != loop1)
		{
			// now swap
			// left side (previous)
			if (loop1->previous != NULL)
			{
				tmp = loop1->previous;
				loop1->previous->next = smallest;
			}
			else
				head = smallest;
			if (smallest->previous != NULL)
			{
				tmp = smallest->previous;
				tmp->next = loop1;
			}
			tmp = loop1->previous;
			loop1->previous = smallest->previous;
			smallest->previous = tmp;
			if (loop1->next != NULL)
			{
				tmp = loop1->next;
				tmp->previous = smallest;
			}
			if (smallest->next != NULL)
			{
				tmp = smallest->next;
				tmp->previous = loop1;
			}
			else
				tail = loop1;
			tmp = loop1->next;
			loop1->next = smallest->next;
			smallest->next = tmp;
		}
		loop1 = listnext;
	}
	if (type)
		sortstate = 2;          // alphabetically sorted
	else
		sortstate = 1;          // numerically sorted
	tmp = head;
	while (tmp != NULL)
	{
		tmp = tmp->next;
	}
	return(0);
};


// Function:   next
// Purpose:    return the 'next' record in the array
// Input:  none
// Output: none
// Author: Greg Shaw
// Created:    8/2/93

FInfo *dllist::next(void)
{
	if (here == NULL)
	{
		here = head;
		return(head);
	}
	here = here->next;
	return(here);
};


// Function:   previous
// Purpose:    return the previous record in the list
// Input:  none
// Output: none
// Author: Greg Shaw
// Created:    8/2/93

FInfo *dllist::previous(void)
{
	if (here == NULL)
	{
		here = tail;
		return(tail);
	}
	here = here->previous;
	return(here);
};


// Function:   head
// Purpose:    set 'here' to top of the list
// Input:  none
// Output: none
// Author: Greg Shaw
// Created:    8/2/93

int dllist::top(void)
{
	here = NULL;
	return(0);
};


// Function:   tail
// Purpose:    set 'here' to end of the list
// Input:  none
// Output: none
// Author: Greg Shaw
// Created:    8/2/93

int dllist::bottom(void)
{
	here = NULL;
	return(0);
};


#endif                          //_DLLIST_C_






