#include "record.h"

#include <maps/wikimap/mapspro/tools/ymapsdf-conversion/json2ymapsdf/lib/common/data_error.h>
#include <maps/wikimap/mapspro/tools/ymapsdf-conversion/json2ymapsdf/lib/common/log.h>
#include <maps/wikimap/mapspro/tools/ymapsdf-conversion/json2ymapsdf/lib/tds/schema.h>
#include "bucket.h"
#include "schema/pqxx.h"
#include "schema/schema.h"

#include <maps/libs/common/include/exception.h>

namespace maps::wiki::json2ymapsdf::ymapsdf {

Record::Record(const schema::Schema& schema, const std::string& tableName)
    : table_(&schema.table(tableName))
{
    fieldValues_.reserve(table_->size());
    for (size_t i = 0; i < table_->size(); ++i) {
        fieldValues_.emplace_back((*table_)[i]);
    }
}

Record::Record(const schema::Table* table)
    : table_(table)
{
    fieldValues_.reserve(table_->size());
    for (size_t i = 0; i < table_->size(); ++i) {
        fieldValues_.emplace_back((*table)[i]);
    }
}

Record
Record::defaultRecord(const schema::Table& table)
{
    Record record(&table);
    for (auto& field: record.fieldValues_) {
        if (field.hasDefault()) {
            field.touch();
        }
    }
    return record;
}

Record
Record::defaultRecord(const schema::Schema& schema, const std::string& tableName)
{
    return defaultRecord(schema.table(tableName));
}

bool
Record::valid() const
{
    for (const auto& field: fieldValues_) {
        if (!field.valid()) {
            return false;
        }
    }
    return true;
}

bool
Record::broken() const
{
    for (const auto& field: fieldValues_) {
        if (field.filled() && !field.valid()) {
            return true;
        }
    }
    return false;
}

bool
Record::completed() const
{
    for (const auto& field: fieldValues_) {
        if (!field.filled()) {
            return false;
        }
    }
    return true;
}

bool
Record::empty() const
{
    size_t emptyFields = 0;
    size_t notEmptyFields = 0;
    for (const auto& field: fieldValues_) {
        if (!field.empty() && *field != field.column().defaultValue())  {
            ++notEmptyFields;
        } else if (!field.column().isService()) {
            ++emptyFields;
        }
    }
    if (emptyFields == 0) {
        return false;
    }
    if (notEmptyFields > 1) {
        return false;
    }
    return true;
}

bool
Record::toDelete() const
{
    return *fieldValues_[DELETE_ID] == VALUE_TRUE;
}

Value&
Record::operator [] (size_t fieldId)
{
    return fieldValues_[fieldId];
}

Value&
Record::operator [] (const std::string& fieldName)
{
    return (*this)[table()[fieldName].id()];
}

const Value&
Record::operator [] (size_t fieldId) const
{
    return fieldValues_[fieldId];
}

const Value&
Record::operator [] (const std::string& fieldName) const
{
    return (*this)[table()[fieldName].id()];
}

bool
Record::operator == (const Record& other) const
{
    return table_ == other.table_
        && fieldValues_ == other.fieldValues_;
}

bool
Record::operator != (const Record& other) const
{
    return !(*this == other);
}

bool
Record::operator < (const Record& other) const
{
    if (key() != other.key()) {
        return key() < other.key();
    } else if (&table() != &other.table()){
        return table().name() < other.table().name();
    }
    for (size_t i = 0; i < fieldValues_.size(); ++i) {
        if (*(*this)[i] != *other[i]) {
            return *(*this)[i] < *other[i];
        }
    }
    return false;
}

} // namespace maps::wiki::json2ymapsdf::ymapsdf
