/*
 * HA_Object.h
 *
 */

#ifndef HA_OBJECT_H_
#define HA_OBJECT_H_

#include <pthread.h>
#include "HA_config.h"

#if defined(__MACH__) && defined(__APPLE__)
#include <mach/clock.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#else
#include <sys/time.h>
#endif

#ifdef __cplusplus

namespace HARKAndroid {

class HAObject {

protected:

public:

    void gettime(timespec *res) const {
#if defined(__MACH__) && defined(__APPLE__)
        // OSX/iOSではclock_gettimeが実装されていないので代わり
        clock_serv_t cclock;
        mach_timespec_t mts;
        
        ::host_get_clock_service(::mach_host_self(), CALENDAR_CLOCK, &cclock);
        ::clock_get_time(cclock, &mts);
        ::mach_port_deallocate(::mach_task_self(), cclock);

        res->tv_sec = mts.tv_sec;
        res->tv_nsec = mts.tv_nsec;
#else
        ::clock_gettime(CLOCK_REALTIME, res);
#endif
    }

    double current_ms() const {
#if defined(__MACH__) && defined(__APPLE__)
        // OSX/iOSではclock_gettimeが実装されていないので代わり
        mach_timebase_info_data_t timebase;
        ::mach_timebase_info(&timebase);
        const uint64_t time = ::mach_absolute_time();
        const double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom);
        //const double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9);

        //return((seconds * 1000.0) + (nseconds / 1000000));
        return (nseconds / 1000000.0);
#else
        struct timespec res;
        ::clock_gettime(CLOCK_MONOTONIC, &res);
        return(1000.0 * res.tv_sec + static_cast<double>(res.tv_nsec) / 1000000);
#endif
    }
    

};

class lockobject : public HAObject {
private:
    pthread_mutex_t *mutex;

public:
    lockobject(const lockobject &);
    lockobject();
    lockobject(::pthread_mutex_t *arg_mutex) : mutex(arg_mutex) {
        ::pthread_mutex_lock(mutex);
    }
    lockobject & operator = (const lockobject &);
    virtual ~lockobject() {
        ::pthread_mutex_unlock(mutex);
    }

};

template <class T>
class autofree_2dptr : public HAObject {
private:
    T **ptr;
public:
    autofree_2dptr(const autofree_2dptr &);
    autofree_2dptr();
    autofree_2dptr(T **ap) : ptr(ap) {}
    autofree_2dptr& operator = (const autofree_2dptr&);
    ~autofree_2dptr() {
        free(ptr[0]);
        free(ptr);
    }
};

template <class T>
class autofree_ptr : public HAObject {
private:
    T *ptr;
public:
    autofree_ptr(const autofree_ptr &);
    autofree_ptr();
    autofree_ptr(T *ap) : ptr(ap) {}
    autofree_ptr& operator = (const autofree_ptr&);
    ~autofree_ptr() {
        free(ptr);
    }
};

} // end of namespace

#endif // __cplusplus

#endif /* HA_OBJECT_H_ */
