/*
 * This file is part of libsh4lt.
 *
 * libsh4lt is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "./any.hpp"

namespace sh4lt {

Any::Any(Any& that) noexcept : SafeBoolLog(that), ptr_(that.clone()) {}

Any::Any(Any&& that) noexcept : ptr_(that.ptr_) { that.ptr_ = nullptr; }

Any::Any(const Any& that) noexcept : SafeBoolLog(that), ptr_(that.clone()) {}

Any::Any(const Any&& that) noexcept : ptr_(that.clone()) {}

Any::Any(std::nullptr_t /*value*/) noexcept : SafeBoolLog() {}

Any::~Any() {
  if (ptr_)
    delete ptr_;
}

auto Any::operator=(const Any& a) -> Any& {
  if (ptr_ == a.ptr_)
    return *this;
  auto old_ptr = ptr_;
  ptr_ = a.clone();
  if (old_ptr)
    delete old_ptr;
  return *this;
}

auto Any::operator=(Any&& a) noexcept -> Any& {
  if (ptr_ == a.ptr_)
    return *this;
  std::swap(ptr_, a.ptr_);
  return *this;
}

auto operator<<(std::ostream& os, const Any& any) -> std::ostream& {
  if (any.ptr_)
    os << any.ptr_->to_string();
  else
    os << "null";
  return os;
}

auto Any::empty() const -> bool { return !ptr_; }

auto Any::get_category() const -> AnyCategory { return ptr_ ? ptr_->category_ : AnyCategory::NONE; }

auto Any::clone() const -> AnyValueBase *{
  if (ptr_)
    return ptr_->clone();
  else
    return nullptr;
}

auto Any::to_string(const Any& any) -> std::string {
  std::stringstream ss;
  ss << any;
  return ss.str();
}

auto Any::is_valid() const -> bool {
  return !(ptr_->category_ == AnyCategory::FLOATING_POINT &&
           ptr_->arithmetic_type_ == AnyArithmeticType::NOT_DEFINED) &&
         !(ptr_->category_ == AnyCategory::INTEGRAL &&
           ptr_->arithmetic_type_ == AnyArithmeticType::NOT_DEFINED);
}

}  // namespace sh4lt
