//  BlockyFroggy
//  Copyright © 2017 John Ryland.
//  All rights reserved.
#pragma once
#ifndef COMMON_H
#define COMMON_H


#include "Log.h"
#include <functional>
#include <vector>
#include <mutex>

#include "Context.h"


class Dispatchable
{
public:
  virtual void dispatch() const = 0;
};


class Finalizable
{
public:
  // Calls all the cleanup functions
  virtual ~Finalizable();

  // Finalizers
  typedef std::function<void()> CleanupFunction;
  void addCleanupCallback(const CleanupFunction& a_callback);

private:
  std::vector<CleanupFunction> m_cleanupFunctions;
};


// Need to use inheritance from unique_lock to make it compatible with using with condition_variables
class ScopeLock : public std::unique_lock<std::mutex>
{
public:
  ScopeLock(std::mutex& a_mutex) : std::unique_lock<std::mutex>(a_mutex) {}
  template <typename F>
  void unlocked(F&& a_func)
  {
    unlock();
    a_func();
    lock();
  }
};


class AutoLock : public Finalizable
{
public:
  AutoLock(std::mutex& a_mutex) { a_mutex.lock(); addCleanupCallback([&](){a_mutex.unlock();}); }
};


// Alternative implementation
class AutoLockClassic
{
public:
  AutoLockClassic(std::mutex& a_mutex) : m_mutex(a_mutex) { m_mutex.lock(); }
  ~AutoLockClassic() { m_mutex.unlock(); }
  std::mutex& m_mutex;
};



class StackOnlyClass
{
private:
  void *operator new(size_t) = delete;
};


class HeapOnlyClass
{
public:
  static HeapOnlyClass *create() { return new HeapOnlyClass; }
  static void destroy(HeapOnlyClass *a_obj) { delete a_obj; }
private:
  HeapOnlyClass() {}
  ~HeapOnlyClass() {}
};


#include "UnitTest.h"


#endif // COMMON_H
