#ifndef MINLIB_ESP32_THREAD_
#define MINLIB_ESP32_THREAD_

#include "mn-autolock.h"
#include "mn-error.hpp"
#include "mn-sleep.h"
#include "mn-micros.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/task.h"

class  basic_thread {
public:
  basic_thread() { }
  basic_thread(char const* strName, unsigned int uiPriority,
       unsigned short  usStackDepth = configMINIMAL_STACK_SIZE);
	virtual ~basic_thread();

  int                   create(int uiCore = -1);
  int                   kill();


  bool                  is_running();

  const char*           get_name();
  unsigned int          get_priority();
  unsigned short        get_stackdepth();
  xTaskHandle           get_handle();
  void*                 get_return_value();
  uint32_t              get_time_since_start();
  uint32_t              get_id();
  uint32_t              get_on_core();

  void                  setPriority(unsigned int uiPriority);

  void                  suspend();
  void                  resume();

  virtual void*         on_thread() { return NULL; }

  basic_thread*         get_root();
  basic_thread*         get_child();

  bool                  add_child_thread(basic_thread* thread);
public:
  static void suspend(basic_thread *t)  { t->suspend(); }
  static void resume(basic_thread *t)   {   t->resume(); }
  static void yield()                   { taskYIELD(); }
  static void sleep(unsigned int secs)     { ::sleep(secs); }
  static void usleep(unsigned int usec)     { ::usleep(usec); }
  static void nsleep(const struct timespec *req, struct timespec *rem)     {
    ::nsleep(req, rem);
  }

  static void lock(basic_thread * t)    { t->m_runningMutex->lock(); }
  static void unlock(basic_thread * t)    { t->m_runningMutex->unlock(); }
protected:
  static void runtaskstub(void* parm);
private:
  static uint32_t get_new_id();
protected:
  xTaskHandle handle;
  const char* m_strName;
  unsigned int m_uiPriority;
  unsigned short m_usStackDepth;
  void* m_retval;

  bool m_bMutexInit;
  bool m_bRunning;
  uint32_t m_iID;
  uint32_t m_iCore;
  mutext_t *m_runningMutex;
  mutext_t *m_contextMutext;

  mutext_t *m_continuemutex, *m_continuemutex2;
private:
  basic_thread *m_pChild;
  basic_thread *m_pParent;
};

using mthread = basic_thread;

#endif