/**
* Copyright (C) 1997-2009 ECMWF
* 
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as 
* published by the Free Software Foundation.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License,
* see file gpl-3.0.txt. If not, see <http://www.gnu.org/licenses/>.
*/

#include <signal.h>

#ifndef MagExceptions_H
#include "MagExceptions.h"
#endif

#ifndef ThreadSingleton_H
#include "ThreadSingleton.h"
#endif

static MagException*& first()
{
	static ThreadSingleton<MagException*> p;
	return p.instance();
}

void xldb_throw(const char *c) // To set a break point in xldb
{
	if(getenv("PAUSE_MagExceptionS"))
	{
		cout << "debug me " << getpid() << endl;
		pause();
	}

	if(getenv("ABORT_MagExceptionS"))
		Panic(c);
}

MagException::MagException():
	next_(first())
{
	first() = this;
	xldb_throw("?");
}

MagException::~MagException() THROW_NOTHING()
{
	first() = next_;
}

void MagException::MagExceptionStack(ostream& out)
{
	out << "MagException stack: " << endl;
	MagException* e =  first();
	while(e)
	{
		out << e->what() << endl;
		e = e->next_;
	}
	out << "End stack" << endl;
}

MagException::MagException(const string& w):
	what_(w),
	next_(first())
{
	first() = this;
	xldb_throw(w.c_str());
}

void MagException::reason(const string& w)
{
	what_ = w;
}

bool MagException::throwing()
{
	return first() != 0;
}

TooManyRetries::TooManyRetries(const int retries) 
{
 cout << "Too many retries: " << retries << endl;
}

TimeOut::TimeOut(const unsigned long timeout)
{   
 cout << "Timeout expired: " << timeout << endl;
}


FailedSystemCall::FailedSystemCall(const string& w)
{   
 cout << "Failed system call: " << w << " " << endl;
}

FailedSystemCall::FailedSystemCall(const char* msg,int line, const char* file, const char* proc,int err)
{
 cout << "Failed system call: " << msg << " in " <<proc<< ", line " << line << " of " << file << endl;
}

AssertionFailed::AssertionFailed(const string& w): 
	MagException(string("Assertion failed: ") + w)
{   
} 

AssertionFailed::AssertionFailed(const char* msg,int line,
	const char* file, const char* proc)
{
 cout << "Assertion failed: " << msg << " in " <<proc<< ", line " << line << " of " << file << endl;
}

BadParameter::BadParameter(const string& w):
	MagException(string("Bad parameter: ") + w)
{   
}

NotImplemented::NotImplemented(int line,const char* file,const char* proc)
{
 cout << "Not implemented: " <<proc<< ", line " << line << " of " << file << endl;
}

UserError::UserError(const string& r):
	MagException(string("UserError: ") + r)
{   
}

UserError::UserError(const string& r,const string& x):
	MagException(string("UserError: ") + r + " : " + x)
{   
}

Stop::Stop(const string& r):
	MagException(string("Stop: ") + r)
{   
}

Abort::Abort(const string& r):
	MagException(string("Abort: ") + r)
{   
}

OutOfRange::OutOfRange(unsigned long long index, unsigned long long max)
{   
}

FileError::FileError(const string& msg)
{   
}

CantOpenFile::CantOpenFile(const string& file, bool retry):
	retry_(retry)
{   
}

WriteError::WriteError(const string& file): 
	FileError(string("Write error on ") + file)
{   
}

ReadError::ReadError(const string& file): 
	FileError(string("Read error on ") + file)
{   
}

ShortFile::ShortFile(const string& file): 
	ReadError(string("Short file while reading ") + file)
{   
}

Ostore::Ostore(const string& msg):
	MagException(string("ObjectStore: ") + msg)
{
}

void Panic(const char *msg)
{
	msg = msg ? msg : "(null message)";

	if(getenv("SLEEP_ON_PANIC"))
	{
		::kill(::getpid(),SIGSTOP);
	}
	else ::kill(::getpid(),SIGABRT);
	::pause();
}

void Panic(const char* msg,int line,const char* file, const char* proc)
{
}

OutOfMemory::OutOfMemory():
	MagException("out of memory")
{
}
