/*
 * list.h
 *
 * Copyright (C) 1995-2000 Kenichi Kourai
 *
 * 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, 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 qvwm; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifndef _LIST_H_
#define _LIST_H_

#include "debug.h"

template <class T>
class List {
public:
  class Iterator;

protected:
  class Item {
  friend class List;
  friend class Iterator;

  private:
    T* obj;
    Item* prev;
    Item* next;
    
  public:
    Item(T* item) : obj(item), prev(NULL), next(NULL) {}
  };

public:
  friend class Iterator {
  protected:
    List<T>* list;
    Item* current;

  public:
    Iterator() : list(NULL), current(NULL) {}
    Iterator(List<T>* lst) : list(lst), current(NULL) {}
    T* GetHead() {
      current = list->head;
      if (current)
	return current->obj;
      else
	return NULL;
    }
    T* GetTail() {
      current = list->tail;
      if (current)
	return current->obj;
      else
	return NULL;
    }
    T* GetPrev() {
      ASSERT(current);
      current = current->prev;
      if (current)
	return current->obj;
      else
	return NULL;
    }
    T* GetNext() {
      ASSERT(current);
      current = current->next;
      if (current)
	return current->obj;
      else
	return NULL;
    }
    T* GetCurrent() {
      if (current)
	return current->obj;
      else
	return NULL;
    }
    void InsertBefore(T* obj) {
      ASSERT(current);
      if (current->prev == NULL)
	list->InsertHead(obj);
      else {
	Item* li = new Item(obj);
	li->next = current;
	li->prev = current->prev;
	current->prev->next = li;
	current->prev = li;
	list->size++;
      }
    }
    void InsertAfter(T* obj) {
      ASSERT(current);
      if (current->next == NULL)
	list->InsertTail(obj);
      else {
	Item* li = new Item(obj);
	li->prev = current;
	li->next = current->next;
	current->next->prev = li;
	current->next = li;
	list->size++;
      }
    }
    // remove current item and advance iterator next
    T* Remove() {
      ASSERT(current);
      Item* li = current;
      current = current->next;
      list->Remove(li);

      if (current)
	return current->obj;
      else
	return NULL;
    }
  };

protected:
  Item* head;
  Item* tail;
  int size;

private:
  void Remove(Item* li) {
    if (li->prev)
      li->prev->next = li->next;
    else
      head = li->next;

    if (li->next)
      li->next->prev = li->prev;
    else
      tail = li->prev;

    delete li;
    size--;
  }

public:
  List() : head(NULL), tail(NULL), size(0) {}

  T* GetHead() const {
    if (head)
      return head->obj;
    else
      return NULL;
  }
  T* GetTail() const {
    if (tail)
      return tail->obj;
    else
      return NULL;
  }
  int GetSize() const { return size; }

  void InsertHead(T* obj) {
    Item* li = new Item(obj);
    if (head) {
      head->prev = li;
      li->next = head;
    }
    else
      tail = li;
    head = li;
    size++;
  }
  void InsertTail(T* obj) {
    Item* li = new Item(obj);
    if (tail) {
      tail->next = li;
      li->prev = tail;
    }
    else
      head = li;
    tail = li;
    size++;
  }
  Bool Remove(T* obj) {
    Item* li = head;

    while (li) {
      if (li->obj == obj) {
	Remove(li);
	return True;
      }
      li = li->next;
    }
    return False;
  }
  T* RemoveHead() {
    ASSERT(head);
    T* obj = head->obj;
    Remove(head);
    return obj;
  }
  T* RemoveTail() {
    ASSERT(tail);
    T* obj = tail->obj;
    Remove(tail);
    return obj;
  }
};

#endif // _LIST_H_
