// This file is a part of the xMule Project
// Copyright (C)2004 Theodore R. Smith (donate@xmule.org / http://xmule.hopto.org/)
// RSA-1024 Fingerprint: 4145 9DFD 5338 4FCC 1636  86E5 2E5A 42D8 BA13 460B
//
// 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 of the License, 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 this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

#ifndef MFC_H
#define MFC_H

// wrappers for required MFC classes
// makes life a bit less annoying

#include <map>                              // std::map
#include <vector>                           // std::vector
#include <wx/list.h>
#include <wx/hashmap.h>
#include <wx/dynarray.h>
#include <wx/listimpl.cpp>

WX_DECLARE_LIST(void, VoidList);

// da map
//WX_DECLARE_HASH_MAP(unsigned int, void *, wxIntegerHash, wxIntegerEqual, VoidHash);
typedef std::map< unsigned int, void * > VoidHash;
//typedef VoidList::Node* POSITION;

typedef struct
{
    VoidHash:: iterator it;
    VoidList:: Node *node;
}

_POSITION;

typedef _POSITION *POSITION;

// basic list
// ok, own implementation. you can't do the reasonaby otherwise
template < class TYPE, class ARG_TYPE >
class CList: public wxObject
{
    typedef struct MyNode
    {
        struct MyNode *next, *prev;
        TYPE data;
    }
    MYNODE;
    protected:
    //VoidList internalList;
    MYNODE *internalList;
    MYNODE *tail;
    int count;
    void freeNode(MYNODE *n)
    {
        delete n;
    }
    MYNODE *newNode(ARG_TYPE data)
    {
        MYNODE *n = new MYNODE;
        n->prev = n->next = NULL;
        n->data = data;
        return n;
    }
    public:
    CList(int none = 0)
    {
        internalList = NULL;
        tail = NULL;
        count = 0;
    }
    // hmm.. you really want to DELETE the list too!
    ~CList()
    {
        RemoveAll();
    }
    ;
    int GetCount() const
    {
        return count;
        //g_list_length(internalList);
    }
    ;
    int GetSize() const
    {
        return count;
        //g_list_length(internalList);
    }
    ;
    bool IsEmpty() const
    {
        return count == 0;
        //g_list_length(internalList)==0;
    }
    ;
    TYPE &GetHead()
    {
        if (internalList)
        {
            return internalList->data;
        }
        else
        {
            printf("1DO NOT CALL WITH EMPTY LIST\n");
            exit(1);
        }
    }
    TYPE GetHead() const
    {
        if (internalList)
        {
            return internalList->data;
        }
        else
        {
            return(TYPE) 0;
        }
    }
    TYPE &GetTail()
    {
        if (tail)
        {
            return tail->data;
        }
        else
        {
            printf("DONT CALL WITH EMPTY LIST\n");
            exit(1);
        }
    }
    TYPE GetTail() const
    {
        if (tail)
        {
            return tail->data;
        }
        else
        {
            return(TYPE) 0;
        }
    }
    TYPE RemoveHead()
    {
        if (internalList)
        {
            MYNODE *old = internalList;
            TYPE oldvalue = old->data;
            // advance head
            internalList = internalList->next;
            // if not null, then there are still items in the list
            if (internalList)
            internalList->prev = NULL;
            // and this is the head
            else
            tail = NULL;
            // otherwise.. no more list and tail
            freeNode(old);
            count--;
            return oldvalue;
        }
        // otherwise we are iterating on a empty list..
        return(TYPE) 0;
    }
    TYPE RemoveTail()
    {
        if (tail)
        {
            MYNODE *old = tail;
            TYPE olddata = tail->data;
            // move tail to previous node
            tail = tail->prev;
            // is there list anymore?
            if (tail)
            tail->next = NULL;
            // yes. this is the tail
            else
            internalList = NULL;
            // no. list has vanished
            freeNode(tail);
            count--;
            return olddata;
        }
        // iterating on an empty list
        return(TYPE) 0;
    }
    POSITION AddHead(ARG_TYPE uusi)
    {
        MYNODE *newnode = newNode(uusi);
        // we are adding to head!
        newnode->next = internalList;
        if (internalList)
        internalList->prev = newnode;
        else
        tail = newnode;
        internalList = newnode;
        count++;
        // return position to head
        return(POSITION) internalList;
    }
    POSITION AddTail(ARG_TYPE uusi)
    {
        MYNODE *newnode = newNode(uusi);
        // and to the tail
        newnode->prev = tail;
        if (tail)
        tail->next = newnode;
        else
        internalList = newnode;
        tail = newnode;
        count++;
        return(POSITION) tail;
    }
    POSITION Append(ARG_TYPE uusi)
    {
        // addtail
        return AddTail(uusi);
    }
    void RemoveAll()
    {
        MYNODE *first = internalList;
        while (first)
        {
            MYNODE *n = first->next;
            freeNode(first);
            first = n;
        }
        internalList = tail = NULL;
        count = 0;
    }
    POSITION GetHeadPosition() const
    {
        return(POSITION) internalList;
    }
    POSITION GetTailPosition() const
    {
        return(POSITION) tail;
    }
    TYPE &GetNext(POSITION &pos)
    {
        MYNODE *n = (MYNODE *) pos;
        if (n)
        {
            TYPE &data = n->data;
            n = n->next;
            pos = (POSITION) n;
            return data;
        }
        else
        {
            printf("2DO NOT CALL WITH EMPTY LIST!\n");
            exit(1);
        }
    }
    TYPE GetNext(POSITION &pos) const
    {
        MYNODE *n = (MYNODE *) pos;
        if (n)
        {
            TYPE data = n->data;
            n = n->next;
            pos = (POSITION) n;
            return data;
        }
        else
        {
            return(TYPE) 0;
        }
    }
    TYPE &GetPrev(POSITION &pos)
    {
        MYNODE *n = (MYNODE *) pos;
        if (n)
        {
            TYPE &data = n->data;
            n = n->prev;
            pos = (POSITION) n;
            return data;
        }
        else
        {
            printf("3DO NOT CALL WITH EMPTY LIST\n");
            exit(1);
        }
    }
    TYPE GetPrev(POSITION &pos) const
    {
        MYNODE *n = (MYNODE *) pos;
        if (n)
        {
            TYPE data = n->data;
            n = n->prev;
            pos = (POSITION) n;
            return data;
        }
        else
        {
            return(TYPE) 0;
        }
    }
    TYPE &GetAt(POSITION pos)
    {
        MYNODE *n = (MYNODE *) pos;
        if (n)
        {
            return n->data;
        }
        else
        {
            printf("4DO NOT CALL WITH EMPTY LIST\n");
            exit(1);
        }
    }
    TYPE GetAt(POSITION pos) const
    {
        MYNODE *n = (MYNODE *) pos;
        if (n)
        {
            return n->data;
        }
        return(TYPE) 0;
    }
    void RemoveAt(POSITION pos)
    {
        MYNODE *n = (MYNODE *) pos;
        if (n)
        {
            // are we removing the head?
            if (internalList == n)
            {
                // yes
                internalList = n->next;
            }
            else
            {
                // no
                n->prev->next = n->next;
            }
            // is it tail too?
            if (tail == n)
            {
                // yes
                tail = n->prev;
            }
            else
            {
                // no
                n->next->prev = n->prev;
            }
            freeNode(n);
            count--;
        }
    }
    void InsertAfter(POSITION pos, ARG_TYPE data)
    {
        MYNODE *n = (MYNODE *) pos;
        if (n)
        {
            MYNODE *newnode = newNode(data);
            newnode->prev = n;
            newnode->next = n->next;
            if (n->next)
            {
                n->next->prev = newnode;
            }
            else
            {
                // it's tail
                tail = newnode;
            }
            n->next = newnode;
            // increase count here. not after addtail()
            count++;
        }
        else
        {
            // just append
            pos = AddTail(data);
        }
    }
    POSITION Find(ARG_TYPE searchValue, POSITION startAfter = NULL) const
    {
        MYNODE *n = internalList;
        if (startAfter) n = ((MYNODE *) startAfter)->next;
        while (n)
        {
            if (n->data == searchValue)
            {
                return(POSITION) n;
            }
            n = n->next;
        }
        return(POSITION) 0;
    }
    POSITION FindIndex(int nIndex) const
    {
        MYNODE *n = internalList;
        for (int i = 0 ; i < nIndex ; i++)
        {
            if (n)
            {
                n = n->next;
            }
            else
            {
                // past the end
                return(POSITION) 0;
            }
        }
        return(POSITION) n;
    }
};

class CPtrList;

// typedptrlist is just an instance of ordinary list...
template < class BASE_CLASS, class TYPE >
class CTypedPtrList: public CList < TYPE, TYPE >
{
    public:
    CTypedPtrList(int nBlockSize = 0)
    {
    }
};

#include <stdarg.h>
// same for string list
/*class wxString: public wxString
{
    public:
    wxString(): wxString()
    {
    }
    wxString(wxChar *ptr)
    : wxString(ptr)
    {
    }
    wxString(const wxChar *ptr)
    : wxString(ptr)
    {
    }
    const char *GetBuffer()
    {
        return(const char *) GetData();
    }
    int GetLength() const
    {
        return Length();
    }
    void Format(const wxChar *pszFormat, ...)
    {
        va_list argptr;
        va_start(argptr, pszFormat);
        PrintfV(pszFormat, argptr);
        va_end(argptr);
    }
    int Find(wxString what) const
    {
        return wxString:: Find(what);
    }
    wxString Mid(int from, int len)
    {
        return wxString(wxString:: Mid(from, len) .GetData());
    }
    wxString &operator = (wxString &src)
    {
        if (this != &src)
        {
            Clear();
            Append(src.GetData());
        }
        return *this;
    }
    wxString &operator = (wxString src)
    {
        if (this != &src)
        {
            Clear();
            Append(src.GetData());
        }
        return *this;
    }
    wxString &operator = (const char a[])
    {
        Clear();
        Append((wxChar *) a);
        return *this;
    }
};

WX_DECLARE_LIST(wxString, stringList);

class CStringList: public stringList
{
    public:
    CStringList(int nblocks = 0)
    {
    }
    POSITION GetHeadPosition()
    {
        return(POSITION) GetFirst();
    }
    wxString GetNext(POSITION &pos)
    {
        stringList:: Node *nod = (stringList:: Node *) pos;
        wxString retval = * (nod->GetData());
        nod = nod->GetNext();
        pos = (POSITION) nod;
        return retval;
    }
    wxString GetAt(POSITION pos)
    {
        stringList:: Node *nod = (stringList:: Node *) pos;
        return * (nod->GetData());
    }
};
*/
// default hasher
template < class ARG_KEY >
unsigned int HashKey(ARG_KEY key)
{
    return((unsigned int) key);
}

template < class TYPE, class ARG_TYPE >
class CArray: private std::vector< ARG_TYPE >
{
public:
    typedef typename std::vector<TYPE>::iterator  iterator;
    typedef std::vector<TYPE> inherited;

protected:
    iterator Index2It(int index)
    {
        iterator it = inherited::begin();
        it += index;

        return it;
    }

public:
    CArray()
    {
    }

    ~CArray()
    {
        inherited::clear();
    }

    int GetSize() const
    {
        return inherited::size();
    }

    int GetCount() const
    {
        return inherited::size();
    }

    int GetUpperBound() const
    {
        return inherited::size() - 1;
    }

    void SetSize(int newsiz, int growby = -1)
    {
        inherited::reserve(newsiz);
    }

    bool IsEmpty() const
    {
        return inherited::empty();
    }

    void RemoveAll()
    {
        inherited::clear();
    }

    void RemoveAt(int nIndex)
    {
        inherited::erase(Index2It(nIndex));
    }

    TYPE GetAt(int nIndex) const
    {
        return inherited::at(nIndex);
    }

    void SetAt(int nIndex, ARG_TYPE newElem)
    {
        this[nIndex] = newElem;
    }

    TYPE &ElementAt(int nIndex)
    {
        return (TYPE &)inherited::at(nIndex);
    }

    int Add(ARG_TYPE newElem)
    {
        inherited::push_back(newElem);
        return 0;
    }

    void InsertAt(int nIndex, ARG_TYPE newElem)
    {
        inherited::insert(Index2It(nIndex), newElem);
    }

/*
    TYPE operator[] (int nIndex) const
    {
        return(TYPE) intArr[nIndex];
    }

    TYPE &operator[] (int nIndex)
    {
        return(TYPE &) intArr[nIndex];
    }
*/
    using inherited::operator[];
};

#endif
