//FTTMap - [2020-04-13 11:57:47]
#ifndef _FTTMAP_H_
#define _FTTMAP_H_

#include "common.h"

/*
001A22C0 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::GetRange(FTTPair<ushort,ushort>)
001A856E FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Clear()
001A8582 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Clear(FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Node *)
001A8D2C FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::End()
001A8C36 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::GetRange(FTTPair<ushort,ushort>,
                                                                  FTTMap<FTTPair<ushort,ushort>, ushort,EdgeLess>::Node *,
                                                                  FTTVector<FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Iterator> &)

0019C69E FTTMap<float,uint,FTTLess>::FTTMap(uint)
0019C700 FTTMap<float,uint,FTTLess>::Insert(FTTPair<float,uint> const&)
0019C790 FTTMap<float,uint,FTTLess>::Iterator::operator->()
0019C794 FTTMap<float,uint,FTTLess>::Remove(FTTMap<float,uint,FTTLess>::Iterator,bool)
0019C824 FTTMap<float,uint,FTTLess>::~FTTMap()
001A2152 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Insert(FTTPair<ushort,ushort>,ushort)
001A2348 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::~FTTMap()
001A49D2 FTTMap<float,uint,FTTLess>::Iterator::operator++()
001A49E2 FTTMap<float,uint,FTTLess>::Iterator::operator!=(FTTMap<float,uint,FTTLess>::Iterator const&)
001A49EE FTTMap<float,uint,FTTLess>::Iterator::operator*()
001A49F2 FTTMap<float,uint,FTTLess>::Iterator::operator--()
001A4A02 FTTMap<float,uint,FTTLess>::Node::Next()
001A4A2E FTTMap<float,uint,FTTLess>::Node::Prev()
001A773C FTTMap<float,uint,FTTLess>::Clear()
001A7750 FTTMap<float,uint,FTTLess>::Clear(FTTMap<float,uint,FTTLess>::Node *)
001A778C FTTMap<float,uint,FTTLess>::Rebalance(FTTMap<float,uint,FTTLess>::Node *)
001A782E FTTMap<float,uint,FTTLess>::Node::GetBalance()
001A784A FTTMap<float,uint,FTTLess>::Node::GetHeight()
001A7874 FTTMap<float,uint,FTTLess>::Node::RotateLeft()
001A78A4 FTTMap<float,uint,FTTLess>::Node::RotateRightLeft()
001A7918 FTTMap<float,uint,FTTLess>::Node::RotateRight()
001A7948 FTTMap<float,uint,FTTLess>::Node::RotateLeftRight()

001A85BC FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Insert(FTTPair const&<FTTPair<ushort,ushort>,ushort>)
001A8654 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Node::operator=(FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Node&&)
001A8674 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Rebalance(FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Node *)
001A8730 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Node::GetBalance()
001A874C FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Node::GetHeight()
001A8776 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Node::RotateLeft()
001A87A8 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Node::RotateRightLeft()
001A881C FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Node::RotateRight()
001A884C FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Node::RotateLeftRight()
001A8CA8 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Search(FTTPair<ushort,ushort>,FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Node *)
001A8D20 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Iterator::operator!=(FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Iterator const&)
001A8D68 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Iterator::operator++()
001A8D78 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Iterator::operator*()
001A8D7C FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Iterator::operator->()
001A8D80 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Iterator::operator--()
001A8D90 FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Node::Next()
001A8DBC FTTMap<FTTPair<ushort,ushort>,ushort,EdgeLess>::Node::Prev()
*/

template <typename T1, typename T2, typename T3>
class FTTMap {
public:
  class Node {
    int GetBalance() {
      Node* v1;    //r1
      Node* v2;    //r0
      int result;  //r0
      Node* v4;    //r1

      v1 = this;
      v2 = this->node_C;
      if (node_C)
        result = -v2->node_14;
      else
        result = 0;
      v4 = v1->node_next_10;
      if (v4)
        result += v4->node_14;
      return result;
    };

    int GetHeight() {
      Node* v1;         //r1
      unsigned int v2;  //r2
      int v3;           //r1
      Node* v4;         //r1
      unsigned int v5;  //r1

      v1      = node_C;
      v2      = 1;
      node_14 = 1;
      if (v1) {
        v3 = v1->node_14;
        v2 = v3 + 1;
        if (v3 == -1)
          v2 = 1;
        this->node_14 = v2;
      }
      v4 = this->node_next_10;
      if (!v4)
        return v2;
      v5 = v4->node_14 + 1;
      if (v2 > v5)
        v5 = v2;
      this->node_14 = v5;
      return v5;
    };

    Node* Next() {
      Node* v1;      //r2
      Node* v2;      //r1
      Node* result;  //r0

      v1 = node_next_10;
      v2 = this;
      if (!v1) {
        result = (Node*)node_8;
        if (result) {
        LABEL_8:
          if (result->node_C == v2)
            return result;
          while (1) {
            v2 = result;
            if (!result)
              break;
            result = (Node*)result->node_8;
            if (result)
              goto LABEL_8;
          }
        }
        return 0;
      }
      do {
        result = v1;
        v1     = v1->node_C;
      } while (v1);
      return result;
    };

    Node* Prev() {
      Node* v1;      //r2
      Node* v2;      //r1
      Node* result;  //r0

      Node* v1 = node_C;
      if (!v1) {
        result = (Node*)this->node_8;
        if (result) {
        LABEL_8:
          if (result->node_next_10 == this)
            return result;
          while (1) {
            this = result;
            if (!result)
              break;
            result = (Node*)result->node_8;
            if (result)
              goto LABEL_8;
          }
        }
        return 0;
      }
      do {
        result = v1;
        v1     = v1->node_next_10;
      } while (v1);
      return result;
    };

    int RotateLeft() {
      Node* v1;  //r2
      Node* v2;  //r1
      Node* v3;  //r3
      Node* v4;  //r3
      Node* v5;  //r3

      v1                 = this->node_next_10;
      v2                 = (Node*)this->node_8;
      v3                 = v1->node_C;
      this->node_8       = (int)v1;
      this->node_next_10 = v3;
      if (v3)
        v3->node_8 = (int)this;
      v1->node_8 = (int)v2;
      v1->node_C = this;
      if (v2) {
        v4 = v2->node_C;
        if (v4 && v4 == this)
          v2->node_C = v1;
        v5 = v2->node_next_10;
        if (v5 && v5 == this)
          v2->node_next_10 = v1;
      }
      return GetHeight();
    };

    T1 node_0;           //0
    T2 note_4;           //4
    T3 node_8;           //8
    Node* node_C;        //0xC
    Node* node_next_10;  //0xC
    int node_14;
  };

  //001C37D0
  FTTMap(int count) {
    map_use_list_0 = nullptr;
    map_count_C    = 0;
    map_10         = 0;
    if (count) {
      Node* v7 = new Node[count];
      memset(v7, 0, sizeof(Node) * count);
      map_idle_list_4 = v7;
      map_all_list_8  = v7;
      int i           = 0;
      int v9          = count;
      while (v9) {
        --v9;
        v7[i].next = &tl[i + 1];
        i++;
      }
      v7[count - 1].next = nullptr;
    } else {
      map_idle_list_4 = nullptr;
      map_all_list_8  = nullptr;
    }
  };

  ~FTTMap() {
    Clear();
    if (map_all_list_8) {
      delete[] map_all_list_8;
    }
  };

  void Clear() {
    if (map_use_list_0)
      Clear(map_use_list_0);
    map_use_list_0 = 0;
  };

  void Clear(FTTMap<T1, T2, T3>::Node*) {
    Node* v2;                      //r5
    Node* v3;                      //r1
    FTTMap<T1, T2, T3>* vthis;     //r4
    Node* v5;                      //r1
    void(__fastcall * v6)(Node*);  //r1
    int result;                    //r0

    v2    = a2;
    v3    = a2->node_C;
    vthis = this;
    if (v3)
      FTTMap<float, unsigned int, FTTLess>::Clear(this, v3);
    v5 = v2->node_next_10;
    if (v5)
      FTTMap<float, unsigned int, FTTLess>::Clear(vthis, v5);
    v6 = (void(__fastcall*)(Node*))vthis->map_10;
    if (v6)
      v6(v2);
    if (vthis->map_all_list_8) {
      v2->node_next_10       = vthis->map_idle_list_4;
      vthis->map_idle_list_4 = v2;
    } else {
      operator delete(v2, (int)v6);
    }
    result             = 0;
    vthis->map_count_C = 0;
    return result;
  };

  Node* Insert() {
    if (map_all_list_8 != nullptr) {
      Node* cur       = map_idle_list_4;
      map_idle_list_4 = map_idle_list_4->next;

    } else {
      Node* v7 = new Node;
    }
  };

  Node* Rebalance(Node* a2) {
    Node* v2;             //r5
    FTTMap_Float_int* i;  //r4
    int v4;               //r6
    Node* v5;             //r1
    Node* v6;             //r0
    unsigned int v7;      //r0
    Node* v8;             //r1
    unsigned int v9;      //r1
    Node* v10;            //r1
    Node* v11;            //r0
    unsigned int v12;     //r0
    Node* v13;            //r1
    unsigned int v14;     //r1
    int* v15;             //r0
    int v16;              //r6

    v2 = a2;
    for (i = this; v2; v2 = (Node*)v2->node_8) {
      v4 = FTTMap<T1, T2, T3>::Node::GetBalance((int)v2);
      FTTMap<T1, T2, T3>::Node::GetHeight(v2);
      this = (FTTMap_Float_int*)(v4 + 2);
      switch (v4 + 2) {
        case 0:
          v5 = v2->node_C;
          v6 = v5->node_C;
          if (v6)
            v7 = v6->node_14;
          else
            v7 = 0;
          v8 = v5->node_next_10;
          if (v8)
            v9 = v8->node_14;
          else
            v9 = 0;
          if (v9 >= v7)
            FTTMap<T1, unsigned int, FTTLess>::Node::RotateLeftRight(v2);
          else
            FTTMap<float, unsigned int, FTTLess>::Node::RotateRight(v2);
          goto LABEL_21;
        case 1:
        case 3:
          continue;
        case 2:
          return this;
        case 4:
          v10 = v2->node_next_10;
          v11 = v10->node_C;
          if (v11)
            v12 = v11->node_14;
          else
            v12 = 0;
          v13 = v10->node_next_10;
          if (v13)
            v14 = v13->node_14;
          else
            v14 = 0;
          if (v12 >= v14)
            FTTMap<float, unsigned int, FTTLess>::Node::RotateRightLeft(v2);
          else
            FTTMap<float, unsigned int, FTTLess>::Node::RotateLeft(v2);
        LABEL_21:
          v15 = &v2->node_8;
          if (v2 == i->map_use_list_0)
            i->map_use_list_0 = (Node*)*v15;
          v2 = (Node*)*v15;
          break;
        default:
          break;
      }
      v16  = FTTMap<float, unsigned int, FTTLess>::Node::GetBalance((int)v2);
      this = (FTTMap_Float_int*)FTTMap<float, unsigned int, FTTLess>::Node::GetHeight(v2);
      if (!v16)
        break;
    }
  };

  Node* map_use_list_0;
  Node* map_idle_list_4;
  Node* map_all_list_8;
  int map_count_C;
  int map_10;
};

#endif  //_FTTMAP_H_