// File: /workspace/github_cpp_makefile_star2_O2/cpottamus[P]btree_lab/btree.cc
// Function: BTreeIndex::Insert(Block const&, Block const&)
ERROR_T BTreeIndex::Insert(const KEY_T &key, const VALUE_T &value)
{
  //This is really a B+ tree (with optional sequentially linked leaf nodes).
  //This means that on every key you split, you need to include that key AGAIN in it's >= diskblock, so that is eventually included in a leaf node with it's key/value pair.
  //This is also what makes deleting a key a nightmare, since you have to get rid of ALL instances of the ky (including the leaf version with the value), and then rebalance.
  // page 636 in the book has good diagrams of this
  //cout << "Started insert" << endl;

  //======ALGORITHM======
  VALUE_T val;

  //Lookup and attempt to update key
  ERROR_T retCode = LookupOrUpdateInternal(superblock.info.rootnode, BTREE_OP_LOOKUP, key, val);

  //cout << "Finished LookupOrUpdateInternal" << endl;

  switch(retCode) {
    //If there is no error in the update call, end function, declare update successful.
    case ERROR_NOERROR:
    //std::cout << "Key already existed, value updated."<<std::endl;
    return ERROR_INSERT;
    //If the key doesn't exist (as expected), begin insert functionality
    case ERROR_NONEXISTENT:
      //traverse to find the leaf
      //Use a stack of pointers to track the path down to the node where the key would go.
    BTreeNode leafNode;
    BTreeNode rootNode;
    BTreeNode rightLeafNode;
    ERROR_T rc;
    SIZE_T leafPtr;
    SIZE_T rightLeafPtr;

    SIZE_T rootPtr = superblock.info.rootnode;
    rootNode.Unserialize(buffercache, rootPtr);
    initBlock = false;
    if (rootNode.info.numkeys != 0) {
      initBlock = true;
    }
    
    rootNode.Serialize(buffercache, rootPtr);

    //If no keys  existent yet...
    if(!initBlock){
      initBlock=true;
      
        //Allocate a new block, and set the values to the first key spot.
      AllocateNode(leafPtr);
      leafNode = BTreeNode(BTREE_LEAF_NODE, superblock.info.keysize, superblock.info.valuesize, superblock.info.blocksize);
      leafNode.Serialize(buffercache, leafPtr);
      rc = leafNode.Unserialize(buffercache, leafPtr);
      if(rc){ return rc;}

      leafNode.info.numkeys++;
      leafNode.SetKey(0, key);
      leafNode.SetVal(0, value);
      //Re-serialize after the access and write. 
      leafNode.Serialize(buffercache, leafPtr);

      //Connect it to root
      rc = rootNode.Unserialize(buffercache, superblock.info.rootnode);
      if(rc){ return rc;}
      rootNode.info.numkeys++;
      rootNode.SetPtr(0, leafPtr);
      rootNode.SetKey(0, key);

      //Built right node and connect
      AllocateNode(rightLeafPtr);
      rightLeafNode = BTreeNode(BTREE_LEAF_NODE, superblock.info.keysize, superblock.info.valuesize, superblock.info.blocksize);
      rc = rightLeafNode.Serialize(buffercache, rightLeafPtr);
      if(rc){ return rc;}
      rootNode.SetPtr(1, rightLeafPtr);
      rc = rootNode.Serialize(buffercache, superblock.info.rootnode);
      if(rc){ return rc;}
    } else{
      std::vector<SIZE_T> pointerPath;
      pointerPath.push_back(superblock.info.rootnode);
      //cout << "Got to LookupLeaf" << endl;
      LookupLeaf(superblock.info.rootnode, key, pointerPath);
      //cout << "Finished LookupLeaf" << endl;
    //Get the node from the last pointer (which points to the leaf node that the key belongs on)
      leafPtr = pointerPath.back();
      // std::cout<<"WE BUILT THIS CITY ON ROCK AND ROLL SHOEFLY Dont bother me ::: "<<leafPtr<<std::endl;
      // std::cout<<"ALSO THIS ::: "<<pointerPath.size()<<std::endl;
      // for(int i =pointerPath.size()-1; i>=0; i--) {
      //   std::cout<<"Little sumpin"<<pointerPath.at(i)<<std::endl;
      // }
      pointerPath.pop_back();
      //cout << "LeafPtr:" << leafPtr << endl;
      KEY_T testkey;
      KEY_T keySpot;
      VALUE_T valSpot;
      rc = leafNode.Unserialize(buffercache, leafPtr);
      //cout << "Unserialized LeafPtr" << endl;
      //Walk the leaf node
      //Increment the key count for the given node.
      leafNode.info.numkeys++;
        //cout << leafNode.info.numkeys << endl;
      if (leafNode.info.numkeys == 1) {
        rc = leafNode.SetKey(0, key);
        if (rc) { return rc;}
        rc = leafNode.SetVal(0, value);
        if (rc) { return rc;}
      } else {
        bool inserted = false;
        for(SIZE_T offset =0; offset<(int)leafNode.info.numkeys-1; offset++){
          rc = leafNode.GetKey(offset, testkey);
          if (rc) { return rc;}
          if(key < testkey) {
        //Once you've found the spot the key needs to go, move all other keys over by 1
            for(int offset2 = (int)leafNode.info.numkeys-2; offset2 >= (int)offset; offset2--){
          //Grab the old key and value
              rc = leafNode.GetKey((SIZE_T)offset2, keySpot);
              if (rc) { return rc;}
              rc = leafNode.GetVal((SIZE_T)offset2, valSpot);
              if (rc) { return rc;}
         //move it up by 1
              rc = leafNode.SetKey((SIZE_T)offset2+1, keySpot);
              if (rc) { return rc;}
              rc = leafNode.SetVal((SIZE_T)offset2+1, valSpot);
              if (rc) { return rc;}
            }

        //assign the new key to offset
            inserted = true;
            rc = leafNode.SetKey(offset, key);
            if (rc) { return rc;}
            rc = leafNode.SetVal(offset, value);
            if (rc) { return rc;}

            break;
          }
        }
        if (!inserted) {
          rc = leafNode.SetKey(leafNode.info.numkeys - 1, key);
          if (rc) { return rc;}
          rc = leafNode.SetVal(leafNode.info.numkeys - 1, value);
          if (rc) { return rc;}
        }
      }
     //Re-serialize after the access and write. 
      leafNode.Serialize(buffercache, leafPtr); 
    //check if the node length is over 2/3, and call rebalance if necessary
      if((int)leafNode.info.numkeys > (int)(2*maxNumKeys/3)) {
          SIZE_T parentPtr = pointerPath.back();
          pointerPath.pop_back();
        rc = Rebalance(parentPtr, pointerPath);
      }
    }

    /*
    default:
    std::cout << "Unexpected Error on look up. Please perform sanityCheck and diagnose issue."<<std::endl;
    return ERROR_INSANE;
    */ 
  }

  //If it exists, call update on it with the new value


  return ERROR_NOERROR;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x168, %rsp            # imm = 0x168
movq %rdx, 0x10(%rsp)
movq %rsi, %r14
movq %rdi, %rbx
leaq 0x140(%rsp), %r15
movq %r15, %rdi
callq 0x2ac4
leaq 0x28(%rbx), %r12
pushq $0x3
popq %rdx
movq %rbx, %rdi
movq %r12, %rsi
movq %r14, %rcx
movq %r15, %r8
callq 0x5316
cmpl $-0x9, %eax
je 0x556a
testl %eax, %eax
jne 0x59fa
pushq $-0x10
popq %r12
jmp 0x59fd
leaq 0x18(%rsp), %rdi
callq 0x725a
leaq 0x88(%rsp), %rdi
callq 0x725a
leaq 0x118(%rsp), %rdi
callq 0x725a
movl 0x28(%rbx), %ebp
movq 0x8(%rbx), %rsi
leaq 0x88(%rsp), %rdi
movl %ebp, %edx
callq 0x73fc
leaq 0x88(%rsp), %rdi
cmpl $0x0, 0x18(%rdi)
setne 0x44(%rbx)
movq 0x8(%rbx), %rsi
movl %ebp, %edx
callq 0x7338
cmpb $0x0, 0x44(%rbx)
je 0x56a3
xorps %xmm0, %xmm0
leaq 0x70(%rsp), %rdi
movaps %xmm0, (%rdi)
andq $0x0, 0x10(%rdi)
movq %r12, %rsi
callq 0x6f0e
leaq 0x70(%rsp), %rcx
movq %rbx, %rdi
movq %r12, %rsi
movq %r14, %rdx
callq 0x5af8
movq 0x78(%rsp), %rax
movl -0x4(%rax), %ecx
addq $-0x4, %rax
movl %ecx, 0x8(%rsp)
movl %ecx, 0x4(%rsp)
movq %rax, 0x78(%rsp)
leaq 0x48(%rsp), %rdi
callq 0x2ac4
leaq 0xf0(%rsp), %rdi
callq 0x2ac4
leaq 0xc8(%rsp), %rdi
callq 0x2ac4
movq 0x8(%rbx), %rsi
leaq 0x18(%rsp), %rdi
movl 0x8(%rsp), %edx
callq 0x73fc
movl 0x30(%rsp), %eax
leal 0x1(%rax), %esi
movl %esi, 0x30(%rsp)
testl %eax, %eax
je 0x5827
xorl %r13d, %r13d
leaq 0x18(%rsp), %r15
leaq 0x48(%rsp), %rbp
decl %esi
cmpl %esi, %r13d
jae 0x5854
movq %r15, %rdi
movl %r13d, %esi
movq %rbp, %rdx
callq 0x7622
movl %eax, %r12d
testl %eax, %eax
jne 0x5997
movq %r14, %rdi
movq %rbp, %rsi
callq 0x2ccc
testb %al, %al
jne 0x5900
incl %r13d
movl 0x30(%rsp), %esi
jmp 0x5663
movb $0x1, 0x44(%rbx)
leaq 0x4(%rsp), %rsi
movq %rbx, %rdi
callq 0x4f90
movl 0x1c(%rbx), %edx
movl 0x20(%rbx), %ecx
movl 0x24(%rbx), %r8d
leaq 0x48(%rsp), %rdi
pushq $0x4
popq %rsi
callq 0x7280
leaq 0x18(%rsp), %rdi
leaq 0x48(%rsp), %rsi
callq 0x732a
leaq 0x48(%rsp), %rdi
callq 0x7264
movq 0x8(%rbx), %rsi
movl 0x4(%rsp), %ebp
leaq 0x18(%rsp), %rdi
movl %ebp, %edx
callq 0x7338
movq 0x8(%rbx), %rsi
leaq 0x18(%rsp), %rdi
movl %ebp, %edx
callq 0x73fc
movl %eax, %r12d
testl %eax, %eax
jne 0x59d0
leaq 0x18(%rsp), %rdi
incl 0x18(%rdi)
xorl %esi, %esi
movq %r14, %rdx
callq 0x770a
leaq 0x18(%rsp), %rdi
xorl %esi, %esi
movq 0x10(%rsp), %rdx
callq 0x775a
movq 0x8(%rbx), %rsi
leaq 0x18(%rsp), %rdi
movl %ebp, %edx
callq 0x7338
movq 0x8(%rbx), %rsi
movl 0x28(%rbx), %edx
leaq 0x88(%rsp), %rdi
callq 0x73fc
movl %eax, %r12d
testl %eax, %eax
jne 0x59d0
leaq 0x88(%rsp), %rdi
incl 0x18(%rdi)
leaq 0x4(%rsp), %rdx
xorl %esi, %esi
callq 0x773e
leaq 0x88(%rsp), %rdi
xorl %esi, %esi
movq %r14, %rdx
callq 0x770a
leaq 0xc(%rsp), %rsi
movq %rbx, %rdi
callq 0x4f90
movl 0x1c(%rbx), %edx
movl 0x20(%rbx), %ecx
movl 0x24(%rbx), %r8d
leaq 0x48(%rsp), %rdi
pushq $0x4
popq %rsi
callq 0x7280
leaq 0x118(%rsp), %rdi
leaq 0x48(%rsp), %rsi
callq 0x732a
leaq 0x48(%rsp), %rdi
callq 0x7264
movq 0x8(%rbx), %rsi
movl 0xc(%rsp), %edx
leaq 0x118(%rsp), %rdi
callq 0x7338
movl %eax, %r12d
testl %eax, %eax
jne 0x59d0
leaq 0x88(%rsp), %rdi
pushq $0x1
popq %rsi
leaq 0xc(%rsp), %rdx
callq 0x773e
movq 0x8(%rbx), %rsi
movl 0x28(%rbx), %edx
leaq 0x88(%rsp), %rdi
callq 0x7338
movl %eax, %r12d
testl %eax, %eax
jne 0x59d0
jmp 0x59cc
leaq 0x18(%rsp), %rdi
xorl %esi, %esi
movq %r14, %rdx
callq 0x770a
movl %eax, %r12d
testl %eax, %eax
jne 0x5997
leaq 0x18(%rsp), %rdi
xorl %esi, %esi
movq 0x10(%rsp), %rdx
callq 0x775a
jmp 0x5880
leaq 0x18(%rsp), %rdi
movq %r14, %rdx
callq 0x770a
movl %eax, %r12d
testl %eax, %eax
jne 0x5997
leaq 0x18(%rsp), %rdi
movl 0x18(%rdi), %esi
decl %esi
movq 0x10(%rsp), %rdx
callq 0x775a
movl %eax, %r12d
testl %eax, %eax
jne 0x5997
movq 0x8(%rbx), %rsi
leaq 0x18(%rsp), %rdi
movl 0x8(%rsp), %edx
callq 0x7338
movl 0x30(%rsp), %ecx
movl 0x40(%rbx), %eax
addl %eax, %eax
xorl %edx, %edx
pushq $0x3
popq %rsi
divl %esi
movb $0x1, %bpl
cmpl %eax, %ecx
jle 0x58fb
leaq 0x70(%rsp), %rsi
movq 0x8(%rsi), %rax
movl -0x4(%rax), %ecx
addq $-0x4, %rax
movl %ecx, 0x44(%rsp)
movq %rax, 0x8(%rsi)
leaq 0xb0(%rsp), %rdi
callq 0x6f2c
leaq 0x44(%rsp), %rsi
leaq 0xb0(%rsp), %rdx
movq %rbx, %rdi
callq 0x5c56
leaq 0xb0(%rsp), %rdi
callq 0x6f7a
jmp 0x5999
leaq 0x18(%rsp), %r15
movl 0x18(%r15), %ebp
addl $-0x2, %ebp
cmpl %r13d, %ebp
jl 0x597c
movq %r15, %rdi
movl %ebp, %esi
leaq 0xf0(%rsp), %rdx
callq 0x7622
movl %eax, %r12d
testl %eax, %eax
jne 0x5997
movq %r15, %rdi
movl %ebp, %esi
leaq 0xc8(%rsp), %rdx
callq 0x768a
movl %eax, %r12d
testl %eax, %eax
jne 0x5997
incl %ebp
movq %r15, %rdi
movl %ebp, %esi
leaq 0xf0(%rsp), %rdx
callq 0x770a
movl %eax, %r12d
testl %eax, %eax
jne 0x5997
movq %r15, %rdi
movl %ebp, %esi
leaq 0xc8(%rsp), %rdx
callq 0x775a
movl %eax, %r12d
addl $-0x2, %ebp
testl %eax, %eax
je 0x590c
jmp 0x5997
leaq 0x18(%rsp), %rdi
movl %r13d, %esi
movq %r14, %rdx
callq 0x770a
movl %eax, %r12d
testl %eax, %eax
je 0x5a1f
xorl %ebp, %ebp
leaq 0xc8(%rsp), %rdi
callq 0x2c6e
leaq 0xf0(%rsp), %rdi
callq 0x2c6e
leaq 0x48(%rsp), %rdi
callq 0x2c6e
leaq 0x70(%rsp), %rdi
callq 0x6f7a
testb %bpl, %bpl
je 0x59d0
movb $0x1, %bl
jmp 0x59d2
xorl %ebx, %ebx
leaq 0x118(%rsp), %rdi
callq 0x7264
leaq 0x88(%rsp), %rdi
callq 0x7264
leaq 0x18(%rsp), %rdi
callq 0x7264
testb %bl, %bl
je 0x59fd
xorl %r12d, %r12d
leaq 0x140(%rsp), %rdi
callq 0x2c6e
movl %r12d, %eax
addq $0x168, %rsp            # imm = 0x168
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x18(%rsp), %rdi
movl %r13d, %esi
movq 0x10(%rsp), %rdx
callq 0x775a
jmp 0x5880
movq %rax, %rbx
leaq 0xb0(%rsp), %rdi
callq 0x6f7a
jmp 0x5a91
jmp 0x5a8e
jmp 0x5a8e
jmp 0x5a5c
jmp 0x5a89
jmp 0x5a8e
movq %rax, %rbx
jmp 0x5a9e
movq %rax, %rbx
jmp 0x5aab
movq %rax, %rbx
leaq 0x48(%rsp), %rdi
callq 0x7264
jmp 0x5abf
jmp 0x5a71
jmp 0x5a89
jmp 0x5a8e
movq %rax, %rbx
jmp 0x5ab5
movq %rax, %rbx
jmp 0x5acc
movq %rax, %rbx
jmp 0x5ad9
jmp 0x5a84
jmp 0x5a8e
movq %rax, %rbx
jmp 0x5ae3
movq %rax, %rbx
jmp 0x5abf
movq %rax, %rbx
leaq 0xc8(%rsp), %rdi
callq 0x2c6e
leaq 0xf0(%rsp), %rdi
callq 0x2c6e
leaq 0x48(%rsp), %rdi
callq 0x2c6e
leaq 0x70(%rsp), %rdi
callq 0x6f7a
leaq 0x118(%rsp), %rdi
callq 0x7264
leaq 0x88(%rsp), %rdi
callq 0x7264
leaq 0x18(%rsp), %rdi
callq 0x7264
leaq 0x140(%rsp), %rdi
callq 0x2c6e
movq %rbx, %rdi
callq 0x2380