// Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// 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 <cstring>

#include "common.h"
#include "sentencepiece_processor.h"

namespace sentencepiece {
namespace util {

Status::Status() {}
Status::~Status() {}

struct Status::Rep {
  StatusCode code;
  std::string error_message;
};

Status::Status(StatusCode code, absl::string_view error_message)
    : rep_(new Rep) {
  rep_->code = code;
  rep_->error_message = std::string(error_message);
}

Status::Status(const Status& s)
    : rep_((s.rep_ == nullptr) ? nullptr : new Rep(*s.rep_)) {}

void Status::operator=(const Status& s) {
  if (rep_ != s.rep_)
    rep_.reset((s.rep_ == nullptr) ? nullptr : new Rep(*s.rep_));
}

bool Status::operator==(const Status& s) const { return (rep_ == s.rep_); }

bool Status::operator!=(const Status& s) const { return (rep_ != s.rep_); }

const char* Status::error_message() const {
  return ok() ? "" : rep_->error_message.c_str();
}

void Status::set_error_message(const char* str) {
  if (rep_ == nullptr) rep_.reset(new Rep);
  rep_->error_message = str;
}

StatusCode Status::code() const { return ok() ? StatusCode::kOk : rep_->code; }

std::string Status::ToString() const {
  if (rep_ == nullptr) return "OK";

  std::string result;
  switch (code()) {
    case StatusCode::kCancelled:
      result = "Cancelled";
      break;
    case StatusCode::kUnknown:
      result = "Unknown";
      break;
    case StatusCode::kInvalidArgument:
      result = "Invalid argument";
      break;
    case StatusCode::kDeadlineExceeded:
      result = "Deadline exceeded";
      break;
    case StatusCode::kNotFound:
      result = "Not found";
      break;
    case StatusCode::kAlreadyExists:
      result = "Already exists";
      break;
    case StatusCode::kPermissionDenied:
      result = "Permission denied";
      break;
    case StatusCode::kResourceExhausted:
      result = "Unauthenticated";
      break;
    case StatusCode::kFailedPrecondition:
      result = "Failed precondition";
      break;
    case StatusCode::kAborted:
      result = "Aborted";
      break;
    case StatusCode::kOutOfRange:
      result = "Out of range";
      break;
    case StatusCode::kUnimplemented:
      result = "Unimplemented";
      break;
    case StatusCode::kInternal:
      result = "Internal";
      break;
    case StatusCode::kUnavailable:
      result = "Unavailable";
      break;
    case StatusCode::kDataLoss:
      result = "Data loss";
      break;
    case StatusCode::kUnauthenticated:
      result = "Unauthenticated";
    default:
      break;
  }

  result += ": ";
  result += rep_->error_message;
  return result;
}

void Status::IgnoreError() {}

}  // namespace util
}  // namespace sentencepiece
