// File: /workspace/github_cpp_makefile_star2_O1/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, %r13
movq %rsi, %r14
movq %rdi, %rbx
leaq 0x140(%rsp), %r15
movq %r15, %rdi
callq 0x2c54
leaq 0x28(%rbx), %r12
movq %rbx, %rdi
movq %r12, %rsi
movl $0x3, %edx
movq %r14, %rcx
movq %r15, %r8
callq 0x59ca
cmpl $-0x9, %eax
je 0x5c55
movl $0xfffffff0, %ebp       # imm = 0xFFFFFFF0
testl %eax, %eax
je 0x5c34
xorl %ebp, %ebp
leaq 0x140(%rsp), %rdi
callq 0x2e22
movl %ebp, %eax
addq $0x168, %rsp            # imm = 0x168
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x10(%rsp), %rdi
callq 0x7d2a
leaq 0xa0(%rsp), %rdi
callq 0x7d2a
movq %r13, 0x38(%rsp)
leaq 0x118(%rsp), %rdi
callq 0x7d2a
movl 0x28(%rbx), %ebp
movq 0x8(%rbx), %rsi
leaq 0xa0(%rsp), %rdi
movl %ebp, %edx
callq 0x7eee
movb $0x0, 0x44(%rbx)
leaq 0xa0(%rsp), %rdi
cmpl $0x0, 0x18(%rdi)
setne 0x44(%rbx)
movq 0x8(%rbx), %rsi
movl %ebp, %edx
callq 0x7e28
cmpb $0x0, 0x44(%rbx)
je 0x5cec
xorps %xmm0, %xmm0
movaps %xmm0, 0x40(%rsp)
movq $0x0, 0x50(%rsp)
movq 0x48(%rsp), %rsi
testq %rsi, %rsi
je 0x5e74
movl (%r12), %eax
movl %eax, (%rsi)
addq $0x4, %rsi
movq %rsi, 0x48(%rsp)
jmp 0x5e81
movb $0x1, 0x44(%rbx)
leaq 0x8(%rsp), %rsi
movq %rbx, %rdi
callq 0x5630
movl 0x1c(%rbx), %edx
movl 0x20(%rbx), %ecx
movl 0x24(%rbx), %r8d
leaq 0x60(%rsp), %rdi
movl $0x4, %esi
callq 0x7d5c
leaq 0x10(%rsp), %rdi
leaq 0x60(%rsp), %rsi
callq 0x7e1a
leaq 0x60(%rsp), %rdi
callq 0x7d3a
movq 0x8(%rbx), %rsi
movl 0x8(%rsp), %edx
leaq 0x10(%rsp), %rdi
callq 0x7e28
movq 0x8(%rbx), %rsi
movl 0x8(%rsp), %edx
leaq 0x10(%rsp), %rdi
callq 0x7eee
movl %eax, %ebp
testl %eax, %eax
jne 0x616f
leaq 0x10(%rsp), %rdi
incl 0x18(%rdi)
xorl %esi, %esi
movq %r14, %rdx
callq 0x8202
leaq 0x10(%rsp), %rdi
xorl %esi, %esi
movq 0x38(%rsp), %rdx
callq 0x8256
movq 0x8(%rbx), %rsi
movl 0x8(%rsp), %edx
leaq 0x10(%rsp), %rdi
callq 0x7e28
movq 0x8(%rbx), %rsi
movl 0x28(%rbx), %edx
leaq 0xa0(%rsp), %rdi
callq 0x7eee
movl %eax, %ebp
testl %eax, %eax
jne 0x616f
leaq 0xa0(%rsp), %rdi
incl 0x18(%rdi)
leaq 0x8(%rsp), %rdx
xorl %esi, %esi
callq 0x8238
leaq 0xa0(%rsp), %rdi
xorl %esi, %esi
movq %r14, %rdx
callq 0x8202
leaq 0xc(%rsp), %rsi
movq %rbx, %rdi
callq 0x5630
movl 0x1c(%rbx), %edx
movl 0x20(%rbx), %ecx
movl 0x24(%rbx), %r8d
leaq 0x60(%rsp), %rdi
movl $0x4, %esi
callq 0x7d5c
leaq 0x118(%rsp), %rdi
leaq 0x60(%rsp), %rsi
callq 0x7e1a
leaq 0x60(%rsp), %rdi
callq 0x7d3a
movq 0x8(%rbx), %rsi
movl 0xc(%rsp), %edx
leaq 0x118(%rsp), %rdi
callq 0x7e28
movl %eax, %ebp
testl %eax, %eax
jne 0x616f
leaq 0xa0(%rsp), %rdi
leaq 0xc(%rsp), %rdx
movl $0x1, %esi
callq 0x8238
movq 0x8(%rbx), %rsi
movl 0x28(%rbx), %edx
leaq 0xa0(%rsp), %rdi
callq 0x7e28
movl %eax, %ebp
testl %eax, %eax
jne 0x616f
jmp 0x616b
leaq 0x40(%rsp), %rdi
movq %r12, %rdx
callq 0x7a66
leaq 0x40(%rsp), %rcx
movq %rbx, %rdi
movq %r12, %rsi
movq %r14, %rdx
callq 0x62a4
movq 0x48(%rsp), %rax
movl -0x4(%rax), %ecx
addq $-0x4, %rax
movl %ecx, 0x8(%rsp)
movq %rax, 0x48(%rsp)
leaq 0x60(%rsp), %rdi
callq 0x2c54
leaq 0xf0(%rsp), %rdi
callq 0x2c54
leaq 0xc8(%rsp), %rdi
callq 0x2c54
movq 0x8(%rbx), %rsi
movl 0x8(%rsp), %edx
leaq 0x10(%rsp), %rdi
callq 0x7eee
movl 0x28(%rsp), %eax
leal 0x1(%rax), %ecx
movl %ecx, 0x28(%rsp)
testl %eax, %eax
je 0x5f00
xorl %r12d, %r12d
cmpl $0x1, 0x28(%rsp)
jne 0x5f39
movb $0x1, %r13b
jmp 0x6053
leaq 0x10(%rsp), %rdi
xorl %esi, %esi
movq %r14, %rdx
callq 0x8202
movl %eax, %ebp
testl %eax, %eax
jne 0x6128
leaq 0x10(%rsp), %rdi
xorl %esi, %esi
movq 0x38(%rsp), %rdx
callq 0x8256
movl %eax, %ebp
testl %eax, %eax
jne 0x6128
jmp 0x60a2
leaq 0x60(%rsp), %r15
leaq 0x10(%rsp), %rdi
movl %r12d, %esi
movq %r15, %rdx
callq 0x8114
movl %eax, %ebp
testl %eax, %eax
sete %r13b
jne 0x6053
movq %r14, %rdi
movq %r15, %rsi
callq 0x2ebc
testb %al, %al
jne 0x5f7e
incl %r12d
movl 0x28(%rsp), %eax
decl %eax
cmpl %eax, %r12d
jb 0x5f3e
jmp 0x6053
movl 0x28(%rsp), %r13d
addl $-0x2, %r13d
cmpl %r12d, %r13d
setl %r15b
jge 0x5fbf
testb $0x1, %r15b
je 0x6050
leaq 0x10(%rsp), %rdi
movl %r12d, %esi
movq %r14, %rdx
callq 0x8202
movb $0x1, %r15b
testl %eax, %eax
je 0x61a2
xorl %r13d, %r13d
movl %eax, %ebp
jmp 0x6056
leaq 0x10(%rsp), %rdi
movl %r13d, %esi
leaq 0xf0(%rsp), %rdx
callq 0x8114
movl %eax, %ebp
testl %eax, %eax
jne 0x5f90
leaq 0x10(%rsp), %rdi
movl %r13d, %esi
leaq 0xc8(%rsp), %rdx
callq 0x8180
movl %eax, %ebp
testl %eax, %eax
jne 0x5f90
incl %r13d
leaq 0x10(%rsp), %rdi
movl %r13d, %esi
leaq 0xf0(%rsp), %rdx
callq 0x8202
movl %eax, %ebp
testl %eax, %eax
jne 0x5f90
leaq 0x10(%rsp), %rdi
movl %r13d, %esi
leaq 0xc8(%rsp), %rdx
callq 0x8256
movl %eax, %ebp
testl %eax, %eax
jne 0x5f90
leal -0x1(%r13), %eax
addl $-0x2, %r13d
cmpl %r12d, %eax
setle %r15b
jg 0x5fbf
jmp 0x5f90
xorl %r13d, %r13d
xorl %r15d, %r15d
testb %r13b, %r13b
je 0x6064
testb %r15b, %r15b
je 0x6068
movb $0x1, %cl
jmp 0x609a
xorl %ecx, %ecx
jmp 0x609a
leaq 0x10(%rsp), %rdi
movl 0x18(%rdi), %esi
decl %esi
movq %r14, %rdx
callq 0x8202
testl %eax, %eax
jne 0x6096
leaq 0x10(%rsp), %rdi
movl 0x18(%rdi), %esi
decl %esi
movq 0x38(%rsp), %rdx
callq 0x8256
testl %eax, %eax
je 0x6060
xorl %ecx, %ecx
movl %eax, %ebp
testb %cl, %cl
je 0x6128
movq 0x8(%rbx), %rsi
movl 0x8(%rsp), %edx
leaq 0x10(%rsp), %rdi
callq 0x7e28
movl 0x40(%rbx), %eax
addl %eax, %eax
movl $0xaaaaaaab, %ecx       # imm = 0xAAAAAAAB
imulq %rax, %rcx
shrq $0x21, %rcx
movb $0x1, %r14b
cmpl %ecx, 0x28(%rsp)
jle 0x612b
leaq 0x40(%rsp), %rsi
movq 0x8(%rsi), %rax
movl -0x4(%rax), %ecx
addq $-0x4, %rax
movl %ecx, 0x5c(%rsp)
movq %rax, 0x8(%rsi)
leaq 0x88(%rsp), %rdi
callq 0x79e6
leaq 0x5c(%rsp), %rsi
leaq 0x88(%rsp), %rdx
movq %rbx, %rdi
callq 0x6452
movq 0x88(%rsp), %rdi
testq %rdi, %rdi
je 0x612b
movq 0x98(%rsp), %rsi
subq %rdi, %rsi
callq 0x21e0
jmp 0x612b
xorl %r14d, %r14d
leaq 0xc8(%rsp), %rdi
callq 0x2e22
leaq 0xf0(%rsp), %rdi
callq 0x2e22
leaq 0x60(%rsp), %rdi
callq 0x2e22
movq 0x40(%rsp), %rdi
testq %rdi, %rdi
je 0x6166
movq 0x50(%rsp), %rsi
subq %rdi, %rsi
callq 0x21e0
testb %r14b, %r14b
je 0x616f
movb $0x1, %bl
jmp 0x6171
xorl %ebx, %ebx
leaq 0x118(%rsp), %rdi
callq 0x7d3a
leaq 0xa0(%rsp), %rdi
callq 0x7d3a
leaq 0x10(%rsp), %rdi
callq 0x7d3a
testb %bl, %bl
jne 0x5c32
jmp 0x5c34
leaq 0x10(%rsp), %rdi
movl %r12d, %esi
movq 0x38(%rsp), %rdx
callq 0x8256
testl %eax, %eax
sete %r13b
cmovnel %eax, %ebp
jmp 0x6056
jmp 0x6228
jmp 0x61fb
jmp 0x6268
movq %rax, %rbx
movq 0x88(%rsp), %rdi
testq %rdi, %rdi
je 0x622b
movq 0x98(%rsp), %rsi
subq %rdi, %rsi
callq 0x21e0
jmp 0x622b
jmp 0x6228
jmp 0x6228
movq %rax, %rbx
jmp 0x6238
movq %rax, %rbx
jmp 0x6245
movq %rax, %rbx
leaq 0x60(%rsp), %rdi
callq 0x7d3a
jmp 0x626b
jmp 0x6210
jmp 0x6268
jmp 0x6228
movq %rax, %rbx
jmp 0x624f
jmp 0x6228
movq %rax, %rbx
jmp 0x6278
movq %rax, %rbx
jmp 0x6285
jmp 0x6223
movq %rax, %rbx
jmp 0x628f
movq %rax, %rbx
leaq 0xc8(%rsp), %rdi
callq 0x2e22
leaq 0xf0(%rsp), %rdi
callq 0x2e22
leaq 0x60(%rsp), %rdi
callq 0x2e22
movq 0x40(%rsp), %rdi
testq %rdi, %rdi
je 0x626b
movq 0x50(%rsp), %rsi
subq %rdi, %rsi
callq 0x21e0
jmp 0x626b
movq %rax, %rbx
leaq 0x118(%rsp), %rdi
callq 0x7d3a
leaq 0xa0(%rsp), %rdi
callq 0x7d3a
leaq 0x10(%rsp), %rdi
callq 0x7d3a
leaq 0x140(%rsp), %rdi
callq 0x2e22
movq %rbx, %rdi
callq 0x2370