// CFTTAsyncEvent - [2020-04-13 11:57:46]
#ifndef _CFTTASYNCEVENT_H_
#define _CFTTASYNCEVENT_H_

#include "CFTTMemPool_Resizing.h"
#include "FTTMutex.h"
#include "FTTSemaphore.h"
#include "FTTThread.h"

/*
001FAA2C CFTTAsyncEvent<TFTTFileAsyncEventData>::CFTTAsyncEvent(EFTTEventType,bool,bool)
001FAAAC CFTTAsyncEvent<TFTTFileAsyncEventData>::AddCallback(void (*)(CFTTAsyncEvent<TFTTFileAsyncEventData>*,TFTTFileAsyncEventData const*,void *),void *)
001FAF54 CFTTAsyncEvent<TFTTFileAsyncEventData>::WaitForCompletion(TFTTFileAsyncEventData*)
001FAFE8 CFTTAsyncEvent<TFTTFileAsyncEventData>::~CFTTAsyncEvent()
00265478 CFTTAsyncEvent<TFTTFileAsyncEventData>::Complete(TFTTFileAsyncEventData const*)

00265CB4 CFTTAsyncEvent<CFTTJob *>::Complete(CFTTJob * const*)
00265DCC CFTTAsyncEvent<CFTTJob *>::~CFTTAsyncEvent()

void (*)(CFTTAsyncEvent<TFTTFileAsyncEventData>*, TFTTFileAsyncEventData const*,void *)

CFTTAsyncEvent<TFTTFileAsyncEventData> 0x70

v33 = operator new(0x70, 0, 0, v31);
CFTTAsyncEvent<TFTTFileAsyncEventData>::CFTTAsyncEvent((int)v33, 2, 1, 0);
CFTTAsyncEvent<CFTTJob *> 0x44

TFTTFileAsyncEventData 0x28
*/
//-------------------------------------------------------------------------------------------------
enum EFTTEventType {
  EFTTEventType_0,
  EFTTEventType_1,
  EFTTEventType_2,
  EFTTEventType_3,
  EFTTEventType_4
};
//-------------------------------------------------------------------------------------------------
extern FTTMutex CFTTAsyncEvent_tCallbackMutex;              // 0x5CE3E8
extern FTTMutex CFTTAsyncEvent_tWakeupMutex;                // 0x5CE40C
extern CFTTMemPool_Resizing* pCFTTAsyncEvent_CallbackPool;  // 0x5CE3E4

//-------------------------------------------------------------------------------------------------
template <typename T>
class CFTTAsyncEvent {
public:
  typedef void (*asyncevent_callback)(CFTTAsyncEvent<T>* pAsyncEvent, T const* pTemplate, void* pClass);

  struct EventNode {
    asyncevent_callback fun_0;
    void* pClass;
    EventNode* next_8;
  };

  // 001FAA2C //^_-
  CFTTAsyncEvent(EFTTEventType dEventType, bool a2, bool a3) : FTTSemaphore_8(0, 8, nullptr), bool_0(false) {
    // 001FAA52
    LOGI("CFTTAsyncEvent::CFTTAsyncEvent entry");
    if (pCFTTAsyncEvent_CallbackPool == nullptr) {
      CFTTAsyncEvent_tCallbackMutex.Lock();           // 001FAA5E
      if (pCFTTAsyncEvent_CallbackPool == nullptr) {  //原始的汇编就是在这里重复两次判断
        pCFTTAsyncEvent_CallbackPool = new CFTTMemPool_Resizing;
        pCFTTAsyncEvent_CallbackPool->pResizing_Node_0 = nullptr;
        pCFTTAsyncEvent_CallbackPool->dsize_4 = sizeof(EventNode);
        pCFTTAsyncEvent_CallbackPool->count_8 = 0x40;
        pCFTTAsyncEvent_CallbackPool->uyMagnify_C = 0;
        pCFTTAsyncEvent_CallbackPool->eHeapId_10 = EFTTMemHeapID_0;
      }
      CFTTAsyncEvent_tCallbackMutex.Unlock();
    }

    // loc_1FAA8E
    EFTTEventType_4 = dEventType;
    pEventNode_38 = nullptr;
    bool_1 = a2;
    bool_2 = a3;
    count_68 = 0;
  };

  // 001FAFE8 //^_^
  ~CFTTAsyncEvent() {
    CFTTAsyncEvent_tCallbackMutex.Lock();
    EventNode* node = pEventNode_38;
    if (node) {
      while (node) {
        pEventNode_38 = node->next_8;
        pCFTTAsyncEvent_CallbackPool->Deallocate(node);
        node = pEventNode_38;
      }
    }

    if (!pCFTTAsyncEvent_CallbackPool->pResizing_Node_0) {
      if (pCFTTAsyncEvent_CallbackPool) {
        delete pCFTTAsyncEvent_CallbackPool;
      }
      pCFTTAsyncEvent_CallbackPool = nullptr;
    }
    CFTTAsyncEvent_tCallbackMutex.Unlock();
  };

  // 00265478 //^_^
  void Complete(T const* pT) {
    LOGI("CFTTAsyncEvent::Complete entry");
    CFTTAsyncEvent_tCallbackMutex.Lock();
    if (bool_0) {
      // loc_265492
      CFTTAsyncEvent_tCallbackMutex.Unlock();
      return;
    }

    // loc_26549C
    memcpy(&tmplate_40, pT, sizeof(T));
    EventNode* r6_pEventNode_38 = pEventNode_38;
    if (bool_1)
      pEventNode_38 = nullptr;

    // loc_2654B2
    if (r6_pEventNode_38 && bool_2) {
      for (EventNode* r5_pNode = r6_pEventNode_38; r5_pNode != nullptr; r5_pNode = r5_pNode->next_8) {  // loc_2654C8
        // loc_2654BC
        r5_pNode->fun_0(this, pT, r5_pNode->pClass);
      }
    }

    // loc_2654CC
    if (EFTTEventType_4 != EFTTEventType_1) {
      // 002654D2
      bool_0 = true;
      if (EFTTEventType_4 == EFTTEventType_0) {
        // loc_265570
        if (r6_pEventNode_38 == nullptr || (bool_2 && !bool_1)) {
          // loc_26557E
          FTTSemaphore_8.SignalSema(8);
          CFTTAsyncEvent_tCallbackMutex.Unlock();
          return;
        }
      }
    }

    // loc_2654DA
    FTTSemaphore_8.SignalSema(8);
    if (EFTTEventType_4 == EFTTEventType_1) {
      // loc_2654F4
      while (count_68) {
        FTTThread_Sleep(1);
      }

      for (uint dr7 = 8; dr7 != 0; dr7--) {  // loc_26550A
        // loc_2654FE
        FTTSemaphore_8.WaitSema(-1);
      }
    }

    // loc_26550E
    CFTTAsyncEvent_tCallbackMutex.Unlock();
    // 00265514
    if (r6_pEventNode_38 != nullptr) {
      if (!bool_2) {
        // 0026551A
        for (EventNode* r5_pNode = r6_pEventNode_38; r5_pNode != nullptr; r5_pNode = r5_pNode->next_8) {  // loc_26552A
          // loc_26551E
          r5_pNode->fun_0(this, pT, r5_pNode->pClass);
        }
      }

      // loc_26552E
      if (bool_1) {
        CFTTAsyncEvent_tCallbackMutex.Lock();
        // loc_26554C
        for (; r6_pEventNode_38 != nullptr; r6_pEventNode_38 = r6_pEventNode_38->next_8) {  // loc_26554C
          // loc_265540
          pCFTTAsyncEvent_CallbackPool->Deallocate(r6_pEventNode_38);
        }
        CFTTAsyncEvent_tCallbackMutex.Unlock();
      }
    }

    // loc_265556
    // if (this != nullptr) //??? 原始函数当中确实，有这一行，但是是感觉没有必要这么写，会引起编译警告，暂时先去掉了
    {
      if (EFTTEventType_4 == EFTTEventType_2) {
        delete this;
      }
    }
    return;
  };

  // 001FAAAC //^_^
  void AddCallback(asyncevent_callback pFunc_Callback, void* pclass) {
    LOGI("CFTTAsyncEvent::AddCallback Entry");
    CFTTAsyncEvent_tCallbackMutex.Lock();
    if (!bool_0 || !bool_1) {
      EventNode* v9 = (EventNode*)pCFTTAsyncEvent_CallbackPool->Allocate();  //引用计数 +1
      v9->fun_0 = pFunc_Callback;
      v9->pClass = pclass;
      v9->next_8 = pEventNode_38;
      pEventNode_38 = v9;
      if (!bool_0) {
        CFTTAsyncEvent_tCallbackMutex.Unlock();
        LOGI("CFTTAsyncEvent::AddCallback End 11");
        return;
      }
    }

    T tmplate;
    memcpy(&tmplate, &tmplate_40, sizeof(T));

    CFTTAsyncEvent_tCallbackMutex.Unlock();
    LOGI("CFTTAsyncEvent::AddCallback pFunc_Callback");
    pFunc_Callback(this, &tmplate, pclass);
    LOGI("CFTTAsyncEvent::AddCallback End");
  };

  // 001FAF54 //^_^
  void WaitForCompletion(T* pTemplate) {
    CFTTAsyncEvent_tCallbackMutex.Lock();
    if (bool_0) {
      if (pTemplate) {
        memcpy(pTemplate, &tmplate_40, sizeof(T));
      }
      CFTTAsyncEvent_tCallbackMutex.Unlock();
    } else {
      CFTTAsyncEvent_tWakeupMutex.Lock();
      ++count_68;
      CFTTAsyncEvent_tWakeupMutex.Unlock();
      CFTTAsyncEvent_tCallbackMutex.Unlock();

      if (FTTSemaphore_8.WaitSema(-1)) {
        CFTTAsyncEvent_tWakeupMutex.Lock();
        --count_68;
        CFTTAsyncEvent_tWakeupMutex.Unlock();
        if (pTemplate)
          memcpy(pTemplate, &tmplate_40, sizeof(T));
        FTTSemaphore_8.SignalSema(1);
      }
    }
  };

  uint8 bool_0;
  bool bool_1;
  bool bool_2;
  bool unuse_3;
  EFTTEventType EFTTEventType_4;
  FTTSemaphore FTTSemaphore_8;
  EventNode* pEventNode_38;  // call back function link list
  int field_3C;
  T tmplate_40;

  int count_68;
};

#endif  //_CFTTASYNCEVENT_H_