#ifndef P2C_CONFIG_H
#define P2C_CONFIG_H


#include <string>
#include <vector>
#include <map>
#include "Template_config.h"
#include "Face_config.h"
#include "Body_config.h"
#include "Front_body_config.h"
#include "Back_body_config.h"
#include "Left_body_config.h"
#include "Right_body_config.h"
#include "Pointset_config.h"
#include "Head_config.h"
#include "Hand_config.h"
#include "Left_or_right_hand_config.h"

#include "Point_set_config.h"
#include "General_config.h"

namespace p2c
{


class Config
{
    //singleton stuff ---------------------------------------------------------
public:
    static Config* instance();


private:
    static Config* instance_;
    Config();
    Config(const Config&) {}
    ~Config(){}

    /*!
         * \brief The Guard class
         * Guard to make sure all data are properly deleted.
         */
    class Guard
    {
    public:
        ~Guard()
        {
            if (Config::instance_ != nullptr)
            {
                delete Config::instance_;
                Config::instance_ = nullptr;
            }
        }
    };

    friend class Guard;

    //singleton stuff end------------------------------------------------------

private:
    std::vector<std::string> argv_;

    //from environment
    std::string metashape_exec_;
    std::string metashape_script_dir_;

    std::string texture_generation_script_;
    std::string partial_texture_generation_script_;
    std::string texture_merge_script_;


    std::vector<std::string> input_filenames_;


    std::map<std::string, std::map<std::string, std::string> > data_;

    Template_config tmpl_config_;

    Body_config body_config_;

    Front_body_config front_body_config_;

    Back_body_config back_body_config_;

    Left_body_config left_body_config_;

    Right_body_config right_body_config_;

    Face_config face_config_;

    Head_config head_config_;

    Left_or_right_hand_config left_hand_config_;

    Left_or_right_hand_config right_hand_config_;

    Hand_config hand_config_;

    Point_set_config point_set_config_;

    General_config general_config_;

    Pointset_config pointset_config_;
public:

    bool parse_cmd_line(int argc, char** argv);

    //getter
    const std::vector<std::string>& get_argv() { return argv_; }

    const std::vector<std::string>& input_filenames() { return input_filenames_; }

    Template_config &tmpl(){return tmpl_config_;}
    Face_config &face(){return face_config_;}
    Body_config &body(){return body_config_;}
    Front_body_config &front_body(){return front_body_config_;}
    Back_body_config &back_body(){return back_body_config_;}
    Left_body_config &left_body(){return left_body_config_;}
    Right_body_config &right_body(){return right_body_config_;}
    Head_config &head(){return head_config_;}
    Left_or_right_hand_config &left_hand(){return left_hand_config_;}
    Left_or_right_hand_config &right_hand(){return right_hand_config_;}
    Hand_config &hand(){return hand_config_;}
    Point_set_config &point_set(){return point_set_config_;}
    General_config & general(){return general_config_;}
    Pointset_config & pointset(){return pointset_config_;}

    const std::string& get_metashape_exec() {return metashape_exec_;}
    const std::string& get_metashape_script_dir() {return metashape_script_dir_;}
    const std::string& get_texture_generation_script() {return texture_generation_script_;}
    const std::string& get_partial_texture_generation_script() {return partial_texture_generation_script_;}
    const std::string& get_texture_merge_script() {return texture_merge_script_;}

private:

    void print_config_data(const std::string &msg);

};

}

#endif
