#ifndef ROFIWORLD_LOADER_INCLUDED
#define ROFIWORLD_LOADER_INCLUDED

#include <rofi/connector.hpp>
#include <rofi/module.hpp>
#include <rofi/voxel.hpp>
#include <rofi/voxel_graph.hpp>
#include <rofi/rofiworld.hpp>

#include <boost/json.hpp>

#include <filesystem>

/* EXPORT */

void export_rofiworld(const rofiworld_ptr rofiworld, const std::vector<objectbase_ptr> &selected_space_joints, const char* file_name);

/* EXPORT MODULES */

void export_modules(boost::json::array &modules_array, const std::map<module_ptr, uint64_t> &modules_map);
void export_module_cube(boost::json::array &modules_array, const module_ptr module, const uint64_t &id);
void export_module_universal(boost::json::array &modules_array, const module_ptr module, const uint64_t &id);
void export_alpha_beta(boost::json::object &module_object, const module_ptr module);
void export_gamma(boost::json::object &module_object, const module_ptr module);
void export_module_pad(boost::json::array &modules_array, const module_ptr module, const uint64_t &id);
void export_module_unknown(boost::json::array &modules_array, const module_ptr module, const uint64_t &id);

/* EXPORT SPACEJOINTS */

void export_spaceJoints(boost::json::array &spaceJoints_array, const rofiworld_ptr rofiworld, const std::vector<objectbase_ptr> &selected_space_joints);
void export_spaceJoint(boost::json::array &spaceJoints_array, const rofiworld_ptr rofiworld, const node_ptr node, const uint64_t component_id, const std::string &module_type);
void export_spaceJoint_point(boost::json::object &spaceJoint_object, const node_ptr node);
void export_spaceJoint_joint(boost::json::object &spaceJoint_object, const node_ptr node);
void export_spaceJoint_joint_matrix(boost::json::object &joint_object, const node_ptr node);
void export_spaceJoint_to(boost::json::object &spaceJoint_object, const rofiworld_ptr rofiworld, const uint64_t module_id, const uint64_t component_id);

/* EXPORT MODULEJOINTS */

void export_moduleJoints(boost::json::array &moduleJoints_array, const rofiworld_ptr rofiworld);
void export_moduleJoint(boost::json::array &moduleJoints_array, const rofiworld_ptr rofiworld, const std::shared_ptr<rofi::ModuleLink> module_link);
void export_moduleJoint_fromto(boost::json::object &moduleJoint_object, const module_ptr module, const uint64_t module_id, const connector_ptr connector, const std::string &&where);
void export_moduleJoint_orientation(boost::json::object &moduleJoint_object, const connector_ptr from_con, const connector_ptr to_con);


/* IMPORT */

std::vector<rofiworld_ptr> import_saved_configurations_rofiworld();
rofiworld_ptr import_rofiworld(const std::filesystem::path file_path);
void get_rofiworld_data(const boost::json::object &json_object, 
                        boost::json::array &modules_array, 
                        boost::json::array &spaceJoints_array, 
                        boost::json::array &moduleJoints_array);

bool import_modules(rofiworld_ptr rofiworld, const boost::json::array &modules_array);
void rotate_universal_joints(const boost::json::object &module_object, rofiworld_ptr rofiworld, module_ptr um_module);
module_ptr import_pad(const uint64_t width, const uint64_t height);

bool import_spaceJoints(rofiworld_ptr rofiworld, const boost::json::array &spaceJoints_array, std::set<module_ptr> &spaceJoint_modules);
bool import_spaceJoint(rofiworld_ptr rofiworld, const boost::json::object &spaceJoint_object, std::set<module_ptr> &spaceJoint_modules);
module_ptr import_spaceJoint_to(rofiworld_ptr rofiworld, const boost::json::object &to_object);
void import_spaceJoint_point(const module_ptr module, const boost::json::array &point);
void import_spaceJoint_joint(rofiworld_ptr rofiworld, const module_ptr module, const boost::json::object &joint);

void import_moduleJoints(rofiworld_ptr rofiworld, const boost::json::array &moduleJoints_array, std::set<module_ptr> &spaceJoint_modules);
module_ptr import_moduleJoint(rofiworld_ptr rofiworld, module_ptr module, const std::set<module_ptr> &searched_modules, const boost::json::object &moduleJoint_object);
std::pair<module_ptr, connector_ptr> get_moduleJoint_module_connector(rofiworld_ptr rofiworld, const boost::json::object &where_object);
rofi::cardinal get_moduleJoint_orientation(const boost::json::string &orientation_string);

#endif