/*
===========================================================================
Copyright (C) 2024 the OpenMoHAA team

This file is part of OpenMoHAA source code.

OpenMoHAA source code 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 of the License,
or (at your option) any later version.

OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/

#pragma once

template<typename type>
class UListItem
{
public:
    type                   item;
    class UListItem<type> *next;
    class UListItem<type> *prev;

    UListItem();
};

template<typename type>
class UList
{
    UListItem<type>  m_top;
    UListItem<type> *m_at;
    int              m_count;

public:
    UList();
    ~UList();

    void  AddHead(type& head);
    void  AddTail(const type& tail);
    bool  IterateFromHead(void);
    bool  IterateFromTail(void);
    bool  IterateNext(void);
    bool  IteratePrev(void);
    type& getCurrent(void);
    void  RemoveCurrentSetNext(void);
    void  RemoveCurrentSetPrev(void);
    bool  IsCurrentValid(void);
    bool  IsCurrentHead(void);
    bool  IsCurrentTail(void);
    void  InsertBeforeCurrent(type& which);
    void  InsertAfterCurrent(type& which);
    int   getCount(void);
    void  RemoveAllItems(void);
    void *getPosition(void);
    void  setPosition(void *pos);
};

template<typename type>
UListItem<type>::UListItem()
{
    next = prev = NULL;
}

template<typename type>
UList<type>::UList()
{
    m_at       = NULL;
    m_count    = 0;
    m_top.next = &m_top;
    m_top.prev = &m_top;
}

template<typename type>
UList<type>::~UList()
{
    RemoveAllItems();
}

template<typename type>
void UList<type>::AddHead(type& head)
{
    // FIXME: stub
}

template<typename type>
void UList<type>::AddTail(const type& tail)
{
    UListItem<type> *item = new UListItem<type>;

    item->item       = tail;
    item->next       = &m_top;
    item->prev       = m_top.prev;
    m_top.prev->next = item;
    m_top.prev       = item;

    m_count++;
}

template<typename type>
bool UList<type>::IterateFromHead(void)
{
    if (m_top.next == &m_top) {
        m_at = NULL;
        return false;
    } else {
        m_at = m_top.next;
        return true;
    }
}

template<typename type>
bool UList<type>::IterateFromTail(void)
{
    if (m_top.prev == &m_top) {
        m_at = NULL;
        return false;
    } else {
        m_at = m_top.prev;
        return true;
    }
}

template<typename type>
bool UList<type>::IterateNext(void)
{
    m_at = m_at->next;

    if (m_at == &m_top) {
        m_at = NULL;
        return false;
    } else {
        return true;
    }
}

template<typename type>
bool UList<type>::IteratePrev(void)
{
    m_at = m_at->prev;

    if (m_at == &m_top) {
        m_at = NULL;
        return false;
    } else {
        return true;
    }
}

template<typename type>
type& UList<type>::getCurrent(void)
{
    return m_at->item;
}

template<typename type>
void UList<type>::RemoveCurrentSetNext(void)
{
    UListItem<type> *item;

    item = m_at;
    IterateNext();

    item->next->prev = item->prev;
    item->prev->next = item->next;

    delete item;

    m_count--;
}

template<typename type>
void UList<type>::RemoveCurrentSetPrev(void)
{
    UListItem<type> *item;

    item = m_at;
    IteratePrev();

    item->next->prev = item->prev;
    item->prev->next = item->next;

    delete item;

    m_count--;
}

template<typename type>
bool UList<type>::IsCurrentValid(void)
{
    return m_at != NULL;
}

template<typename type>
bool UList<type>::IsCurrentHead(void)
{
    return m_at == &m_top;
}

template<typename type>
bool UList<type>::IsCurrentTail(void)
{
    // FIXME: stub
    return false;
}

template<typename type>
void UList<type>::InsertBeforeCurrent(type& which)
{
    // FIXME: stub
}

template<typename type>
void UList<type>::InsertAfterCurrent(type& which)
{
    UListItem<type> *item = new UListItem<type>;

    item->item       = which;
    item->next       = m_at->next;
    item->prev       = m_at;
    m_at->next->prev = item;
    item->prev->next = item;

    m_count++;
}

template<typename type>
int UList<type>::getCount(void)
{
    return m_count;
}

template<typename type>
void UList<type>::RemoveAllItems(void)
{
    UListItem<type> *item;
    UListItem<type> *next;

    for (item = m_top.next; item && item != &m_top; item = next) {
        next = item->next;
        delete item;
    }

    m_top.next = &m_top;
    m_top.prev = &m_top;
    m_count    = 0;
}

template<typename type>
void *UList<type>::getPosition(void)
{
    return (void *)m_at;
}

template<typename type>
void UList<type>::setPosition(void *pos)
{
    m_at = static_cast<UListItem<type> *>(pos);
}
