#include "stdafx.h"
#include "Exception.h"
#include "Type.h"
#include "Core/Str.h"

namespace storm {

	Str *CodeError::messageText() const {
		StrBuf *buf = new (this) StrBuf();
		messageText(buf);
		return buf->toS();
	}

	CodeError::CodeError(SrcPos where) : pos(where) {}

	void CodeError::message(StrBuf *to) const {
		*to << S("@") << pos << S(": ");
		messageText(to);
	}

	LangDefError::LangDefError(const wchar *msg) {
		w = new (this) Str(msg);
	}

	LangDefError::LangDefError(Str *msg) : w(msg) {}

	void LangDefError::message(StrBuf *to) const {
		*to << w;
	}

	DebugError::DebugError() {
		saveTrace();
	}

	void DebugError::message(StrBuf *to) const {
		*to << S("Debug error");
	}

	InternalTypeError::InternalTypeError(const wchar *context, Type *expected, Type *got) :
		InternalError(TO_S(engine(), context << S(": expected ") << expected->identifier()
									<< S(", got ") << (got ? got->identifier() : new (engine()) Str(S("null"))))) {}

	InternalTypeError::InternalTypeError(Str *context, Type *expected, Type *got) :
		InternalError(TO_S(engine(), context << S(": expected ") << expected->identifier()
									<< S(", got ") << (got ? got->identifier() : new (engine()) Str(S("null"))))) {}


	LookupError::LookupError(Str *msg) : CodeError(SrcPos()), msg(msg) {}

	LookupError::LookupError(SrcPos pos, Str *msg) : CodeError(pos), msg(msg) {}

	void LookupError::messageText(StrBuf *to) const {
		*to << S("Name lookup error: ") << msg;
	}

	SyntaxError::SyntaxError(SrcPos where, const wchar *msg) :
		CodeError(where), text(new (engine()) Str(msg)) {}

	SyntaxError::SyntaxError(SrcPos where, Str *msg) :
		CodeError(where), text(msg) {}

	void SyntaxError::messageText(StrBuf *to) const {
		*to << S("Syntax error: ") << text;
	}

	TypeError::TypeError(SrcPos where, const wchar *msg) : CodeError(where), msg(new (engine()) Str(msg)) {}
	TypeError::TypeError(SrcPos where, Str *msg) : CodeError(where), msg(msg) {}
	TypeError::TypeError(SrcPos where, Value expected, ExprResult got)
		: CodeError(where),
		  msg(TO_S(engine(), S("Expected ") << expected << S(" but got ") << got)) {}
	TypeError::TypeError(SrcPos where, Value expected, Value got)
		: CodeError(where),
		  msg(TO_S(engine(), S("Expected ") << expected << S(" but got ") << got)) {}

	void TypeError::messageText(StrBuf *to) const {
		*to << S("Type error: ") << msg;
	}

	TypedefError::TypedefError(SrcPos pos, const wchar *msg) : CodeError(pos), msg(new (engine()) Str(msg)) {}
	TypedefError::TypedefError(SrcPos pos, Str *msg) : CodeError(pos), msg(msg) {}

	void TypedefError::messageText(StrBuf *to) const {
		*to << S("Type definition error: ") << msg;
	}

	BuiltInError::BuiltInError(const wchar *msg) {
		this->msg = new (this) Str(msg);
		saveTrace();
	}

	BuiltInError::BuiltInError(Str *msg) : msg(msg) {
		saveTrace();
	}

	void BuiltInError::message(StrBuf *to) const {
		*to << S("Error while loading built in functions: ") << msg;
	}

	InstantiationError::InstantiationError(SrcPos pos, const wchar *msg) : CodeError(pos), msg(new (engine()) Str(msg)) {}
	InstantiationError::InstantiationError(SrcPos pos, Str *msg) : CodeError(pos), msg(msg) {}

	void InstantiationError::messageText(StrBuf *to) const {
		*to << S("Instantiation error: ") << msg;
	}

	ReplaceError::ReplaceError(SrcPos pos, const wchar *msg) : CodeError(pos), msg(new (engine()) Str(msg)) {}
	ReplaceError::ReplaceError(SrcPos pos, Str *msg) : CodeError(pos), msg(msg) {}

	void ReplaceError::messageText(StrBuf *to) const {
		*to << S("Replace error: ") << msg;
	}

	ActiveReplaceError::ActiveReplaceError(CodeError *src, Named *entity)
		: ReplaceError(src->pos, S("")), original(src), entity(entity) {}

	void ActiveReplaceError::messageText(StrBuf *to) const {
		*to << S("Replacement error: failed to update invocations of ") << entity->identifier()
			<< S(" due to the error below. Fix the error and update again to replace the function.\n");
		original->messageText(to);
	}

}
