#include <memory>
#include <iostream>
#include <dynamical_systems/base/DynamicsBase.hpp>
#include <dynamical_systems/base/DerivativesNumDiffBase.hpp>
#include <dynamical_systems/systems/acrobot/acrobotDimensions.hpp>
#include <dynamical_systems/systems/acrobot/acrobot_dynamics.hpp>
#include <dynamical_systems/systems/acrobot/acrobot_derivatives.hpp>
typedef acrobot::acrobotDimensions::state_vector_t state_vector_t;
typedef acrobot::acrobotDimensions::state_vector_array_t state_vector_array_t;
typedef acrobot::acrobotDimensions::control_vector_t control_vector_t;
typedef acrobot::acrobotDimensions::control_vector_array_t control_vector_array_t;
using namespace DirectTrajectoryOptimization;
int main(int argc, const char* argv[]) {
    std::shared_ptr<DynamicsBase<acrobot::acrobotDimensions> > dynamics(new acrobotDynamics);
    std::shared_ptr<DerivativesNumDiffBase<acrobot::acrobotDimensions> > derivatives(new acrobotNumDiffDerivatives(dynamics));
    
    if(argc < 2) {
        std::cout << "Add parameters to command line: Method(0/1)" << std::endl;
        std::cout << "Method: 0-Direct Transcription / 1-Multiple Shooting" << std::endl;
        exit(0);
    }
    Eigen::Vector2d duration;
    duration << 2,10;
    int number_of_nodes = 40;
    std::string argv1 = argv[1];
    if (argv1 == "0") {
    } else {
    }
    bool method_verbose = false;
    bool solver_verbose = false;
    std::unique_ptr<DirectTrajectoryOptimizationProblem<acrobot::acrobotDimensions> > my_snoptdt =
                    dynamics,
                    derivatives,
                    costFunction,
                    constraints,
                    duration,
                    number_of_nodes,
                    chosen,
                    solver_verbose,
                    method_verbose);
    
    state_vector_t initial_state = state_vector_t::Zero();
    state_vector_t final_state;
    final_state << 3.1415926, 0, 0, 0;
    my_snoptdt->SetInitialState(initial_state);
    my_snoptdt->SetFinalState(final_state);
    my_snoptdt->SetEvenTimeIncrements(false);
    my_snoptdt->SetControlBounds(control_vector_t::Constant(-10), control_vector_t::Constant(10));
    my_snoptdt->SetStateBounds(state_vector_t::Constant(-10), state_vector_t::Constant(10));
    
    bool solver_numerical_differentiation = false;
    int integration_method = 1; 
    int snopt_derivatives_verification = 3;
    bool use_solver_print_file = false;
    my_snoptdt->SetDircolMethod(integration_method);
    my_snoptdt->_solver->SetVerifyLevel(snopt_derivatives_verification);
    my_snoptdt->_solver->UsePrintFile(use_solver_print_file);
    my_snoptdt->InitializeSolver("acrobot", "filename", "",solver_numerical_differentiation);
    
    my_snoptdt->Solve();
    
    state_vector_array_t    y_trajectory;
    control_vector_array_t  u_trajectory;
    Eigen::VectorXd         h_trajectory;
    my_snoptdt->GetDTOSolution(y_trajectory, u_trajectory, h_trajectory);
    
    std::cout << std::endl;
    std::cout << "final state: ";
    std::cout << y_trajectory.back().transpose();
    std::cout << std::endl;
    std::cout << "final_control: ";
    std::cout << u_trajectory.back().transpose();
    std::cout << std::endl;
    std::cout << std::endl << "... end of Test."  << std::endl;
}