// SaxonApiException.cpp : Defines the exported functions for the DLL
// application.
//

#include "saxonc/SaxonApiException.h"

#ifdef MEM_DEBUG
#define new new (__FILE__, __LINE__)
#endif

#ifdef _LIBCPP___EXCEPTION_EXCEPTION_H
char const* SaxonApiException::what() const _NOEXCEPT
{
  // need cast to remove const flag
  SaxonApiException *s = const_cast<SaxonApiException*>(this);
  return s->getMessageWithErrorCode();
}
#else

const char *SaxonApiException::what() {
  return this->getMessageWithErrorCode();
}
#endif


SaxonApiException::SaxonApiException(bool staticError) {
  message = "";
  lineNumber = -1;
  errorCode = "";
  systemId = "";
  cppException = false;
  isStaticError = staticError;
  
  // preload the error message
  getMessageWithErrorCode();
}

SaxonApiException::SaxonApiException(const SaxonApiException &ex) {
  message = ex.message;
  lineNumber = ex.lineNumber;
  errorCode = ex.errorCode;
  systemId = ex.systemId;
  cppException = ex.cppException;
  isStaticError = ex.isStaticError;
}

SaxonApiException::SaxonApiException(const char *m) {
  if (m != nullptr) {
    message = std::string(m);
  } else {
    message = "unknown exception";
  }

  lineNumber = -1;
  errorCode = "";
  systemId = "";
  cppException = true;
  isStaticError = false;
}

SaxonApiException::SaxonApiException(const char *m, const char *ec,
                                     const char *sysId, int linenumber) {
  if (m != nullptr) {
    message = std::string(m);
  } else {
    message = "";
  }

  lineNumber = linenumber;

  if (ec != nullptr) {
    errorCode = std::string(ec);
  } else {
    errorCode = "";
  }

  if (sysId != nullptr) {
    systemId = std::string(sysId);
  } else {
    systemId = "";
  }
  cppException = true;
  isStaticError = false;
}

SaxonApiException::~SaxonApiException() throw() {
  if (!message.empty()) {
    message.clear();
  }
  if (!s_message.empty()) {
    s_message.clear();
  }
  if (!ec_message.empty()) {
    ec_message.clear();
  }
  if (!errorCode.empty()) {
    errorCode.clear();
  }
  if (!systemId.empty()) {
    systemId.clear();
  }
  if (!cppException) {
    graal_isolatethread_t *thread = SaxonProcessor::getOrAttachCurrentThread(SaxonProcessor::sxn_environ);
    j_clearException(thread);
  }
}

const char *SaxonApiException::getErrorCode() {
  if (errorCode.empty() && !cppException) {
    allocFn fn = operator new;
    char *tempm = nullptr;
    graal_isolatethread_t *thread = SaxonProcessor::getOrAttachCurrentThread(SaxonProcessor::sxn_environ);
    tempm = j_getErrorCode(thread, (void *)fn);
    if (tempm == nullptr) {
      return nullptr;
    }
    errorCode = std::string(tempm);
    //operator delete(tempm);
  }
  return errorCode.c_str();
}

int SaxonApiException::getLineNumber() {
  if (lineNumber == -1 && !cppException) {
    graal_isolatethread_t *thread = SaxonProcessor::getOrAttachCurrentThread(SaxonProcessor::sxn_environ);
    lineNumber = j_getLineNumber(thread);
  }
  return lineNumber;
}

const char *SaxonApiException::getSystemId() {
  if (systemId.empty() && !cppException) {
    allocFn fn = operator new;
    char *tempm = nullptr;
    tempm = j_getSystemId(SaxonProcessor::sxn_environ->thread, (void *)fn);
    if (tempm == nullptr) {
      return nullptr;
    }
    systemId = std::string(tempm);
    //operator delete(tempm);
  }
  return systemId.c_str();
}

const char *SaxonApiException::getMessage() {
  if (message.empty() && !cppException) {
    allocFn fn = operator new;
    char *tempm = nullptr;
    graal_isolatethread_t *thread = SaxonProcessor::getOrAttachCurrentThread(SaxonProcessor::sxn_environ);
    if (isStaticError) {
      tempm = j_getCombinedStaticErrorMessages(thread, (void *)fn);
    } else {
      tempm =
          j_getErrorMessage(thread, (void *)fn);
    }
    if (tempm == nullptr) {
      return nullptr;
    }
    message = std::string(tempm);
    //operator delete(tempm);
  }

  return message.c_str();
}

const char *SaxonApiException::getMessageWithErrorCode() {

  if(cppException) {
    return getMessage();
  } else if (ec_message.empty()) {
    allocFn fn = operator new;
    char *tempm = nullptr;
    graal_isolatethread_t *thread = SaxonProcessor::getOrAttachCurrentThread(SaxonProcessor::sxn_environ);
    if (isStaticError) {
      tempm = j_getCombinedStaticErrorMessages(thread, (void *)fn);
    } else {
      tempm = j_getErrorMessageWithErrorCode(thread, (void *)fn);
    }
    if (tempm == nullptr) {
      return nullptr;
    }
    ec_message = std::string(tempm);
    //operator delete(tempm);
  }
  return ec_message.c_str();
}

const char *SaxonApiException::getCombinedStaticErrorMessages() {
  if (s_message.empty() && !cppException) {
    allocFn fn = operator new;
    char *tempm = nullptr;
    graal_isolatethread_t *thread = SaxonProcessor::getOrAttachCurrentThread(SaxonProcessor::sxn_environ);
    tempm = j_getCombinedStaticErrorMessages(thread, (void *)fn);
    if (tempm == nullptr) {
      return nullptr;
    }
    s_message = std::string(tempm);
    //operator delete(tempm);
  }
  return s_message.c_str();
}

int SaxonApiException::staticErrorCount() {
  graal_isolatethread_t *thread = SaxonProcessor::getOrAttachCurrentThread(SaxonProcessor::sxn_environ);
  return j_staticErrorCount(thread);
}
