#pragma once
#include "Arguments.h"
#include <string>
#include <vector>

namespace ArgumentParser {

class ArgParser {

public:

    ArgParser(const std::string& name)
      : parser_name_(name)
    {}
    ~ArgParser() {};

    bool Parse(std::vector<std::string> args);

    ArgParser& AddStringArgument(const std::string param);
    ArgParser& AddStringArgument(const char short_param, const std::string param);
    ArgParser& AddStringArgument(const char short_param, const std::string param, const std::string description);
    std::string GetStringValue(const std::string param);

    Args& AddIntArgument(const std::string number);
    Args& AddIntArgument(const std::string numer, const std::string description);
    int GetIntValue(const std::string param);
    Args& AddIntArgument(const char short_param, const std::string param);
    int GetIntValue(const std::string param, const int ind);

    Args& AddFlag(const char short_flag, const std::string flag);
    Args& AddFlag(const char short_flag, const std::string flag, const std::string description);
    Args& AddFlag(const std::string flag, const std::string description);

    bool GetFlag(const std::string flag);

    Args& AddHelp(const char short_help, const std::string help, const std::string description);
    bool Help();
    std::string HelpDescription();

private:

    std::string parser_name_;
    std::vector<Args*> all_;
    
};

}
#include "ArgParser.h"
#include "Arguments.h"
#include <string>
#include <vector>
#include <iostream>

namespace ArgumentParser {

    bool ArgParser::Parse(std::vector<std::string> args) {
        if (all_.empty() && args.size() == 1) {
            return true;
        }
        int count = 0;
        for (int i = 0; i < args.size(); ++i) {

                std::string origin_param = "--" + all_[j]->GetParam() + "=";
                std::string origin_short_param = "-";
                origin_short_param.push_back(all_[j]->GetShortParam());
                origin_short_param += "=";

                if (args.size() == 1 && !all_[j]->GetDefaultValue().empty()) {
                    all_[j]->PutValue(all_[j]->GetDefaultValue());
                    ++count;
                } else if (!all_[j]->GetParam().empty() && args[i].substr(0, origin_param.length()) == origin_param && !all_[j]->GetFlagMultiValue()) {
                    all_[j]->PutValue(args[i].substr(origin_param.length(), args[i].length()));
                    if (all_[j]->GetFlagStoreValue()) {
                        all_[j]->AddStoreValue(all_[j]->GetValue());
                    }
                    ++count;
                } else if (all_[j]->GetFlagShortParam() && args[i].substr(0, origin_short_param.length()) == origin_short_param && !all_[j]->GetFlagMultiValue()) {
                    all_[j]->PutValue(args[i].substr(origin_short_param.length(), args[i].length()));
                    if (all_[j]->GetFlagStoreValue()) {
                        all_[j]->AddStoreValue(all_[j]->GetValue());
                    }
                    ++count;
                } else if (all_[j]->GetFlagMultiValue()) {
                    if (args[i].substr(0, origin_param.length()) == origin_param) {
                        all_[j]->PutValue(args[i].substr(origin_param.length(), args[i].length()));
                        all_[j]->MultiArgsCount();
                    } else if (all_[j]->GetFlagShortParam() && args[i].substr(0, origin_short_param.length()) == origin_short_param) {
                        all_[j]->PutValue(args[i].substr(origin_short_param.length(), args[i].length()));
                        all_[j]->MultiArgsCount();
                    }
                    if (args[i][0] == '-' && all_[j]->GetFlagStoreValues()) {
                        all_[j]->AddStoreValues(all_[j]->GetValue());
                        all_[j]->AddAllValues(all_[j]->GetValue());
                    }
                }

                std::string origin_flag = "--" + all_[j]->GetFlag();
                std::string origin_help = "--" + all_[j]->GetHelp();
                std::string origin_short_help = "-";
                origin_short_help.push_back(all_[j]->GetShortHelp());

                if (all_[j]->GetIsFlag()) {
                    if (args[i].substr(0, origin_flag.length()) == origin_flag) {
                        if (all_[j]->GetFlagStoreFlag()) {
                            all_[j]->AddStoreFlag(true);
                        }
                        ++count;
                    } else if (args[i][0] == '-' && args[i][1] != '-' && args[i].length() > 2) {
                        for (int z = 1; z < args[i].length(); ++z) {
                            if (args[i][z] == all_[j]->GetShortFlag()) {
                                if (all_[j]->GetFlagStoreFlag()) {
                                all_[j]->AddStoreFlag(true);
                                }
                                ++count;
                            }
                        }
                    }
                } else if (all_[j]->GetFlagPositional()) {
                    int count_len = 0;
                    for (int k = 0; k < args[i].length(); ++k) {
                        if (!std::isdigit(args[i][k])){
                            break;
                        } else {
                            ++count_len;
                        }
                    }
                    if (count_len == args[i].length()) {
                        all_[j]->PutValue(args[i]);
                        all_[j]->MultiArgsCount();
                        if (all_[j]->GetFlagStoreValues()) {
                            all_[j]->AddStoreValues(all_[j]->GetValue());
                            all_[j]->AddAllValues(all_[j]->GetValue());
                        }
                    }
                } else if (args[i].substr(0, origin_help.length()) == origin_help || args[i].substr(0, origin_short_help.length()) == origin_short_help) {
                    all_[j]->FlagHelp();
                    ++count;
                }
        }
        for (int i = 0; i < all_.size(); ++i) {
            if (all_[i]->GetMultiArgsCount() > 0) {
                ++count;
            }
            if (all_[i]->GetFlagDefaultFlag()) {
                ++count;
            }
            if (all_[i]->GetMultiArgsCount() > 0 && all_[i]->GetMinArgsCount() > all_[i]->GetMultiArgsCount()) {
                return false;
            }
        }
        if (count == all_.size()) {
            return true;
        } else {
            for (int i = 0; i < all_.size(); ++i) {
                if (all_[i]->GetFlagHelp()) {
                    return true;
                }
            }
            return false;
        }
    }

    ArgParser& ArgParser::AddStringArgument(const std::string param) {
        String* str = new String();
        str->param_ = param;
        all_->push_back(*str);
        return *this;
    }

    ArgParser& ArgParser::AddStringArgument(const char short_param, const std::string param) {
        String* str = new String();
        str->short_param_ = short_param;
        str->param_ = param;
        all_->push_back(*str);
        return *this;
    }

    ArgParser& ArgParser::AddStringArgument(const char short_param, const std::string param, const std::string description) {
        String* str = new String();
        str->param_ = param;
        all_->push_back(*str);
        str->Description(description);
        return *this;
    }

    std::string ArgParser::GetStringValue(const std::string param) {
        for (int i = 0; i < (all_).size(); ++i) {
            if (static_cast<String*>(all_[i])->param_ == param) {
                return static_cast<String*>(all_[i])->GetValue();
            }
        }
    }

    Args& ArgParser::AddIntArgument(const std::string number) {
        Args* int_val = new Args(number);
        all_.push_back(int_val);
        return *int_val;
    }

    Args& ArgParser::AddIntArgument(const std::string numer, const std::string description) {
        Args* int_val = new Args(numer);
        all_.push_back(int_val);
        int_val->Description(description);
        return *int_val;
    }

    int ArgParser::GetIntValue(const std::string param) {
        for (int i = 0; i < all_.size(); ++i) {
            if (all_[i]->GetParam() == param) {
                int value = std::stoi(all_[i]->GetValue());
                return value;
            }
        }
    }

    Args& ArgParser::AddIntArgument(const char short_param, const std::string param) {
        Args* int_val = new Args(short_param, param);
        all_.push_back(int_val);
        return *int_val;
    }

    int ArgParser::GetIntValue(const std::string param, const int ind) {
        if (all_[ind]->GetParam() == param) {
            return all_[ind]->GetIndexedValue(ind);
        }
    }

    Args& ArgParser::AddFlag(const char short_flag, const std::string flag) {
        Args* new_flag = new Args();
        new_flag->AddFlags(short_flag, flag);
        all_.push_back(new_flag);
        return *new_flag;
    }

    Args& ArgParser::AddFlag(const char short_flag, const std::string flag, const std::string description) {
        Args* new_flag = new Args();
        new_flag->AddFlags(short_flag, flag);
        all_.push_back(new_flag);
        new_flag->Description(description);
        return *new_flag;
    }

    Args& ArgParser::AddFlag(const std::string flag, const std::string description) {
        Args* new_flag = new Args();
        new_flag->AddFlag(flag);
        all_.push_back(new_flag);
        new_flag->Description(description);
        return *new_flag;
    }

    bool ArgParser::GetFlag(const std::string flag) {
        for (int i = 0; i < all_.size(); ++i) {
            if (all_[i]->GetFlag() == flag) {
                return true;
            }
        }
        return false;
    }

    bool ArgParser::Help() {
        return true;
    }

    Args& ArgParser::AddHelp(const char short_help, const std::string help, const std::string description) {
        Args* new_help = new Args();
        new_help->Help(short_help, help);
        new_help->Description(description);
        all_.push_back(new_help);
        return *new_help;
    }

    std::string ArgParser::HelpDescription() {
        std::cout << "My Parser\n";
        std::cout << "Some Description about program\n\n";
        std::cout << "-i,  --input=<string>,  File path for input file [repeated, min args = 1]\n";
        std::cout << "-s,  --flag1,  Use some logic [default = true]\n";
        std::cout << "-p,  --flag2,  Use some logic\n";
        std::cout << "     --number=<int>,  Some Number\n\n";
        std::cout << "-h, --help Display this help and exit\n";
    }

}#pragma once
#include <string>
#include <vector>

namespace ArgumentParser {

class Args {
public:
    Args();
    Args(const std::string param);
    Args(const char short_param, const std::string param);
    ~Args() {};

    Args& MultiValue();
    Args& MultiValue(const int min_args_count);
    bool GetFlagMultiValue();

    Args& Positional();
    bool GetFlagPositional();

    void MultiArgsCount(); 
    int GetMultiArgsCount();
    int GetMinArgsCount();

    void AddAllValues(const std::string value);
    int GetIndexedValue(const int ind);

    void Help(const char short_help, const std::string help);
    std::string GetHelp();
    char GetShortHelp();
    void FlagHelp();
    bool GetFlagHelp();

    void Description(const std::string description);


    bool flag_positional_ = false;

    bool flag_multi_value_ = false;
    int min_args_count_;
    int multi_args_count_ = 0;

    std::vector<int> all_values_;

    char short_help_;
    std::string help_;
    std::string description_;
    bool flag_help_ = false;

};

class Int : public Args {
    void StoreValues(std::vector<int>& store_values);
    void AddStoreValues(const std::string value);
    bool GetFlagStoreValues();

    std::vector<int>* store_values_;
    bool flag_store_values_ = false;
};

class String : public Args {
public:
    std::string GetParam();
    char GetShortParam();
    bool GetFlagShortParam();
    void PutValue(const std::string value);
    std::string GetValue();
    void Default(const char* value);
    std::string GetDefaultValue();

    void AddFlags(const char short_flag, const std::string flag);
    void AddFlag(const std::string flag);
    std::string GetFlag();
    bool GetIsFlag();
    char GetShortFlag();

    void StoreValue(std::string& value);
    void AddStoreValue(const std::string value);
    bool GetFlagStoreValue();
    
    std::string param_;
    char short_param_;
    bool flag_short_param_ = false;
    std::string value_;
    std::string* store_value_;
    std::string default_value_;

    std::string flag_;
    char short_flag_;
    bool is_flag_ = false;

    bool flag_store_value_ = false;
};

class Bool : public Args {
public:
    void Default(const bool flag);
    bool GetFlagDefaultFlag();
    void StoreValue(bool& flag);
    bool GetFlagStoreFlag();
    void AddStoreFlag(const bool flag);


    bool default_flag_;
    bool flag_default_flag_ = false;
    bool* store_flag_;
    bool flag_store_flag_ = false;
};

};#include "Arguments.h"
#include <string>
#include <vector>

namespace ArgumentParser {
    Args::Args() {}

    Args::Args(const std::string param) {
        static_cast<String*>(this)->param_ = param;
    }

    Args::Args(const char short_param, const std::string param) {
        static_cast<String*>(this)->param_ = param;
        static_cast<String*>(this)->short_param_ = short_param;
        static_cast<String*>(this)->flag_short_param_ = true;
    }
    
    std::string String::GetParam() {
        return param_;
    }

    std::string String::GetValue() {
        return value_;
    }







    char Args::GetShortParam() {
        return short_param_;
    }

    bool Args::GetFlagShortParam() {
        return flag_short_param_;
    }

    void Args::PutValue(const std::string value) {
        value_ = value;
    }

    void Args::Default(const char* value) {
        default_value_ = value;
    }

    void Args::Default(const bool flag) {
        default_flag_ = flag;
        flag_default_flag_ = true;
    }

    std::string Args::GetDefaultValue() {
        return default_value_;
    }

    bool Args::GetFlagDefaultFlag() {
        return flag_default_flag_;
    }

    void Args::StoreValue(std::string& value) {
        store_value_ = &value;
        flag_store_value_ = true;
    }

    void Args::StoreValues(std::vector<int>& store_values) {
        store_values_ = &store_values;
        flag_store_values_ = true;
    }

    void Args::StoreValue(bool& flag) {
        store_flag_ = &flag;
        flag_store_flag_ = true;
    }

    bool Args::GetFlagStoreValue() {
        return flag_store_value_;
    }

    void Args::AddStoreValue(const std::string value) {
        *store_value_ = value;
    }

    void Args::AddStoreValues(const std::string value) {
        (*store_values_).push_back(std::stoi(value));
    }

    bool Args::GetFlagStoreValues() {
        return flag_store_values_;
    }

    bool Args::GetFlagStoreFlag() {
        return flag_store_flag_;
    }

    void Args::AddStoreFlag(const bool flag) {
        *store_flag_ = flag;
    }

    Args& Args::MultiValue() {
        flag_multi_value_ = true;
        return *this;
    }

    Args& Args::MultiValue(const int min_args_count) {
        flag_multi_value_ = true;
        min_args_count_ = min_args_count;
        return *this;
    }

    bool Args::GetFlagMultiValue() {
        return flag_multi_value_;
    }

    void Args::MultiArgsCount() {
        ++multi_args_count_;
    }

    int Args::GetMultiArgsCount() {
        return multi_args_count_;
    }

    int Args::GetMinArgsCount() {
        return min_args_count_;
    }

    void Args::AddAllValues(const std::string value) {
        all_values_.push_back(std::stoi(value));
    }

    int Args::GetIndexedValue(const int ind) {
        return all_values_[ind];
    }

    void Args::AddFlags(const char short_flag, const std::string flag) {
        short_flag_ = short_flag;
        flag_ = flag;
        is_flag_ = true;
    }

    void Args::AddFlag(const std::string flag) {
        flag_ = flag;
        is_flag_ = true;
    }

    std::string Args::GetFlag() {
        return flag_;
    }

    bool Args::GetIsFlag() {
        return is_flag_;
    }

    char Args::GetShortFlag() {
        return short_flag_;
    }

    Args& Args::Positional() {
        flag_positional_ = true;
        return *this;
    }

    bool Args::GetFlagPositional() {
        return flag_positional_;
    }

    void Args::Help(const char short_help, const std::string help) {
        short_help_ = short_help;
        help_ = help;
    }

    std::string Args::GetHelp() {
        return help_;
    }

    char Args::GetShortHelp() {
        return short_help_;
    }

    void Args::FlagHelp() {
        flag_help_ = true;
    }

    bool Args::GetFlagHelp() {
        return flag_help_;
    }

    void Args::Description(const std::string description) {
        description_ = description;
    }

}get type in parsing and switch