#include "pch.h"
#include "mzArrayList.h"
#include "mzMath.h"
#include <stdio.h>

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

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

mzstd::CmzArrayList::~CmzArrayList() {
    if (this->_items) {
        delete[] this->_items;
        this->_items = NULL;
    }
}

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

VOID mzstd::CmzArrayList::append(LONG 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] = data;
    this->_size++;
}

VOID mzstd::CmzArrayList::addAsFirst(LONG 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] = data;
        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] = data;
        this->_size++;
    }
}

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

    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] = data;
    this->_size++;
}

ULONG mzstd::CmzArrayList::del(LONG data) {
    ULONG removed = 0;

    for (ULONG i = 0; i < this->_size; i++) {
        if (this->_items[i] == data) {
            for (ULONG j = i + 1; j < this->_size; j++) {
                this->_items[j - 1] = this->_items[j];
            }
            this->_size--;
            removed++;
        }
    }

    return removed;
}

BOOL mzstd::CmzArrayList::delFirst(LONG data) {
    BOOL removed = FALSE;

    for (ULONG i = 0; i < this->_size; i++) {
        if (this->_items[i] == data) {
            for (ULONG j = i + 1; j < this->_size; j++) {
                this->_items[j - 1] = this->_items[j];
            }
            this->_size--;
            removed = TRUE;
            break;
        }
    }

    return removed;
}

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

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

    return TRUE;
}

LONG mzstd::CmzArrayList::pos(LONG data) {
    for (ULONG i = 0; i < this->_size; i++) {
        if (this->_items[i] == data) {
            return i;
        }
    }

    return -1;
}

BOOL mzstd::CmzArrayList::contains(LONG data) {
    return this->pos(data) >= 0;
}

VOID mzstd::CmzArrayList::clear() {
    this->_size = 0;
}

LONG mzstd::CmzArrayList::getMinValue() {
    LONG min = (LONG)0xffffffff; // MIN_LONG
    LONG size = this->_size;

    for (LONG i = 0; i < size; i++) {
        if (min > this->_items[i]) {
            min = this->_items[i];
        }
    }

    return min;
}

LONG mzstd::CmzArrayList::getMaxValue() {
    LONG max = (LONG)0x7fffffff; // MAX_LONG
    LONG size = this->_size;

    for (LONG i = 0; i < size; i++) {
        if (max < this->_items[i]) {
            max = this->_items[i];
        }
    }

    return max;
}

LONG mzstd::CmzArrayList::getFirstAvailableValue() {
    if (this->_size < 1) {
        return 1;
    }
    if (this->_size == 1) {
        return this->_items[0] + 1;
    }

    mzstd::CmzArrayList* lst = this->clone();
    lst->sort();

    for (ULONG i = 1; i < lst->_size; i++) {
        if (lst->_items[i] - lst->_items[i-1] > 1) {
            return lst->_items[i-1] + 1;
        }
    }

    LONG retval = lst->_items[lst->_size-1] + 1;
    delete lst;
    return retval;
}

VOID mzstd::CmzArrayList::sort(BOOL asc) {
    LONG size = this->_size;
    LONG tmp;

    if (asc) {
        for (LONG i = 0; i < size - 1; i++) {
            for (LONG j = i + 1; j < size; j++) {
                if (this->_items[i] > this->_items[j]) {
                    tmp = this->_items[j];
                    this->_items[j] = this->_items[i];
                    this->_items[i] = tmp;
                }
            }
        }
    } else {
        for (LONG i = 0; i < size - 1; i++) {
            for (LONG j = i + 1; j < size; j++) {
                if (this->_items[i] < this->_items[j]) {
                    tmp = this->_items[j];
                    this->_items[j] = this->_items[i];
                    this->_items[i] = tmp;
                }
            }
        }
    }
}

VOID mzstd::CmzArrayList::insertRandomValues(ULONG count, ULONG minValue, ULONG maxValue) {
    if (this->_size + count > this->_capacity) {
        ULONG newCapacity = this->_size + count;
        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 (ULONG i = 0; i < count; i++) {
        this->_items[i + this->_size] = random(minValue, maxValue);
    }
}

VOID mzstd::CmzArrayList::randomizeAllCapacity() {
    this->_size = this->_capacity;
    this->randomizeAll();
}

VOID mzstd::CmzArrayList::randomizeAllCapacity(ULONG minValue, ULONG maxValue) {
    this->_size = this->_capacity;
    this->randomizeAll(minValue, maxValue);
}

VOID mzstd::CmzArrayList::randomizeAll() {
    for (ULONG i = 0; i < this->_size; i++) {
        this->_items[i] = random();
    }
}

VOID mzstd::CmzArrayList::randomizeAll(ULONG minValue, ULONG maxValue) {
    for (ULONG i = 0; i < this->_size; i++) {
        this->_items[i] = random(minValue, maxValue);
    }
}

mzstd::CmzArrayList* mzstd::CmzArrayList::clone() {
    mzstd::CmzArrayList* newList = new mzstd::CmzArrayList(this->_capacity);
    memcpy(newList->_items, this->_items, sizeof(LONG) * this->_capacity);
    newList->_size = this->_size;
    return newList;
}

mzstd::CmzString mzstd::CmzArrayList::toString() {
    CmzString s(COMMON_EMPTY_STRING);

    for (ULONG i = 0; i < this->_size; i++) {
        if (i > 0) {
            s += L", ";
        }
        s += this->_items[i];
    }

    return s;
}


VOID mzstd::CmzArrayList::setAt(ULONG pos, LONG data) {
    if (pos >= this->_size) {
        this->append(data);
    } else {
        this->_items[pos] = data;
    }
}
