// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2020-2022 Xilinx, Inc
// Copyright (C) 2022-2023 Advanced Micro Devices, Inc. All rights reserved.

#ifndef __OptionOptions_h_
#define __OptionOptions_h_

// Please keep eternal include file dependencies to a minimum
#include <vector>
#include <string>
#include <boost/format.hpp>
#include <boost/program_options.hpp>

#include "JSONConfigurable.h"
  
class OptionOptions : public JSONConfigurable {
 public:
  typedef std::vector<std::string> SubCmdOptions;

  virtual void execute(const SubCmdOptions &_options) const = 0;

 public:
  const boost::shared_ptr<boost::program_options::option_description>&
  option() const
  {
    if (m_selfOption.options().empty())
      throw std::runtime_error(boost::str(boost::format("%s missing self option") % longName()));
    return m_selfOption.options()[0];
  };
  const std::string &longName() const { return m_longName; };
  const std::string &getConfigName() const { return longName(); };
  const std::string optionNameString() const { return m_shortName.empty() ? m_longName : m_longName + "," + m_shortName; };
  const std::string &description() const {return m_description; };
  const std::string &getConfigDescription() const { return description(); };
  const std::string &extendedHelp() const { return m_extendedHelp; };
  bool isHidden() const { return m_isHidden; };
  bool getConfigHidden() const {return isHidden();};

  void setExecutable( const std::string &_executable) {m_executable = _executable; };
  void setCommand( const std::string & _command) {m_command = _command; };

  const boost::program_options::options_description & 
    getOptionsDescription() const { return m_optionsDescription; } ;
  const boost::program_options::positional_options_description & 
    getPositionalOptions() const { return m_positionalOptions; } ;

  void setGlobalOptions(const boost::program_options::options_description &globalOptions) { m_globalOptions.add(globalOptions); };

 public:
  virtual ~OptionOptions() {};

 // Child class Helper methods
 protected:
  OptionOptions(const std::string & longName, bool isHidden, const std::string & description);
  OptionOptions(const std::string& longName, const std::string& shortName, const std::string& optionDescription, const boost::program_options::value_semantic* optionValue, const std::string& valueDescription, bool isHidden);
  void setExtendedHelp(const std::string &extendedHelp) { m_extendedHelp = extendedHelp; };
  void printHelp() const;
  std::vector<std::string> process_arguments( boost::program_options::variables_map& vm,
                                              const SubCmdOptions& options,
                                              bool validate_arguments = true) const;

 private:
  OptionOptions() = delete;

 // Variables
 protected:
  boost::program_options::options_description m_selfOption;
  boost::program_options::options_description m_optionsDescription;
  boost::program_options::options_description m_optionsHidden;
  boost::program_options::positional_options_description m_positionalOptions;

 private:
  std::string m_executable;
  std::string m_command;
  std::string m_longName;
  std::string m_shortName;
  bool m_isHidden;
  std::string m_description;
  std::string m_extendedHelp;
  bool m_defaultOptionValue;
  boost::program_options::options_description m_globalOptions;
};
  
#endif

