#include "KSGTFile.h"

#include "File.h"
#include "Text.h"

using namespace Framework;

// Contents of the KSGTFile class from KSGTFile.h
// Constructor
KSGTFile::KSGTFile()
    : ReferenceCounter(),
      pfad(new Text()),
      data(new RCArray<RCArray<Text>>())
{}

KSGTFile::KSGTFile(const char* pfad)
    : ReferenceCounter(),
      pfad(new Text()),
      data(new RCArray<RCArray<Text>>())
{
    setPfad(pfad);
}

KSGTFile::KSGTFile(Text* pfad)
    : ReferenceCounter(),
      pfad(new Text()),
      data(new RCArray<RCArray<Text>>())
{
    setPfad(pfad);
}

// Destructor
KSGTFile::~KSGTFile()
{
    pfad->release();
    data->release();
}

// non-constant
void KSGTFile::setPfad(const char* pfad)
{
    this->pfad->setText(pfad);
}

void KSGTFile::setPfad(Text* pfad)
{
    this->pfad->setText(*pfad);
    pfad->release();
}

bool KSGTFile::load()
{
    std::ifstream inf;
    inf.open(pfad->getText(), std::ios::binary);
    if (!inf.good() || !inf.is_open()) return 0;
    data->clear();
    inf.seekg(0, std::ios::end);
    __int64 gr = inf.tellg();
    __int64 pos = 0;
    int zeilenPos = 0;
    int feldPos = 0;
    while (pos < gr)
    {
        inf.seekg(pos, std::ios::beg);
        char c = 1;
        int len = 0;
        do
        {
            inf.read(&c, 1);
            ++len;
        } while (c != 0 && c != '\n' && pos + len < gr);
        if (pos + len == gr) ++len;
        inf.seekg(pos, std::ios::beg);
        char* v = new char[len];
        v[len - 1] = 0;
        if (len > 1) inf.read(v, len - 1);
        pos += len;
        if (zeilenPos > data->getLastIndex()) data->add(new RCArray<Text>);
        auto line = data->z(zeilenPos);
        if (feldPos > line->getLastIndex())
            line->add(new Text(v));
        else
            line->z(feldPos)->setText(v);
        delete[] v;
        if (c == 0)
            ++feldPos;
        else if (c == '\n')
        {
            ++zeilenPos;
            feldPos = 0;
        }
        else
            break;
    }
    inf.close();
    return 1;
}

bool KSGTFile::addRow(int fieldCount, RCArray<Text>* zValue)
{
    auto line = new RCArray<Text>();
    data->add(line);
    for (Text* t : *zValue)
        line->add((Text*)t ? new Text(t->getText()) : 0);
    return 1;
}

bool KSGTFile::setRow(int zeile, int fieldCount, RCArray<Text>* zValue)
{
    int zA = getRowCount();
    if (zeile >= zA) return 0;
    auto line = new RCArray<Text>();
    data->set(line, zeile);
    for (Text* t : *zValue)
        line->add(t ? new Text(t->getText()) : 0);
    return 1;
}

bool KSGTFile::removeRow(int zeile)
{
    int zA = getRowCount();
    if (zeile >= zA) return 0;
    data->remove(zeile);
    return 1;
}

bool KSGTFile::addField(int zeile, int pos, Text* wert)
{
    int zA = getRowCount();
    if (zeile >= zA)
    {
        wert->release();
        return 0;
    }
    int fA = getFieldCount(zeile);
    if (pos > fA)
    {
        wert->release();
        return 0;
    }
    data->z(zeile)->add(new Text(wert->getText()), pos);
    wert->release();
    return 1;
}

bool KSGTFile::addField(int zeile, int pos, const char* wert)
{
    return addField(zeile, pos, new Text(wert));
}

bool KSGTFile::addField(int zeile, Text* wert)
{
    int zA = getRowCount();
    if (zeile >= zA)
    {
        wert->release();
        return 0;
    }
    data->z(zeile)->add(new Text(wert->getText()));
    wert->release();
    return 1;
}

bool KSGTFile::addField(int zeile, const char* wert)
{
    return addField(zeile, new Text(wert));
}

bool KSGTFile::setField(int zeile, int feld, Text* wert)
{
    int zA = getRowCount();
    if (zeile >= zA)
    {
        wert->release();
        return 0;
    }
    int fA = getFieldCount(zeile);
    if (feld >= fA)
    {
        wert->release();
        return 0;
    }
    data->z(zeile)->set(new Text(wert->getText()), feld);
    wert->release();
    return 1;
}

bool KSGTFile::setField(int zeile, int feld, const char* wert)
{
    return setField(zeile, feld, new Text(wert));
}

bool KSGTFile::removeField(int zeile, int feld)
{
    int zA = getRowCount();
    if (zeile >= zA) return 0;
    int fA = getFieldCount(zeile);
    if (feld >= fA) return 0;
    data->z(zeile)->remove(feld);
    return 1;
}

bool KSGTFile::save()
{
    if (!pfad->getLength()) return 0;
    if (!FileExists(pfad->getText())) FilePathCreate(pfad->getText());
    std::ofstream of(pfad->getText(), std::ios::binary);
    if (!of.good() || !of.is_open()) return 0;
    int i = 0;
    for (auto line = data->begin(); line; line++, i++)
    {
        if (i) of.write("\n", 1);
        int f = 0;
        for (auto field = line->begin(); field; field++, f++)
        {
            if (f) of.write("\0", 1);
            if ((Text*)field) of.write(field->getText(), field->getLength());
        }
    }
    of.close();
    return 1;
}

// constant
int KSGTFile::getRowCount() const
{
    return data->getEntryCount();
}

int KSGTFile::getFieldCount(int zeile) const
{
    int zA = getRowCount();
    if (zeile >= zA) return 0;
    return data->z(zeile)->getEntryCount();
}

Text* KSGTFile::getField(int zeile, int feld) const
{
    int zA = getRowCount();
    if (zeile >= zA) return 0;
    int fA = getFieldCount(zeile);
    if (feld >= fA) return 0;
    return data->z(zeile)->get(feld);
}

Text* KSGTFile::zField(int zeile, int feld) const
{
    int zA = getRowCount();
    if (zeile >= zA) return 0;
    int fA = getFieldCount(zeile);
    if (feld >= fA) return 0;
    return data->z(zeile)->z(feld);
}