/*******************************TRICK HEADER******************************
PURPOSE: ( Implementation of a simple python executable code instruction)

LIMITATION: (This implementation is intended to provide a fixed operation
             that generates one variable as a function of one or more
             variables -- such as random variables -- that were previously
             generated by the MonteCarlo process.
             E.g. y = x + 2
             It does not provide randomization of the operation itself; in
             this example the value y will always be generated as x+2, using
             the value x which may be variable.  However, it will never be
             generated as x+3.
             To implement randomization of the operation itself, use the
             MonteCarloVariableRandomStringSet class instead.)

PROGRAMMERS:
  (((Gary Turner) (OSR) (October 2019) (Antares) (Initial)))
  (((Isaac Reaves) (NASA) (November 2022) (Integration into Trick Core)))
**********************************************************************/
#ifndef CML_MONTE_CARLO_PYTHON_CODE_HH
#define CML_MONTE_CARLO_PYTHON_CODE_HH

#include "mc_variable.hh"

class MonteCarloPythonLineExec : public MonteCarloVariable
{
 public:
  std::string instruction_set; /* (--)
      The right-hand-side of an equation that gets inserted into the
      monte-input file and looks like:
      <variable_name> = <instruction-set>*/
 protected:
  bool instruction_is_command; /* (--)
      Indicates whether to implement a command that looks like:
      - variable=instruction vs
      variable representing the standalone command, in which case
      variable_name and instruction_set are identical. */

 public:
 // 2 constructors:
  MonteCarloPythonLineExec(const std::string & var_name,
                           const std::string & instruction)
    :
    MonteCarloVariable( var_name),
    instruction_set(instruction),
    instruction_is_command(false)
  {
    include_in_summary = false;
    type = MonteCarloVariable::Calculated;
  }
  // other constructor
  MonteCarloPythonLineExec( const std::string & instruction)
    :
    MonteCarloVariable( instruction),
    instruction_set(instruction),
    instruction_is_command(true)
  {
    include_in_summary = false;
    type = MonteCarloVariable::Execute;
  }
  virtual ~MonteCarloPythonLineExec(){};

  void generate_assignment()
  {
    if (instruction_is_command) {
      command = "\n" + instruction_set;
    }
    else {
      command = "\n" + variable_name + " = " + instruction_set;
    }
  }
 private: // and undefined:
  MonteCarloPythonLineExec( const MonteCarloPythonLineExec & );
  MonteCarloPythonLineExec& operator = (const MonteCarloPythonLineExec&);
};


/*****************************************************************************
MonteCarloPythonFileExec
Purpose:(Provides a filename for execution to support more extensive
         calculations than are possible with the simple one-liner commands
         provided by MonteCarloPythonLineExec)
Assumptions: The file identified by filename is expected to be a Python file
Limitations: The file is not tested prior to execution
Other notes:
   This class inherits from MonteCarloVariable to simplify the inclusion of
     its "command" into the monte_input files.  However, it does not populate
     a specific variable; its command string is an executive statement, unlike
     other MonteCarloVariable instances, which have a command string that
     looks like "variable = ..."
   This class's "variable_name" is instead re-purposed as a filename
*****************************************************************************/
class MonteCarloPythonFileExec : public MonteCarloVariable
{
 public:
  MonteCarloPythonFileExec(const std::string & filename)
    :
    MonteCarloVariable( filename)
  {
    include_in_summary = false;
    type = MonteCarloVariable::Execute;
  }
  virtual ~MonteCarloPythonFileExec(){};

  void generate_assignment()
  {
    command =
    "\nexec(open('" + variable_name + "').read())";
  }
 private: // and undefined:
  MonteCarloPythonFileExec( const MonteCarloPythonFileExec & );
  MonteCarloPythonFileExec& operator = (const MonteCarloPythonFileExec&);
};

#endif
