/*
   HARK Library
   Copyright (C) 2021 Honda Research Institute Japan Inc.
 */

#include "hark-lib/data.h"

#if !defined(HARKLIB_PLATFORM_TYPE_WINDOWS)
#include <cxxabi.h>
#endif

namespace hark
{
    template<>
    data::data(data&& src) : _value(src._value)
    {
    }

    template<>
    data::data(data& src) : _value(src._value)
    {
    }

    template<>
    data::data(const data& src) : _value(src._value)
    {
    }

    data::data():
         _value(nullptr)
     {
         // std::cout << "data::ctor(): this=" << (void *)this << ", value.ref=" << this->_value.use_count() << ", value.ptr=" << (void *)this->_value.get() << std::endl;
     }

     data::data(const data &src):
         _value(src._value)
     {
         // std::cout << "data::ctor(): copy: this=" << (void *)this << ", src=" << (void *)&src << ", value.ref=" << this->_value.use_count() << ", value.ptr=" << (void *)this->_value.get() << ", src.ref=" << src._value.use_count() << ", src.ptr=" << (void *)src._value.get() << std::endl;
     }

     data::data(data &src):
         _value(src._value)
     {
         // std::cout << "data::ctor(): copy: this=" << (void *)this << ", src=" << (void *)&src << ", value.ref=" << this->_value.use_count() << ", value.ptr=" << (void *)this->_value.get() << ", src.ref=" << src._value.use_count() << ", src.ptr=" << (void *)src._value.get() << std::endl;
         // std::cout << "  type: this->T: " << data_typename(typeid(*this->_value.get())) << ", src.T: " << data_typename(typeid(*src._value.get())) << std::endl;
     }

     data::data(data &&src):
         _value(std::move(src._value))
     {
         // std::cout << "data::ctor(): move: this=" << (void *)this << ", src=" << (void *)&src << ", value.ref=" << this->_value.use_count() << ", value.ptr=" << (void *)this->_value.get() << ", src.ref=" << src._value.use_count() << ", src.ptr=" << (void *)src._value.get() << std::endl;
     }

     data &
     data::operator = (const data &src)
     {
         // std::cout << "data::operator(): copy: before: this=" << (void *)this << ", src=" << (void *)&src << ", value.ref=" << this->_value.use_count() << ", value.ptr=" << (void *)this->_value.get() << ", src.ref=" << src._value.use_count() << ", src.ptr=" << (void *)src._value.get() << std::endl;
         if(this != &src){
             this->_value = src._value;
         }
         // std::cout << "data::operator(): copy: after: this=" << (void *)this << ", src=" << (void *)&src << ", value.ref=" << this->_value.use_count() << ", value.ptr=" << (void *)this->_value.get() << ", src.ref=" << src._value.use_count() << ", src.ptr=" << (void *)src._value.get() << std::endl;
         return *this;
     }

     data &
     data::operator = (data &&src)
     {
         // std::cout << "data::operator(): move: before: this=" << (void *)this << ", src=" << (void *)&src << ", value.ref=" << this->_value.use_count() << ", value.ptr=" << (void *)this->_value.get() << ", src.ref=" << src._value.use_count() << ", src.ptr=" << (void *)src._value.get() << std::endl;
         if(this != &src){
             this->_value = std::move(src._value);
         }
         // std::cout << "data::operator(): move: after: this=" << (void *)this << ", src=" << (void *)&src << ", value.ref=" << this->_value.use_count() << ", value.ptr=" << (void *)this->_value.get() << ", src.ref=" << src._value.use_count() << ", src.ptr=" << (void *)src._value.get() << std::endl;
         return *this;
     }

     data::~data()
     {
         // std::cout << "data::dtor(): before: this=" << (void *)this << ", has_value=" << (bool)this->_value << ", value.ref=" << this->_value.use_count() << ", value.ptr=" << (void *)this->_value.get() << std::endl;
         this->_value.reset();
         // std::cout << "data::dtor(): after: this=" << (void *)this << ", has_value=" << (bool)this->_value << ", value.ref=" << this->_value.use_count() << ", value.ptr=" << (void *)this->_value.get() << std::endl;
     }

    bool
    data::is_empty() const
    {
        if(this->_value){
            return false;
        }
        return true;
    }

    std::ostream &
    operator << (std::ostream &os, const data &value)
    {
        if(value._value){
            return value._value->dump(os);
        }else{
            os << "(empty)";
            return os;
        }
    }

    std::string
    data_typename(const std::type_info &ti)
    {
#if !defined(HARKLIB_PLATFORM_TYPE_WINDOWS)
        int status;
        char *s = abi::__cxa_demangle(ti.name(), 0, 0, &status);
        std::string n(s);
        free(s);
        return n;
#else
        return ti.name();
#endif
    }

    void
    data::clear()
    {
        this->_value.reset();
    }

}

/* end of file */
