/*
 * This is the source code of tgnet library v. 1.0
 * It is licensed under GNU GPL v. 2 or later.
 * You should have received a copy of the license in this archive (see LICENSE).
 *
 * Copyright Nikolai Kudashov, 2015.
 */

#include "Config.h"
#include "ConnectionsManager.h"
#include "FileLog.h"
#include "BuffersStorage.h"

Config::Config(std::string fileName) {
    configPath = ConnectionsManager::getInstance().currentConfigPath + fileName;
    backupPath = configPath + ".bak";
    FILE *backup = fopen(backupPath.c_str(), "rb");
    if (backup != nullptr) {
        remove(configPath.c_str());
        rename(backupPath.c_str(), configPath.c_str());
        fclose(backup);
    }
}

NativeByteBuffer *Config::readConfig() {
    NativeByteBuffer *buffer = nullptr;
    FILE *file = fopen(configPath.c_str(), "rb");
    if (file != nullptr) {
        fseek(file, 0, SEEK_END);
        long fileSize = ftell(file);
        fseek(file, 0, SEEK_SET);
        uint32_t size = 0;
        int bytesRead = fread(&size, sizeof(uint32_t), 1, file);
        DEBUG_D("Config(%p, %s) load, size = %u", this, configPath.c_str(), size);
        if (bytesRead > 0 && size > 0 && (int32_t) size < fileSize) {
            buffer = BuffersStorage::getInstance().getFreeBuffer(size);
            if (fread(buffer->bytes(), sizeof(uint8_t), size, file) != size) {
                buffer->reuse();
                buffer = nullptr;
            }
        }
        fclose(file);
    }
    return buffer;
}

void Config::writeConfig(NativeByteBuffer *buffer) {
    FILE *file = fopen(configPath.c_str(), "rb");
    FILE *backup = fopen(backupPath.c_str(), "rb");
    bool error = false;
    if (file != nullptr) {
        if (backup == nullptr) {
            fclose(file);
            if (rename(configPath.c_str(), backupPath.c_str()) != 0) {
                DEBUG_E("Config(%p) unable to rename file %s to backup file %s", this, configPath.c_str(), backupPath.c_str());
                error = true;
            }
        } else {
            fclose(file);
            fclose(backup);
            remove(configPath.c_str());
        }
    }
    if (error) {
        return;
    }
    file = fopen(configPath.c_str(), "wb");
    if (file == nullptr) {
        return;
    }
    uint32_t size = buffer->position();
    if (fwrite(&size, sizeof(uint32_t), 1, file) == 1) {
        if (fwrite(buffer->bytes(), sizeof(uint8_t), size, file) != size) {
            error = true;
        }
    } else {
        error = true;
    }
    fclose(file);
    if (error) {
        remove(configPath.c_str());
    } else {
        remove(backupPath.c_str());
    }
}
