#ifndef STAN_MATH_PRIM_SCAL_ERR_INVALID_ARGUMENT_HPP
#define STAN_MATH_PRIM_SCAL_ERR_INVALID_ARGUMENT_HPP

#include <typeinfo>
#include <string>
#include <sstream>
#include <stdexcept>

namespace stan {
  namespace math {

    /**
     * Throw an invalid_argument exception with a consistently formatted message.
     *
     * This is an abstraction for all Stan functions to use when throwing
     * invalid argument. This will allow us to change the behavior for all
     * functions at once.
     *
     * The message is:
     * "<function>: <name> <msg1><y><msg2>"
     *
     * @tparam T Type of variable
     * @param function Name of the function
     * @param name Name of the variable
     * @param y Variable
     * @param msg1 Message to print before the variable
     * @param msg2 Message to print after the variable
     * @throw std::invalid_argument
     */
    template <typename T>
    inline void invalid_argument(const std::string& function,
                                 const std::string& name,
                                 const T& y,
                                 const std::string& msg1,
                                 const std::string& msg2) {
      std::ostringstream message;

      message << function << ": "
              << name << " "
              << msg1
              << y
              << msg2;

      throw std::invalid_argument(message.str());
    }

    /**
     * Throw an invalid_argument exception with a consistently formatted message.
     *
     * This is an abstraction for all Stan functions to use when throwing
     * invalid argument. This will allow us to change the behavior for all
     * functions at once. (We've already changed behavior mulitple times up
     * to Stan v2.5.0.)
     *
     * The message is:
     * "<function>: <name> <msg1><y>"
     *
     * @tparam T Type of variable
     * @param function Name of the function
     * @param name Name of the variable
     * @param y Variable
     * @param msg1 Message to print before the variable
     * @throw std::invalid_argument
     */
    template <typename T>
    inline void invalid_argument(const std::string& function,
                                 const std::string& name,
                                 const T& y,
                                 const std::string& msg1) {
      invalid_argument(function, name, y, msg1, "");
    }

  }
}
#endif
