// File: /workspace/github_cpp_makefile_star2_O3/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 $0x178, %rsp            # imm = 0x178
movq %rdx, %r13
movq %rsi, %r14
movq %rdi, %rbx
leaq 0x150(%rsp), %r15
movq %r15, %rdi
callq 0x2c58
leaq 0x28(%rbx), %r12
movq %rbx, %rdi
movq %r12, %rsi
movl $0x3, %edx
movq %r14, %rcx
movq %r15, %r8
callq 0x59ac
cmpl $-0x9, %eax
je 0x5c35
movl $0xfffffff0, %ebp       # imm = 0xFFFFFFF0
testl %eax, %eax
je 0x5c14
xorl %ebp, %ebp
leaq 0x150(%rsp), %rdi
callq 0x2e26
movl %ebp, %eax
addq $0x178, %rsp            # imm = 0x178
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x20(%rsp), %rdi
callq 0x7c4a
leaq 0xb0(%rsp), %rdi
callq 0x7c4a
movq %r13, 0x18(%rsp)
leaq 0x128(%rsp), %rdi
callq 0x7c4a
movl 0x28(%rbx), %ebp
movq 0x8(%rbx), %rsi
leaq 0xb0(%rsp), %rdi
movl %ebp, %edx
callq 0x7e00
leaq 0xb0(%rsp), %rdi
cmpl $0x0, 0x18(%rdi)
setne 0x44(%rbx)
movq 0x8(%rbx), %rsi
movl %ebp, %edx
callq 0x7d3a
cmpb $0x0, 0x44(%rbx)
je 0x5da1
xorps %xmm0, %xmm0
leaq 0x50(%rsp), %rdi
movaps %xmm0, (%rdi)
movq $0x0, 0x10(%rdi)
xorl %esi, %esi
movq %r12, %rdx
callq 0x7986
leaq 0x50(%rsp), %rcx
movq %rbx, %rdi
movq %r12, %rsi
movq %r14, %rdx
callq 0x620c
movq 0x58(%rsp), %rax
movl -0x4(%rax), %ecx
addq $-0x4, %rax
movl %ecx, 0x10(%rsp)
movl %ecx, 0xc(%rsp)
movq %rax, 0x58(%rsp)
leaq 0x70(%rsp), %rdi
callq 0x2c58
leaq 0x100(%rsp), %rdi
callq 0x2c58
leaq 0xd8(%rsp), %rdi
callq 0x2c58
movq 0x8(%rbx), %rsi
leaq 0x20(%rsp), %rdi
movl 0x10(%rsp), %edx
callq 0x7e00
movl 0x38(%rsp), %eax
leal 0x1(%rax), %ecx
movl %ecx, 0x38(%rsp)
testl %eax, %eax
je 0x5f2b
xorl %r13d, %r13d
leaq 0x20(%rsp), %r15
leaq 0x70(%rsp), %r12
movq %r15, %rdi
movl %r13d, %esi
movq %r12, %rdx
callq 0x802a
movl %eax, %ebp
testl %eax, %eax
jne 0x5f97
movq %r14, %rdi
movq %r12, %rsi
callq 0x2e9e
testb %al, %al
jne 0x5f53
incl %r13d
movl 0x38(%rsp), %esi
decl %esi
cmpl %esi, %r13d
jb 0x5d38
leaq 0x20(%rsp), %rdi
movq %r14, %rdx
callq 0x8118
movl %eax, %ebp
testl %eax, %eax
jne 0x5f97
leaq 0x20(%rsp), %rdi
movl 0x18(%rdi), %esi
decl %esi
movq 0x18(%rsp), %rdx
callq 0x816c
jmp 0x5f8d
movb $0x1, 0x44(%rbx)
leaq 0xc(%rsp), %rsi
movq %rbx, %rdi
callq 0x560c
movl 0x1c(%rbx), %edx
movl 0x20(%rbx), %ecx
movl 0x24(%rbx), %r8d
leaq 0x70(%rsp), %rdi
movl $0x4, %esi
callq 0x7c7c
leaq 0x20(%rsp), %rdi
leaq 0x70(%rsp), %rsi
callq 0x7d2c
leaq 0x70(%rsp), %rdi
callq 0x7c5a
movq 0x8(%rbx), %rsi
movl 0xc(%rsp), %r15d
leaq 0x20(%rsp), %rdi
movl %r15d, %edx
callq 0x7d3a
movq 0x8(%rbx), %rsi
leaq 0x20(%rsp), %rdi
movl %r15d, %edx
callq 0x7e00
movl %eax, %ebp
testl %eax, %eax
jne 0x5fde
leaq 0x20(%rsp), %rdi
incl 0x18(%rdi)
xorl %esi, %esi
movq %r14, %rdx
callq 0x8118
leaq 0x20(%rsp), %rdi
xorl %esi, %esi
movq 0x18(%rsp), %rdx
callq 0x816c
movq 0x8(%rbx), %rsi
leaq 0x20(%rsp), %rdi
movl %r15d, %edx
callq 0x7d3a
movq 0x8(%rbx), %rsi
movl 0x28(%rbx), %edx
leaq 0xb0(%rsp), %rdi
callq 0x7e00
movl %eax, %ebp
testl %eax, %eax
jne 0x5fde
leaq 0xb0(%rsp), %rdi
incl 0x18(%rdi)
leaq 0xc(%rsp), %rdx
xorl %esi, %esi
callq 0x814e
leaq 0xb0(%rsp), %rdi
xorl %esi, %esi
movq %r14, %rdx
callq 0x8118
leaq 0x14(%rsp), %rsi
movq %rbx, %rdi
callq 0x560c
movl 0x1c(%rbx), %edx
movl 0x20(%rbx), %ecx
movl 0x24(%rbx), %r8d
leaq 0x70(%rsp), %rdi
movl $0x4, %esi
callq 0x7c7c
leaq 0x128(%rsp), %rdi
leaq 0x70(%rsp), %rsi
callq 0x7d2c
leaq 0x70(%rsp), %rdi
callq 0x7c5a
movq 0x8(%rbx), %rsi
movl 0x14(%rsp), %edx
leaq 0x128(%rsp), %rdi
callq 0x7d3a
movl %eax, %ebp
testl %eax, %eax
jne 0x5fde
leaq 0xb0(%rsp), %rdi
leaq 0x14(%rsp), %rdx
movl $0x1, %esi
callq 0x814e
movq 0x8(%rbx), %rsi
movl 0x28(%rbx), %edx
leaq 0xb0(%rsp), %rdi
callq 0x7d3a
movl %eax, %ebp
testl %eax, %eax
jne 0x5fde
jmp 0x5fda
leaq 0x20(%rsp), %rdi
xorl %esi, %esi
movq %r14, %rdx
callq 0x8118
movl %eax, %ebp
testl %eax, %eax
jne 0x5f97
leaq 0x20(%rsp), %rdi
xorl %esi, %esi
movq 0x18(%rsp), %rdx
callq 0x816c
jmp 0x5f8d
movl 0x38(%rsp), %r12d
addl $-0x2, %r12d
cmpl %r13d, %r12d
jge 0x6011
leaq 0x20(%rsp), %rdi
movl %r13d, %esi
movq %r14, %rdx
callq 0x8118
movl %eax, %ebp
testl %eax, %eax
jne 0x5f97
leaq 0x20(%rsp), %rdi
movl %r13d, %esi
movq 0x18(%rsp), %rdx
callq 0x816c
movl %eax, %ebp
testl %eax, %eax
je 0x60a4
xorl %r14d, %r14d
leaq 0xd8(%rsp), %rdi
callq 0x2e26
leaq 0x100(%rsp), %rdi
callq 0x2e26
leaq 0x70(%rsp), %rdi
callq 0x2e26
movq 0x50(%rsp), %rdi
testq %rdi, %rdi
je 0x5fd5
movq 0x60(%rsp), %rsi
subq %rdi, %rsi
callq 0x21e0
testb %r14b, %r14b
je 0x5fde
movb $0x1, %bl
jmp 0x5fe0
xorl %ebx, %ebx
leaq 0x128(%rsp), %rdi
callq 0x7c5a
leaq 0xb0(%rsp), %rdi
callq 0x7c5a
leaq 0x20(%rsp), %rdi
callq 0x7c5a
testb %bl, %bl
jne 0x5c12
jmp 0x5c14
leaq 0x20(%rsp), %r15
movq %r15, %rdi
movl %r12d, %esi
leaq 0x100(%rsp), %rdx
callq 0x802a
movl %eax, %ebp
testl %eax, %eax
jne 0x5f97
movq %r15, %rdi
movl %r12d, %esi
leaq 0xd8(%rsp), %rdx
callq 0x8096
movl %eax, %ebp
testl %eax, %eax
jne 0x5f97
incl %r12d
movq %r15, %rdi
movl %r12d, %esi
leaq 0x100(%rsp), %rdx
callq 0x8118
movl %eax, %ebp
testl %eax, %eax
jne 0x5f97
movq %r15, %rdi
movl %r12d, %esi
leaq 0xd8(%rsp), %rdx
callq 0x816c
movl %eax, %ebp
testl %eax, %eax
jne 0x5f97
leal -0x1(%r12), %eax
addl $-0x2, %r12d
cmpl %r13d, %eax
jg 0x6016
jmp 0x5f65
movq 0x8(%rbx), %rsi
leaq 0x20(%rsp), %rdi
movl 0x10(%rsp), %edx
callq 0x7d3a
movl 0x40(%rbx), %eax
addl %eax, %eax
movl $0xaaaaaaab, %ecx       # imm = 0xAAAAAAAB
imulq %rax, %rcx
shrq $0x21, %rcx
movb $0x1, %r14b
cmpl %ecx, 0x38(%rsp)
jle 0x6128
leaq 0x50(%rsp), %rsi
movq 0x8(%rsi), %rax
movl -0x4(%rax), %ecx
addq $-0x4, %rax
movl %ecx, 0x4c(%rsp)
movq %rax, 0x8(%rsi)
leaq 0x98(%rsp), %rdi
callq 0x7906
leaq 0x4c(%rsp), %rsi
leaq 0x98(%rsp), %rdx
movq %rbx, %rdi
callq 0x63b4
movq 0x98(%rsp), %rdi
testq %rdi, %rdi
je 0x6128
movq 0xa8(%rsp), %rsi
subq %rdi, %rsi
callq 0x21e0
jmp 0x5f9a
movq %rax, %rbx
movq 0x98(%rsp), %rdi
testq %rdi, %rdi
je 0x6198
movq 0xa8(%rsp), %rsi
subq %rdi, %rsi
callq 0x21e0
jmp 0x6198
jmp 0x6195
jmp 0x6163
jmp 0x6190
jmp 0x6195
jmp 0x6195
movq %rax, %rbx
jmp 0x61a5
movq %rax, %rbx
jmp 0x61b2
movq %rax, %rbx
leaq 0x70(%rsp), %rdi
callq 0x7c5a
jmp 0x61d3
jmp 0x6178
jmp 0x6190
jmp 0x6195
movq %rax, %rbx
jmp 0x61bc
movq %rax, %rbx
jmp 0x61e0
movq %rax, %rbx
jmp 0x61ed
jmp 0x618b
jmp 0x6195
movq %rax, %rbx
jmp 0x61f7
movq %rax, %rbx
jmp 0x61d3
movq %rax, %rbx
leaq 0xd8(%rsp), %rdi
callq 0x2e26
leaq 0x100(%rsp), %rdi
callq 0x2e26
leaq 0x70(%rsp), %rdi
callq 0x2e26
movq 0x50(%rsp), %rdi
testq %rdi, %rdi
je 0x61d3
movq 0x60(%rsp), %rsi
subq %rdi, %rsi
callq 0x21e0
leaq 0x128(%rsp), %rdi
callq 0x7c5a
leaq 0xb0(%rsp), %rdi
callq 0x7c5a
leaq 0x20(%rsp), %rdi
callq 0x7c5a
leaq 0x150(%rsp), %rdi
callq 0x2e26
movq %rbx, %rdi
callq 0x2370