/*
 * ************************************************************************************************************
 * 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 "mzStringList.h"
#include "mzFileUtils.h"
#include "mzLogger.h"

CStringList::CStringList(ULONG capacity) {
    this->setRealClassName(L"CStringList");
	this->_growBy = 100;
	this->_emptyStr = "";
    this->_capacity = capacity;
    this->_size = 0;

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

CStringList::~CStringList() {
	CString *s;
    if (this->_items) {
		for (ULONG i = 0; i < this->_size; i++) {
			s = (CString*)this->_items[i];
			delete s;
		}
        delete[] this->_items;
    }
}

LONG* CStringList::createNullArray(ULONG capacity) {
    LONG* result = new LONG[capacity];
    return result;
}

VOID CStringList::append(CString data) {
    if (this->_size == this->_capacity) {
		ULONG newCapacity = this->_capacity + this->_growBy;
		this->_growBy *= 2;
        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)(new CString(data));
    this->_size++;
}

VOID WINAPI CStringList::append(CStringList *lst) {
    if (lst && lst->size() > 0) {
        for (ULONG i = 0; i < lst->size(); i++) {
            this->append(lst->getAt(i));
        }
    }
}

VOID CStringList::setAt(ULONG pos, CString data) {
    if (pos >= this->_size) {
        this->append(data);
    } else {
        CString* s = (CString*)this->_items[pos];
        if (s) {
            delete s;
        }
        this->_items[pos] = (LONG)(new CString(data));
    }
}

VOID CStringList::addAsFirst(CString data) {
    if (this->_size == this->_capacity) {
		ULONG newCapacity = this->_capacity + this->_growBy;
		this->_growBy *= 2;
        LONG *newItems = this->createNullArray(newCapacity);
        if (this->_items) {
            memcpy((newItems + sizeof(LONG)), this->_items, sizeof(LONG) * this->_size);
            delete[] this->_items;
        }
        newItems[0] = (LONG)(new CString(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] = (LONG)(new CString(data));
        this->_size++;
    }
}

VOID CStringList::addAsFirst(WCHAR* data) {
    CString s(data);
    this->addAsFirst(s);
}

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

    if (this->_size == this->_capacity) {
        ULONG newCapacity = this->_capacity + this->_growBy;
		this->_growBy *= 2;
        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)(new CString(data));
    this->_size++;
}

ULONG CStringList::del(CString data) {
    ULONG removed = 0;
	CString *s;

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

    return removed;
}

BOOL CStringList::delFirst(CString data) {
    BOOL removed = FALSE;
	CString *s;

    for (ULONG i = 0; i < this->_size; i++) {
		s = (CString*)this->_items[i];
        if (*s == 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 CStringList::delAt(ULONG pos) {
    if (pos >= this->_size) {
        return FALSE;
    }

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

    return TRUE;
}

LONG CStringList::pos(CString data) {
	CString *s;

    for (ULONG i = 0; i < this->_size; i++) {
		s = (CString*)this->_items[i];
        if (*s == data) {
            return i;
        }
    }

    return -1;
}

BOOL CStringList::contains(CString data) {
    return this->pos(data) >= 0;
}

VOID CStringList::clear() {
	CString *s;
    if (this->_items) {
        ULONG i;
		for (i = 0; i < this->_size; i++) {
			s = (CString*)this->_items[i];
			delete s;
		}
        this->_items[i] = NULL;
    }
    this->_size = 0;
}

VOID CStringList::writeToFile(CString fname) {
	WriteFile(fname, this, ENC_UTF8);
}

VOID CStringList::readFromFile(CString fname) {
}

VOID CStringList::joinIntoStringArray(CString* result, WCHAR glue) {
    if (result) {
        *result = COMMON_EMPTY_STRING;
        WCHAR* item = NULL;
        for (ULONG i = 0; i < this->_size; i++) {
            if (this->_items[i]) {
                item = ((CString*)this->_items[i])->toWCHAR();
                (*result).appendAfterEos(item, glue);
            }
        }
    }
}

CString CStringList::join(WCHAR* glue) {
    CString s;
    for (ULONG i = 0; i < this->_size; i++) {
        s.append(((CString*)this->_items[i])->getBuffer());
        if (i != this->_size - 1) {
            s.append(glue);
        }
    }
    
    return s;
}

CString CStringList::toString() {
    return this->join(L"\n");
}

CStringList::operator WCHAR*() {
    static CString s;
    s = this->toString();
    return s.getBuffer();
}
