//
// Created by Иван_Архипов on 07.11.2017.
//
#include "SubDirectory.h"

#include "DatFile.h"
#include "DatException.h"
#include "Subfile.h"
#include "BinaryData.h"


LOTRO_DAT::SubDirectory::SubDirectory() {
    offset_ = 0;
}

LOTRO_DAT::SubDirectory::SubDirectory(long long offset, DatFile *dat) :
        offset_(offset), dat_(dat) {
    try {
        MakeSubDirectories();
    } catch (...) {
		fprintf(stderr, "Unable to initialize directory at offset %lld. Initializing as empty directory...\n", offset);
		subdirs_.clear();
		subfiles_.clear();
		return;
	}

    try {
        MakeSubFiles();
	} catch (...) {
		fprintf(stderr, "Unable to initialize directory at offset %lld. Initializing as empty directory...\n", offset);
		subdirs_.clear();
		subfiles_.clear();
		return;
	}
}

void LOTRO_DAT::SubDirectory::MakeSubDirectories() {
    BinaryData data(1024);
    dat_->ReadData(data, 63 * 8, offset_);
    if (data.ToNumber<4>(0) != 0 || data.ToNumber<4>(4) != 0) {
        std::string err =
                std::string("Bad SubDirectory::MakeSubDirectories - first 8 bytes are not equal to 0 at offset ")
                + std::to_string(offset_);
        throw DatException(err.c_str(), SUBDIR_EXCEPTION);
    }

    for (unsigned int i = 8; i < 63 * 8; i += 8) {
        if (data.ToNumber<4>(i) == 0)
            break;

        try {
            subdirs_.emplace_back(
                    SubDirectory(
                            data.ToNumber<4>(i + 4),
                            dat_
                    )
            );

        } catch (...) {
            fprintf(stderr, "Making SubDirectory at offset %lld failed, continuing\n",  data.ToNumber<4>(i + 4));
        }
    }
}

void LOTRO_DAT::SubDirectory::MakeSubFiles() {
    BinaryData data(64 * 32);
    dat_->ReadData(data, 64 * 32, offset_ + 63 * 8);

    for (unsigned int i = 0; i < 61 * 32; i += 32) {
        if (data.ToNumber<4>(i + 8) < 0x32 || data.ToNumber<4>(i + 12) < 0x32)
            continue;
        subfiles_.emplace_back(
            Subfile(
                    dat_,
                    data.ToNumber<4>(i), // fragments_count
                    data.ToNumber<4>(i + 4), // unknown1
                    data.ToNumber<4>(i + 8), // file_id
                    data.ToNumber<4>(i + 12), // file_offset
                    data.ToNumber<4>(i + 16), // block_size
                    data.ToNumber<4>(i + 20), // timestamp
                    data.ToNumber<4>(i + 24), // version
                    data.ToNumber<4>(i + 28) // block_size
            )
        );
    }
}

void LOTRO_DAT::SubDirectory::MakeDictionary(std::unordered_map<long long, Subfile *> &dict) {
    for (Subfile &i : subfiles_) {
        //if (dict.count(i.file_id()) != 0 && dict[i.file_id()]->file_offset() != i.file_offset())
        //    throw DatException("Bad SubDirectory::MakeDictionary() - found 2 files with different offset!!!", SUBFILE_EXCEPTION);
        if (dict.count(i.file_id()) == 0 || dict[i.file_id()]->timestamp() < i.timestamp()
            || (dict[i.file_id()]->timestamp() == i.timestamp() && dict[i.file_id()]->block_size() < i.block_size()))
			dict[i.file_id()] = &i;
    }
    for (SubDirectory &i : subdirs_)
        i.MakeDictionary(dict);
}
