// File: /workspace/github_cpp_makefile_star2_O2/Dwijesh522[P]DBMS_assignment_3/linear_search.cpp
// Function: main
int main(int argc, char **argv) {
    updateFilePaths(argc, argv);
    int integers_per_page = PAGE_CONTENT_SIZE / sizeof(int);
    FileManager fm;
    FileHandler output_handler = fm.CreateFile(output_file_path);
    FileHandler input_handler = fm.OpenFile(input_file_path);
    // by default following page is pinned and marked dirty
    PageHandler output_page_handler = output_handler.NewPage();
    int integers_written_on_output_page = 0;
    // reading query files
    ifstream query_file (query_file_path);
    if (query_file.is_open()) {
        string line;
        int counter = 0; // even counter for backward traversal, odd counter for forward traversal
        int input_last_page_number = getLastPageNumber(input_handler, /*keep pinned*/true);
        while (getline(query_file, line)) {
            int target_number = getSearchValue(line); // value to search for

            // since the input file is sorted, once processed all target values,
            // we need not process the remaining values
            bool found_it = false, query_processed = false;

            // Looping from last page to first page
            try {
                PageHandler curr_page_handler;
                if (counter %2 == 0) curr_page_handler = getLastPageHandler(input_handler, /*keep_pinned*/true);
                else curr_page_handler = getFirstPageHandler(input_handler, /*keep_pinned*/true);
                while (true) {
                    char *data = curr_page_handler.GetData();
                    if (data == nullptr) throw "EmptyFileException: Input file no pages\n";
                    for (int i=sizeof(int)*(integers_per_page-1); i>= 0; i-= sizeof(int)) {
                        // traversing from the last entry of the page to first entry
                        int curr_number;
                        memcpy(&curr_number, &data[i], sizeof(int));
                        if (curr_number == target_number) {
                            found_it = true;
                            // store (page num, offset) into the output file page
                            int curr_page_number = curr_page_handler.GetPageNum();
                            int offset = i/sizeof(int);
                            if (integers_written_on_output_page >= integers_per_page) {
                                output_handler.UnpinPage(output_page_handler.GetPageNum());//so that it can be flushed
                                output_handler.FlushPage(output_page_handler.GetPageNum()); // write otuput page to disk and remove from buffer
                                output_page_handler = output_handler.NewPage();	// create new output page in buffer
                                integers_written_on_output_page = 0; // new page is empty
                            }
                            char *output_data = output_page_handler.GetData();
                            memcpy(&output_data[integers_written_on_output_page * sizeof(int)], &curr_page_number, sizeof(int));
                            ++integers_written_on_output_page;
                            memcpy(&output_data[integers_written_on_output_page * sizeof(int)], &offset, sizeof(int));
                            ++integers_written_on_output_page;
                        }
                    }
                    // since we are done using the current input page, we can unpin it
                    if (query_processed) break;
                    if (curr_page_handler.GetPageNum() == 0 and counter %2 == 0) break; // termination for backward traversal
                    if (curr_page_handler.GetPageNum() == input_last_page_number and counter %2 == 1) break; // termination for forward traversal
                    input_handler.UnpinPage(curr_page_handler.GetPageNum());
                    if (counter %2 == 0) curr_page_handler = input_handler.PrevPage(curr_page_handler.GetPageNum()); // pinned
                    else curr_page_handler = input_handler.NextPage(curr_page_handler.GetPageNum()); // pinned
                }
//                input_handler.UnpinPage(curr_page_handler.GetPageNum());// so that it can be replaced
            }
            catch (exception &e) { }//cout << e.what() << endl; }
            catch (const char *e) { }//cout << e << endl; }
            catch (...) {}// { cout << "Unknown exception occured\n"; }

            // Since we are done with one query, writing (-1, -1) pair in output page
            if (integers_written_on_output_page >= integers_per_page) {
                output_handler.UnpinPage(output_page_handler.GetPageNum());//so that it can be flushed
                output_handler.FlushPage(output_page_handler.GetPageNum()); // write otuput page to disk and remove from buffer
                output_page_handler = output_handler.NewPage();	// create new output page in buffer
                integers_written_on_output_page = 0; // new page is empty
            }
            char *output_data = output_page_handler.GetData();
            memcpy(&output_data[integers_written_on_output_page * sizeof(int)], &MINUS_ONE, sizeof(int));
            ++integers_written_on_output_page;
            memcpy(&output_data[integers_written_on_output_page * sizeof(int)], &MINUS_ONE, sizeof(int));
            ++integers_written_on_output_page;
            ++counter;
        }
        // fill the empty space with int_min
        for (int j=integers_written_on_output_page; j<= integers_per_page; ++j) {
            char *output_data = output_page_handler.GetData();
            memcpy(&output_data[integers_written_on_output_page * sizeof(int)], &int_min, sizeof(int));
            ++integers_written_on_output_page;
        }
    }
    //else cout << "Unable to open query file\n";
    output_handler.UnpinPage(output_page_handler.GetPageNum());//so that it can be flushed
    output_handler.FlushPages(); // flush output pages
    fm.CloseFile (output_handler);
    fm.CloseFile(input_handler);

    // #TODO: following lines are only for debugging. Remove it in final submission
    //char *my_output = "./output_search";
    //char *ta_output = "./TestCases/TC_search/output_search";
    //printAnswers(fm, my_output, "My output");
    //printAnswers(fm, ta_output, "TA output");
    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x2c8, %rsp            # imm = 0x2C8
callq 0x3e3d
leaq -0x48(%rbp), %rbx
movq %rbx, %rdi
callq 0x3ae2
movq 0x409f(%rip), %rdx      # 0x81c8
leaq -0xa0(%rbp), %rdi
movq %rbx, %rsi
callq 0x3b84
movq 0x4079(%rip), %rdx      # 0x81b8
leaq -0xc0(%rbp), %rdi
leaq -0x48(%rbp), %rsi
callq 0x3c22
leaq -0x60(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0x391c
movq 0x405a(%rip), %rsi      # 0x81c0
leaq -0x2e8(%rbp), %rdi
pushq $0x8
popq %rdx
callq 0x22b0
leaq -0x270(%rbp), %rdi
callq 0x2070
testb %al, %al
je 0x4485
leaq -0xd0(%rbp), %rax
movq %rax, -0x10(%rax)
andq $0x0, -0x8(%rax)
movb $0x0, (%rax)
leaq -0xc0(%rbp), %rdi
pushq $0x1
popq %rsi
callq 0x3e6f
movl %eax, -0x7c(%rbp)
movq $0x0, -0x78(%rbp)
xorl %ebx, %ebx
leaq -0x2e8(%rbp), %rdi
leaq -0xe0(%rbp), %rsi
callq 0x2060
movq (%rax), %rcx
movq -0x18(%rcx), %rcx
testb $0x5, 0x20(%rax,%rcx)
jne 0x4455
leaq -0xe0(%rbp), %rdi
callq 0x3db4
movl %eax, %r14d
leaq -0x40(%rbp), %rdi
callq 0x3670
movq -0x78(%rbp), %rax
movl %eax, %r15d
andl $0x1, %r15d
testb $0x1, %al
movl %r15d, -0x80(%rbp)
jne 0x421d
leaq -0x70(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
pushq $0x1
popq %rdx
callq 0x3eba
jmp 0x4230
leaq -0x70(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
pushq $0x1
popq %rdx
callq 0x3ef7
movups -0x70(%rbp), %xmm0
movaps %xmm0, -0x40(%rbp)
leaq -0x40(%rbp), %rdi
callq 0x36b6
movq %rax, %r13
testq %rax, %rax
je 0x436c
pushq $0x14
popq %r15
testl %r15d, %r15d
js 0x42e3
movl %r15d, %eax
cmpl %r14d, (%r13,%rax)
jne 0x42da
leaq -0x40(%rbp), %rdi
callq 0x36c0
movl %eax, %r12d
cmpl $0x6, %ebx
jl 0x42bd
leaq -0x60(%rbp), %rdi
callq 0x36c0
leaq -0xa0(%rbp), %rdi
movl %eax, %esi
callq 0x3902
leaq -0x60(%rbp), %rdi
callq 0x36c0
leaq -0xa0(%rbp), %rdi
movl %eax, %esi
callq 0x3a88
leaq -0x70(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0x391c
movups -0x70(%rbp), %xmm0
movaps %xmm0, -0x60(%rbp)
xorl %ebx, %ebx
leaq -0x60(%rbp), %rdi
callq 0x36b6
movl %r15d, %ecx
shrl $0x2, %ecx
movslq %ebx, %rbx
movl %r12d, (%rax,%rbx,4)
movl %ecx, 0x4(%rax,%rbx,4)
addl $0x2, %ebx
addl $-0x4, %r15d
jmp 0x4251
leaq -0x40(%rbp), %rdi
callq 0x36c0
movl -0x80(%rbp), %r15d
orl %r15d, %eax
je 0x43d7
leaq -0x40(%rbp), %rdi
callq 0x36c0
testl %r15d, %r15d
je 0x4310
cmpl -0x7c(%rbp), %eax
je 0x43d7
leaq -0x40(%rbp), %rdi
callq 0x36c0
leaq -0xc0(%rbp), %rdi
movl %eax, %esi
callq 0x3902
testl %r15d, %r15d
jne 0x434c
leaq -0x40(%rbp), %rdi
callq 0x36c0
leaq -0x70(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
movl %eax, %edx
callq 0x37d8
jmp 0x4230
leaq -0x40(%rbp), %rdi
callq 0x36c0
leaq -0x70(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
movl %eax, %edx
callq 0x3736
jmp 0x4230
pushq $0x8
popq %rdi
callq 0x2120
leaq 0x1043(%rip), %rcx      # 0x53be
movq %rcx, (%rax)
movq %rax, %rdi
movq 0x3c30(%rip), %rsi      # 0x7fb8
xorl %edx, %edx
callq 0x2280
jmp 0x44f1
jmp 0x43a8
jmp 0x43a8
jmp 0x43a8
jmp 0x43a8
jmp 0x43a8
jmp 0x43a8
jmp 0x43a8
jmp 0x43a8
jmp 0x43a8
jmp 0x43a8
movq %rdx, %r14
movq %rax, %rdi
cmpl $0x3, %r14d
jne 0x43c0
callq 0x20d0
callq 0x2260
jmp 0x43d7
callq 0x20d0
cmpl $0x2, %r14d
jne 0x43d2
callq 0x2260
jmp 0x43d7
callq 0x2260
cmpl $0x6, %ebx
jl 0x4424
leaq -0x60(%rbp), %rdi
callq 0x36c0
leaq -0xa0(%rbp), %rdi
movl %eax, %esi
callq 0x3902
leaq -0x60(%rbp), %rdi
callq 0x36c0
leaq -0xa0(%rbp), %rdi
movl %eax, %esi
callq 0x3a88
leaq -0x40(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0x391c
movups -0x40(%rbp), %xmm0
movaps %xmm0, -0x60(%rbp)
xorl %ebx, %ebx
leaq -0x60(%rbp), %rdi
callq 0x36b6
movslq %ebx, %rbx
movl 0x3d52(%rip), %ecx      # 0x8188
movl %ecx, (%rax,%rbx,4)
movl 0x3d49(%rip), %ecx      # 0x8188
movl %ecx, 0x4(%rax,%rbx,4)
addl $0x2, %ebx
movq -0x78(%rbp), %rax
incl %eax
movq %rax, -0x78(%rbp)
jmp 0x41b8
movslq %ebx, %r14
leaq -0x60(%rbp), %rbx
cmpl $0x7, %r14d
jge 0x4479
movq %rbx, %rdi
callq 0x36b6
movl 0x3d1c(%rip), %ecx      # 0x818c
movl %ecx, (%rax,%r14,4)
incq %r14
jmp 0x445c
leaq -0xe0(%rbp), %rdi
callq 0x20f0
leaq -0x60(%rbp), %rdi
callq 0x36c0
leaq -0xa0(%rbp), %rdi
movl %eax, %esi
callq 0x3902
leaq -0xa0(%rbp), %rdi
callq 0x3a3c
leaq -0x48(%rbp), %rdi
leaq -0xa0(%rbp), %rsi
callq 0x3cdc
leaq -0x48(%rbp), %rdi
leaq -0xc0(%rbp), %rsi
callq 0x3cdc
leaq -0x2e8(%rbp), %rdi
callq 0x2080
leaq -0x48(%rbp), %rdi
callq 0x3b58
xorl %eax, %eax
addq $0x2c8, %rsp            # imm = 0x2C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x450f
jmp 0x450f
jmp 0x44fb
jmp 0x44fb
jmp 0x44fb
movq %rax, %rbx
jmp 0x452a
movq %rax, %rbx
jmp 0x451e
jmp 0x450f
jmp 0x450f
jmp 0x450f
jmp 0x450f
jmp 0x450f
movq %rax, %rbx
leaq -0xe0(%rbp), %rdi
callq 0x20f0
leaq -0x2e8(%rbp), %rdi
callq 0x2080
leaq -0x48(%rbp), %rdi
callq 0x3b58
movq %rbx, %rdi
callq 0x22a0