/*
 * ************************************************************************************************************
 * Author: Marcin Załęczny
 * Copyright (C)2010 Marcin Załęczny <mzaleczny@hotmail.com>
 * License: The GNU Lesser General Public License, version 3.0 (LGPLv3)
 * Library Name: mzstd
 * Version: 1.07
 * First release date:   2010-11-08
 * Current release date: 2011-03-04
 *
 *
 * This file is part of mzstd library
 * 
 * mzstd library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * mzstd library 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * ************************************************************************************************************
 */

#include "mzTypedArrayList.h"
#include "mzstdGlobals.h"

CTypedArrayList::CTypedArrayList(ULONG capacity) {
    this->setRealClassName(L"CTypedArrayList");
    this->_capacity = capacity;
    this->_size = 0;

    if (capacity > 0) {
        this->_items = this->_createNullArray(capacity);
    } else {
        this->_items = NULL;
    }
}

CTypedArrayList::~CTypedArrayList() {
    this->clear();
    
    if (this->_items) {
        delete[] this->_items;
    }
}

LONG* CTypedArrayList::_createNullArray(ULONG capacity) {
    ULONG bufsize = capacity * sizeof(LONG);
    LONG* result = new LONG[bufsize];
    memset(result, 0, bufsize); 
    return result;
}

VOID CTypedArrayList::append(LONG data, CString type) {
    CTypedArrayListItem* item = new CTypedArrayListItem(type, data);
    
    if (this->_size == this->_capacity) {
        ULONG newCapacity = this->_capacity + 100;
        LONG *newItems = this->_createNullArray(newCapacity);
        if (this->_items) {
            memcpy(newItems, this->_items, sizeof(LONG) * this->_size);
            delete[] this->_items;
        }
        this->_items = newItems;
        this->_capacity = newCapacity;
    }
    this->_items[this->_size] = (LONG)item;
    this->_size++;
}

VOID CTypedArrayList::addAsFirst(LONG data, CString type) {
    CTypedArrayListItem* item = new CTypedArrayListItem(type, data);

    if (this->_size == this->_capacity) {
        ULONG newCapacity = this->_capacity + 100;
        LONG *newItems = this->_createNullArray(newCapacity);
        if (this->_items) {
            memcpy((newItems + sizeof(LONG)), this->_items, sizeof(LONG) * this->_size);
            delete[] this->_items;
        }
        newItems[0] = (LONG)item;
        this->_items = newItems;
        this->_capacity = newCapacity;
        this->_size++;
    } else {
        for (LONG i = this->_size; i > 0; i--) {
            this->_items[i] = this->_items[i-1];
        }
        this->_items[0] = (LONG)item;
        this->_size++;
    }
}

VOID CTypedArrayList::insert(ULONG pos, LONG data, CString type) {
    if (pos < 0 || pos > this->_size) {
        return;
    }

    CTypedArrayListItem* item = new CTypedArrayListItem(type, data);

    if (this->_size == this->_capacity) {
        ULONG newCapacity = this->_capacity + 100;
        LONG *newItems = this->_createNullArray(newCapacity);
        if (this->_items) {
            memcpy(newItems, this->_items, sizeof(LONG) * this->_size);
            delete[] this->_items;
        }
        this->_items = newItems;
        this->_capacity = newCapacity;
    }

    for (LONG i = (LONG)this->_size; i > (LONG)pos; i--) {
        this->_items[i] = this->_items[i-1];
    }
    this->_items[pos] = (LONG)item;
    this->_size++;
}

ULONG CTypedArrayList::del(LONG data, CString type) {
    ULONG removed = 0;
    CTypedArrayListItem* item;

    for (ULONG i = 0; i < this->_size; i++) {
        item = (CTypedArrayListItem*)this->_items[i];
        if (item->pointer == data && item->type == type) {
            for (ULONG j = i + 1; j < this->_size; j++) {
                this->_items[j - 1] = this->_items[j];
            }
            delete item;
            this->_size--;
            removed++;
        }
    }

    return removed;
}

BOOL CTypedArrayList::delFirst(LONG data, CString type) {
    BOOL removed = FALSE;
    CTypedArrayListItem* item;

    for (ULONG i = 0; i < this->_size; i++) {
        item = (CTypedArrayListItem*)this->_items[i];
        if (item->pointer == data && item->type == type) {
            for (ULONG j = i + 1; j < this->_size; j++) {
                this->_items[j - 1] = this->_items[j];
            }
            delete item;
            this->_size--;
            removed = TRUE;
            break;
        }
    }

    return removed;
}

BOOL CTypedArrayList::delAt(ULONG pos) {
    if (pos >= this->_size) {
        return FALSE;
    }

    CTypedArrayListItem* item = (CTypedArrayListItem*)this->_items[pos];
    delete item;
    for (ULONG i = pos + 1; i < this->_size; i++) {
        this->_items[i - 1] = this->_items[i];
    }
    this->_size--;

    return TRUE;
}

LONG CTypedArrayList::pos(LONG data, CString type) {
    CTypedArrayListItem* item;

    for (ULONG i = 0; i < this->_size; i++) {
        item = (CTypedArrayListItem*)this->_items[i];
        if (item->pointer == data && item->type == type) {
            return i;
        }
    }

    return -1;
}

BOOL CTypedArrayList::contains(LONG data, CString type) {
    return this->pos(data, type) >= 0;
}

VOID CTypedArrayList::clear() {
    CTypedArrayListItem* item;
    LONG len = this->_size;
    for (LONG i = 0; i < len; i++) {
        item = (CTypedArrayListItem*)this->_items[i];
        if (item) {
            delete item;
        }
    }
    
    this->_size = 0;
}

CTypedArrayListItem* CTypedArrayList::getAt(ULONG pos) {
    if (pos < this->_size) return (CTypedArrayListItem*)this->_items[pos];
    return NULL;
}

VOID CTypedArrayList::getAt(ULONG pos, LONG& data, CString& type) {
    CTypedArrayListItem* item;
    if (pos < this->_size) {
        item = (CTypedArrayListItem*)this->_items[pos];
        data = item->pointer;
        type = item->type;
    } else {
        data = 0;
        type = COMMON_EMPTY_STRING;
    }
}

LONG CTypedArrayList::getDataAt(ULONG pos) {
    CTypedArrayListItem* item;
    if (pos < this->_size) {
        item = (CTypedArrayListItem*)this->_items[pos];
        return item->pointer;
    }
    
    return 0;
}

CString CTypedArrayList::getTypeAt(ULONG pos) {
    CTypedArrayListItem* item;
    if (pos < this->_size) {
        item = (CTypedArrayListItem*)this->_items[pos];
        return item->type;
    }
    
    return COMMON_EMPTY_STRING;
}

CTypedArrayListItem* CTypedArrayList::getFirst() {
    if (this->_size > 0) return (CTypedArrayListItem*)this->_items[0]; return NULL;
}

VOID CTypedArrayList::getFirst(LONG& data, CString& type) {
    CTypedArrayListItem* item;
    if (this->_size > 0) {
        item = (CTypedArrayListItem*)this->_items[0];
        data = item->pointer;
        type = item->type;
    } else {
        data = 0;
        type = COMMON_EMPTY_STRING;
    }
}

LONG CTypedArrayList::getDataAtFirst() {
    CTypedArrayListItem* item;
    if (this->_size > 0) {
        item = (CTypedArrayListItem*)this->_items[0];
        return item->pointer;
    }
    
    return 0;
}

CString CTypedArrayList::getTypeAtFirst() {
    CTypedArrayListItem* item;
    if (this->_size > 0) {
        item = (CTypedArrayListItem*)this->_items[0];
        return item->type;
    }
    
    return COMMON_EMPTY_STRING;
}

CTypedArrayListItem* CTypedArrayList::getLast() {
    if (this->_size > 0) return (CTypedArrayListItem*)this->_items[this->_size-1]; return NULL;
}

VOID CTypedArrayList::getLast(LONG& data, CString& type) {
    CTypedArrayListItem* item;
    if (this->_size > 0) {
        item = (CTypedArrayListItem*)this->_items[this->_size-1];
        data = item->pointer;
        type = item->type;
    } else {
        data = 0;
        type = COMMON_EMPTY_STRING;
    }
}

LONG CTypedArrayList::getDataAtLast() {
    CTypedArrayListItem* item;
    if (this->_size > 0) {
        item = (CTypedArrayListItem*)this->_items[this->_size-1];
        return item->pointer;
    }
    
    return 0;
}

CString CTypedArrayList::getTypeAtLast() {
    CTypedArrayListItem* item;
    if (this->_size > 0) {
        item = (CTypedArrayListItem*)this->_items[this->_size-1];
        return item->type;
    }
    
    return COMMON_EMPTY_STRING;
}

CTypedArrayListItem* CTypedArrayList::pop() {
    CTypedArrayListItem* item;
    
    if (this->_size < 1) {
        return NULL;
    }
    
    item = (CTypedArrayListItem*)this->_items[this->_size - 1];
    this->_items[this->_size - 1] = NULL;
    this->_size--;
    
    return item;
}

VOID CTypedArrayList::pop(LONG& data) {
    CTypedArrayListItem* item;
    
    if (this->_size < 1) {
        data = 0;
        return;
    }
    
    item = (CTypedArrayListItem*)this->_items[this->_size - 1];
    this->_items[this->_size - 1] = NULL;
    this->_size--;
    
    data = item->pointer;
    delete item;
}

VOID CTypedArrayList::pop(CString& type) {
    CTypedArrayListItem* item;
    
    if (this->_size < 1) {
        type = COMMON_EMPTY_STRING;
        return;
    }
    
    item = (CTypedArrayListItem*)this->_items[this->_size - 1];
    this->_items[this->_size - 1] = NULL;
    this->_size--;
    
    type = item->type;
    delete item;
}

VOID CTypedArrayList::pop(LONG& data, CString& type) {
    CTypedArrayListItem* item;
    
    if (this->_size < 1) {
        data = 0;
        type = COMMON_EMPTY_STRING;
        return;
    }
    
    item = (CTypedArrayListItem*)this->_items[this->_size - 1];
    this->_items[this->_size - 1] = NULL;
    this->_size--;
    
    data = item->pointer;
    type = item->type;
    delete item;
}
