#ifndef errH
#define errH
#include <stdexcept>
#include <string>
#include <cerrno>
namespace hub {
// -----------------------------------------------------------
//	null classes as default components for the template below
//	a component must:have
//	- a copy constructor which stores whatever info is needed
//	- if it has default ctor, then in should also take a dummy int parameter
//	- std::string tell (void) const which returns an explanation
// -----------------------------------------------------------
class ExNullPosition {
public:
    ExNullPosition (void) {}
    ExNullPosition (int) {}
    ExNullPosition (const ExNullPosition& e) {}
    std::string tell (void) const { return ""; } 
};

class ExNullContext {
public:
    ExNullContext (void) {}
    ExNullContext (int) {}
    ExNullContext (const ExNullPosition& e) {}
    std::string tell (void) const { return ""; } 
};

// ===========================================================
//	exception system
// ===========================================================
template <
class SysCategory, 			// std::runtime_error, etc.
class Reason,				// syntax error, I/O error, inconsistency ...
class Position = ExNullPosition,	// file name, line number
class Context = ExNullContext		// block/wire name etc.

> class CException :  
public Reason,
public SysCategory {			// must be last - initialization
    static ExNullPosition nopos_;
    static ExNullContext noctx_;
public:
    CException (const Reason, const Position = nopos_, const Context = noctx_);
    CException (const Position = nopos_, const Context = noctx_);
    ~CException () throw () {}
};

// ===========================================================
//	components
// ===========================================================
class FilePosition {
    std::string name_;		// existing or tried name of the file
    int lineno_;			// line number where applicable
    static const int none_;		// lineno_ == none_ means no number available
public:
    FilePosition (const std :: string&, int = none_);
    FilePosition (const FilePosition&);
    std::string tell (void) const; 
};
// -----------------------------------------------------------
class IOReason {
    int err_;
public:
    IOReason (void);
    IOReason (int);
    IOReason (const IOReason&);
    std::string tell (void) const;
    int err (void) { return err_; }
};
// -----------------------------------------------------------
typedef CException <std::runtime_error, IOReason, FilePosition> IOException;
// -----------------------------------------------------------
class InconsReason {
    std::string reason_;
public:
    InconsReason (int =0) {}
    InconsReason (const std::string rsn):    reason_ (rsn) {}
    InconsReason (const char* rsn):          reason_ (rsn) {}
    InconsReason (const InconsReason& rsn):  reason_ (rsn.reason_) {}
    std::string tell (void) const { return reason_; }
    bool okay (void) { return reason_.empty(); }
};
// -----------------------------------------------------------
class ERCReason: public InconsReason {

public:
    ERCReason (const std::string rsn): InconsReason(rsn) {};
    ERCReason (const char* rsn): InconsReason(rsn) {};
    ERCReason (const ERCReason& rsn): InconsReason(rsn) {};
};
// ===========================================================
class ToolPosition {
    std::string text_;
public:
    ToolPosition (const std :: string&);
    ToolPosition (const ToolPosition&);
    std::string tell (void) const; 
};
// -----------------------------------------------------------
typedef CException <std::runtime_error, InconsReason, ToolPosition> UnspecException;

#include "err.tcc"
}
#endif
