#pragma once

#include <exception>
#include <sstream>
#include <string>

namespace virtdb { namespace proto {

  class exception : public std::exception
  {
    // must pass minimal location information as below
    exception() = delete;

  protected:
    std::string data_;
  
  public:
    exception(
      const char * file,
      unsigned int line,
      const char * func,
      const char * msg)
    {
      std::ostringstream os;
      os << '[' << file << ':' << line << "] " << func << "() ";
      if( msg ) os << "msg=" << msg << " ";
      data_ = os.str();
    }

    exception(
              const char * file,
              unsigned int line,
              const char * func,
              const std::string & msg)
    {
      std::ostringstream os;
      os << '[' << file << ':' << line << "] " << func << "() ";
      if( !msg.empty() ) os << "msg=" << msg << " ";
      data_ = os.str();
    }

    virtual ~exception() {}

    const char* what() const noexcept(true)
    {
      return data_.c_str();
    }
  };

}}

#ifndef EXCEPTION_PROTO_
#define EXCEPTION_PROTO_(MSG) virtdb::proto::exception(__FILE__,__LINE__,__func__,MSG)
#endif // EXCEPTION_PROTO_

#ifndef THROW_PROTO_
#define THROW_PROTO_(MSG) throw EXCEPTION_PROTO_(MSG);
#endif // THROW_PROTO_

