/**
 * This file is part of the "clip" project
 *   Copyright (c) 2018 Paul Asmuth
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "exception.h"

namespace clip {

Exception::Exception() :
    type_name_(nullptr),
    file_(nullptr),
    line_(0),
    func_(nullptr) {
  *message_ = 0;
}

Exception::Exception(
    const char* message,
    ...) :
    type_name_(nullptr),
    file_(nullptr),
    line_(0),
    func_(nullptr) {
  va_list args;
  va_start(args, message);
  int pos = vsnprintf(message_, sizeof(message_), message, args);
  va_end(args);
}

Exception::Exception(
    const std::string& message) :
    type_name_(nullptr),
    file_(nullptr),
    line_(0),
    func_(nullptr) {
  strncpy(message_, message.c_str(), sizeof(message_));
}

Exception::Exception(
    const Exception& other) :
    type_name_(other.type_name_),
    file_(other.file_),
    line_(other.line_),
    func_(other.func_) {
  strncpy(message_, other.message_, sizeof(message_));
}

Exception Exception::setSource(
    const char* file,
    int line,
    const char* func) {
  file_ = file;
  line_ = line;
  func_ = func;
  return *this;
}

Exception Exception::setTypeName(const char* type_name) {
  type_name_ = type_name;
  return *this;
}

Exception Exception::setErrno(int posix_errno) {
  if (posix_errno > 0) {
    char buf[4096];
    char* errstr = buf;

#ifdef _GNU_SOURCE
    errstr = strerror_r(posix_errno, buf, sizeof(buf));
#else
    strerror_r(posix_errno, buf, sizeof(buf));
#endif

    size_t pos = strlen(message_);
    snprintf(message_ + pos, sizeof(message_) - pos, ": %s", errstr);
  }

  return *this;
}

void Exception::appendMessage(const char* message, ...) {
  va_list args;
  va_start(args, message);
  size_t pos = strlen(message_);
  vsnprintf(message_ + pos, sizeof(message_) - pos, message, args);
  va_end(args);
}

bool Exception::ofType(const char* type_name) {
  return strcmp(type_name_, type_name) == 0;
}

std::string Exception::getMessage() const {
  return std::string(message_);
}

std::string Exception::getTypeName() const {
  return std::string(type_name_);
}

std::string Exception::method() const {
  return std::string(func_);
}

std::string Exception::file() const {
  return std::string(file_);
}

int Exception::line() const {
  return line_;
}

} // namespace clip

