#ifndef STAN_MATH_PRIM_ERR_OUT_OF_RANGE_HPP
#define STAN_MATH_PRIM_ERR_OUT_OF_RANGE_HPP

#include <stan/math/prim/meta.hpp>
#include <typeinfo>
#include <sstream>
#include <stdexcept>

namespace stan {
namespace math {

/**
 * Throw an out_of_range exception with a consistently formatted message.
 * This is an abstraction for all Stan functions to use when throwing
 * out of range. This will allow us to change the behavior for all
 * functions at once.
 * The message is:
 * "<function>: index <index> out of range; expecting index to be between "
 * "1 and <max><msg1><msg2>"
 * @param function Name of the function
 * @param max Max
 * @param index Index
 * @param msg1 Message to print. Default is "".
 * @param msg2 Message to print. Default is "".
 * @throw std::out_of_range with message.
 */
inline void out_of_range(const char* function, int max, int index,
                         const char* msg1 = "", const char* msg2 = "") {
  std::ostringstream message;
  message << function << ": accessing element out of range. "
          << "index " << index << " out of range; ";

  if (max == 0) {
    message << "container is empty and cannot be indexed" << msg1 << msg2;
  } else {
    message << "expecting index to be between " << stan::error_index::value
            << " and " << stan::error_index::value - 1 + max << msg1 << msg2;
  }
  throw std::out_of_range(message.str());
}

}  // namespace math
}  // namespace stan
#endif
