// ========================================================================== //
// Class inclusion
#include "StreamSurfaces/StreamSurfaces.hpp"

// Local libraries
#include "Frames/FrameField.hpp"
#include "Options/options.hpp"
#include "Utilities/string_operations.hpp"

// External libraries
#include <GEL/CGLA/CGLA.h>

// Standard libraries
#include <filesystem>
#include <iostream>
#include <vector>

// ========================================================================== //
// Construction and Deconstruction

StreamSurfaces::StreamSurfaces(std::string opt_file) {
    Options opt(opt_file);
    constructor(opt);
}
StreamSurfaces::StreamSurfaces(Options &opt) { constructor(opt); }

void StreamSurfaces::constructor(Options &opt) {

    // Read the input files
    this->read_options(opt);
    this->read_information();

    Utilities::debug_info(__FILE__, __LINE__, "Setup and IO", debug);

    // Setup the frame field
    frame = new FrameGrid(dimX, dimY, dimZ, dimS);

    frame->read(data_location + data_name);

    bbox      = frame->get_bbox();
    bbox_diag = bbox.diagonal().length();

    desired_spacing  = bbox.diagonal().min_coord() / desired_spacing;
    desired_surfaces = 1 + int(CGLA::dot(bbox.diagonal(), CGLA::Vec3d(1.0)) /
                               (tolerated_error * desired_spacing));
    desired_surfaces =
        std::max(surf_min_number, std::min(surf_max_number, desired_surfaces));

    this->read_input();
    this->read_probe();

    if (singularity_toggle) frame->read_singular(data_location + data_name);
}

// ========================================================================== //
// Setting up default option values and read specifications from user

// This function overwrites the default values, specified in StreamSurfaces.hpp
// with the values specified by the user through the options file.
void StreamSurfaces::read_options(Options &opt) {

    // Specification of input names and structure
    opt.get("data_name", data_name);
    opt.get("data_location", data_location);

    // Meta settings
    opt.get("tolerated_error", tolerated_error);
    opt.get("desired_spacing", desired_spacing);

    // Generation of surfaces
    opt.get("surf_pds_r", surf_pds_r);
    opt.get("surf_pds_k", surf_pds_k);
    opt.get("include_hull", include_hull);
    opt.get("surf_min_number", surf_min_number);
    opt.get("surf_max_number", surf_max_number);

    // Implicit system
    opt.get("singularity_toggle", singularity_toggle);

    // Topology optimization settings
    opt.get("threshold_void", threshold_void);
    opt.get("threshold_solid", threshold_solid);

    // Super Sampling and Post-processing
    opt.get("super_sampling", super_sampling);
    opt.get("super_sample_pds_r", super_sample_pds_r);
    opt.get("smooth_max_iter", smooth_max_iter);

    // Input specifications
    opt.get("seed_method", seed_method);
    opt.get("seed_grid_amount", seed_grid_amount);
    opt.get("seed_pds_r", seed_pds_r);
    opt.get("seed_file_type", seed_file_type);
    opt.get("seed_file_name", seed_file_name);

    // Computation of voxel indicator response
    opt.get("probe_method", probe_method);
    opt.get("probe_grid_max", probe_grid_max);
    opt.get("probe_file_name", probe_file_name);

    // Export Settings
    opt.get("export_name", export_name);
    opt.get("export_location", export_location);

    // Meta settings
    opt.get("debug", debug);

    opt.write_file();

    // Ensure options are correctly setup
    data_name += data_name.back() != '/' ? "/" : "";
    data_location += data_location.back() != '/' ? "/" : "";
    export_location += export_location.back() != '/' ? "/" : "";

    std::filesystem::create_directory(export_location);
}

// End of File
// ========================================================================== //