// File: m0Mh42[P]mash/./src/main.cpp
// Function: main
int main(int argc, char* argv[]) {

    // Filename is a must
    if (argc < 2){
        cout << "Usage: " << endl << argv[0] << " [file] [difficulty]" << endl;
        exit(NOFILE);
    }

    // Checking difficulty declaration
    if (argc > 2){
        difficulty_set(argv[2]);
    }

    string filename = argv[1];
    
    // File object
    File file;
    file.open_file(filename);

    // Mashing Object
    Mash mash;

    // Random seed
    mash.rand_seed();

    // Calculating chunk size.
    unsigned long len = file.get_file_length();
    unsigned long chunksize = len / 32;

    // Mashtree Object
    Mashtree mashtree(chunksize);
    string chunk = "";
    file.is_eof = false;

    signal(SIGINT, intsig);

    while (true){
        for (uint l = 0; l < 2; l++){
            if (!file.is_eof){
                chunk = file.read_chunk();
                mashtree.add_node(chunk);
            }
        }
        if (mashtree.tree_size > 1)
            mashtree.mash_k_matching_nodes();
        else
            break;
        if (file.is_eof && mashtree.tree_size > 1){
            mashtree.mash_remaining();
            break;
        }
    }

    // we don't need the file anymore, so we close it.
    file.close_file();

    // We get the resulted mash node, so we can mash it again, without using the nodetree.
    MashNode mashnode = mashtree.return_result();

    // And then we delete the nodetree to free memory.
    mashtree.delete_nodetree();

    // cout << endl << "Size of mashnode: " << sizeof(MashNode) << endl;
    // cout << "Size of mashtree: " << (sizeof(MashNode) * (chunksize)) << endl;
    // cout << "Size of mash class: " << sizeof(Mash) << endl;
    // cout << "Size of Mashtree class: " << sizeof(Mashtree) << endl;

    // Some initializations
    double microsecs = 0;
    run = true;
    string out;
    u_long count = 0;

    while (run) {
        // Measuring time taken to mash
        auto t1 = high_resolution_clock::now();

        mashnode = mash.mash(mashnode);

        auto t2 = high_resolution_clock::now();
        auto duration = duration_cast<microseconds>(t2 - t1);
        microsecs += duration.count();

        out = string_to_hex(mashnode.value);
        check_output(out);

        count++;
    }

    cout << endl << "Time taken by Mashing: " << (microsecs / 1000) << "ms" << endl;
    cout << "Count: " << count << endl;
    cout << "Exiting..." << endl;

    return 0;
}

// Assembly:
subq $0x4f8, %rsp            # imm = 0x4F8
movl $0x0, 0x4f4(%rsp)
movl %edi, 0x4f0(%rsp)
movq %rsi, 0x4e8(%rsp)
cmpl $0x2, 0x4f0(%rsp)
jge 0x2ab5
movq 0x456e(%rip), %rdi      # 0x6fd0
leaq 0x2656(%rip), %rsi      # 0x50bf
callq 0x21f0
movq %rax, %rdi
movq 0x4548(%rip), %rsi      # 0x6fc0
callq 0x2220
movq %rax, %rdi
movq 0x4e8(%rsp), %rax
movq (%rax), %rsi
callq 0x21f0
movq %rax, %rdi
leaq 0x262d(%rip), %rsi      # 0x50c7
callq 0x21f0
movq %rax, %rdi
movq 0x4517(%rip), %rsi      # 0x6fc0
callq 0x2220
xorl %edi, %edi
callq 0x2290
cmpl $0x2, 0x4f0(%rsp)
jle 0x2ad0
movq 0x4e8(%rsp), %rax
movq 0x10(%rax), %rdi
callq 0x2820
movq 0x4e8(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, 0x88(%rsp)
leaq 0x4c7(%rsp), %rdi
movq %rdi, 0x90(%rsp)
callq 0x23e0
movq 0x88(%rsp), %rsi
movq 0x90(%rsp), %rdx
leaq 0x4c8(%rsp), %rdi
callq 0x32a0
jmp 0x2b18
leaq 0x4c7(%rsp), %rdi
callq 0x2240
leaq 0x270(%rsp), %rdi
callq 0x3370
jmp 0x2b34
leaq 0x250(%rsp), %rdi
leaq 0x4c8(%rsp), %rsi
callq 0x20f0
jmp 0x2b4b
leaq 0x270(%rsp), %rdi
leaq 0x250(%rsp), %rsi
callq 0x47c0
jmp 0x2b62
leaq 0x250(%rsp), %rdi
callq 0x2130
leaq 0x238(%rsp), %rdi
callq 0x40c0
jmp 0x2b7e
leaq 0x270(%rsp), %rdi
callq 0x49e0
movq %rax, 0x80(%rsp)
jmp 0x2b95
movq 0x80(%rsp), %rax
movq %rax, 0x230(%rsp)
movq 0x230(%rsp), %rax
shrq $0x5, %rax
movq %rax, 0x228(%rsp)
movl 0x228(%rsp), %esi
leaq 0x200(%rsp), %rdi
callq 0x4100
jmp 0x2bcf
leaq 0x1df(%rsp), %rdi
movq %rdi, 0x78(%rsp)
callq 0x23e0
movq 0x78(%rsp), %rdx
leaq 0x2572(%rip), %rsi      # 0x515f
leaq 0x1e0(%rsp), %rdi
callq 0x32a0
jmp 0x2bfc
leaq 0x1df(%rsp), %rdi
callq 0x2240
movb $0x0, 0x270(%rsp)
movl $0x2, %edi
leaq -0x60d(%rip), %rsi      # 0x2610
callq 0x2280
jmp 0x2c24
movl $0x0, 0x1d8(%rsp)
cmpl $0x2, 0x1d8(%rsp)
jae 0x2d79
testb $0x1, 0x270(%rsp)
jne 0x2d61
leaq 0x1b8(%rsp), %rdi
leaq 0x270(%rsp), %rsi
callq 0x4870
jmp 0x2c62
leaq 0x1e0(%rsp), %rdi
movq %rdi, 0x70(%rsp)
leaq 0x1b8(%rsp), %rsi
movq %rsi, 0x68(%rsp)
callq 0x22a0
movq 0x68(%rsp), %rdi
callq 0x2130
movq 0x70(%rsp), %rsi
leaq 0x200(%rsp), %rdi
callq 0x4220
jmp 0x2c9f
jmp 0x2d61
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4b8(%rsp)
movl %eax, 0x4b4(%rsp)
leaq 0x4c7(%rsp), %rdi
callq 0x2240
jmp 0x31c4
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4b8(%rsp)
movl %eax, 0x4b4(%rsp)
jmp 0x31b7
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4b8(%rsp)
movl %eax, 0x4b4(%rsp)
jmp 0x31aa
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4b8(%rsp)
movl %eax, 0x4b4(%rsp)
leaq 0x250(%rsp), %rdi
callq 0x2130
jmp 0x31aa
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4b8(%rsp)
movl %eax, 0x4b4(%rsp)
leaq 0x1df(%rsp), %rdi
callq 0x2240
jmp 0x31aa
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4b8(%rsp)
movl %eax, 0x4b4(%rsp)
jmp 0x319d
jmp 0x2d63
movl 0x1d8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x1d8(%rsp)
jmp 0x2c2f
cmpl $0x1, 0x200(%rsp)
jbe 0x2d94
leaq 0x200(%rsp), %rdi
callq 0x4330
jmp 0x2d92
jmp 0x2d96
jmp 0x2dc0
testb $0x1, 0x270(%rsp)
je 0x2dbb
cmpl $0x1, 0x200(%rsp)
jbe 0x2dbb
leaq 0x200(%rsp), %rdi
callq 0x44d0
jmp 0x2db9
jmp 0x2dc0
jmp 0x2c22
leaq 0x270(%rsp), %rdi
callq 0x4830
jmp 0x2dcf
leaq 0x188(%rsp), %rdi
leaq 0x200(%rsp), %rsi
callq 0x4630
jmp 0x2de6
leaq 0x200(%rsp), %rdi
callq 0x4660
jmp 0x2df5
xorps %xmm0, %xmm0
movsd %xmm0, 0x180(%rsp)
movb $0x1, 0x443b(%rip)      # 0x7243
leaq 0x160(%rsp), %rdi
callq 0x2300
movq $0x0, 0x158(%rsp)
testb $0x1, 0x441b(%rip)      # 0x7243
je 0x3034
callq 0x2060
movq %rax, 0x150(%rsp)
leaq 0xf0(%rsp), %rdi
leaq 0x188(%rsp), %rsi
callq 0x33b0
jmp 0x2e52
leaq 0x120(%rsp), %rdi
leaq 0x238(%rsp), %rsi
leaq 0xf0(%rsp), %rdx
callq 0x3ed0
jmp 0x2e71
leaq 0x188(%rsp), %rdi
leaq 0x120(%rsp), %rsi
movq %rsi, 0x58(%rsp)
callq 0x3400
movq 0x58(%rsp), %rdi
callq 0x3450
leaq 0xf0(%rsp), %rdi
callq 0x3450
callq 0x2060
movq %rax, 0xe8(%rsp)
leaq 0xe8(%rsp), %rdi
leaq 0x150(%rsp), %rsi
callq 0x34a0
movq %rax, 0x60(%rsp)
jmp 0x2ecb
movq 0x60(%rsp), %rax
movq %rax, 0xd8(%rsp)
leaq 0xd8(%rsp), %rdi
callq 0x3470
movq %rax, 0x50(%rsp)
jmp 0x2eec
movq 0x50(%rsp), %rax
movq %rax, 0xe0(%rsp)
leaq 0xe0(%rsp), %rdi
callq 0x34f0
movq %rax, 0x48(%rsp)
jmp 0x2f0d
movq 0x48(%rsp), %rax
cvtsi2sd %rax, %xmm1
movsd 0x180(%rsp), %xmm0
addsd %xmm1, %xmm0
movsd %xmm0, 0x180(%rsp)
leaq 0x190(%rsp), %rsi
leaq 0xb8(%rsp), %rdi
callq 0x2650
jmp 0x2f44
leaq 0x160(%rsp), %rdi
movq %rdi, 0x40(%rsp)
leaq 0xb8(%rsp), %rsi
movq %rsi, 0x38(%rsp)
callq 0x22a0
movq 0x38(%rsp), %rdi
callq 0x2130
movq 0x40(%rsp), %rsi
leaq 0x98(%rsp), %rdi
callq 0x20f0
jmp 0x2f81
leaq 0x98(%rsp), %rdi
callq 0x2770
jmp 0x2f90
leaq 0x98(%rsp), %rdi
callq 0x2130
movq 0x158(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x158(%rsp)
jmp 0x2e21
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4b8(%rsp)
movl %eax, 0x4b4(%rsp)
jmp 0x3190
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4b8(%rsp)
movl %eax, 0x4b4(%rsp)
jmp 0x3183
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4b8(%rsp)
movl %eax, 0x4b4(%rsp)
leaq 0xf0(%rsp), %rdi
callq 0x3450
jmp 0x3183
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x4b8(%rsp)
movl %eax, 0x4b4(%rsp)
leaq 0x98(%rsp), %rdi
callq 0x2130
jmp 0x3183
movq 0x3f95(%rip), %rdi      # 0x6fd0
movq 0x3f7e(%rip), %rsi      # 0x6fc0
callq 0x2220
movq %rax, 0x30(%rsp)
jmp 0x304e
movq 0x30(%rsp), %rdi
leaq 0x2082(%rip), %rsi      # 0x50dc
callq 0x21f0
movq %rax, 0x28(%rsp)
jmp 0x3066
movq 0x28(%rsp), %rdi
movsd 0x180(%rsp), %xmm0
movsd 0x1f9c(%rip), %xmm1     # 0x5018
divsd %xmm1, %xmm0
callq 0x2410
movq %rax, 0x20(%rsp)
jmp 0x308c
movq 0x20(%rsp), %rdi
leaq 0x205c(%rip), %rsi      # 0x50f4
callq 0x21f0
movq %rax, 0x18(%rsp)
jmp 0x30a4
movq 0x18(%rsp), %rdi
movq 0x3f10(%rip), %rsi      # 0x6fc0
callq 0x2220
jmp 0x30b7
movq 0x3f12(%rip), %rdi      # 0x6fd0
leaq 0x2032(%rip), %rsi      # 0x50f7
callq 0x21f0
movq %rax, 0x10(%rsp)
jmp 0x30d1
movq 0x10(%rsp), %rdi
movq 0x158(%rsp), %rsi
callq 0x2090
movq %rax, 0x8(%rsp)
jmp 0x30ea
movq 0x8(%rsp), %rdi
movq 0x3eca(%rip), %rsi      # 0x6fc0
callq 0x2220
jmp 0x30fd
movq 0x3ecc(%rip), %rdi      # 0x6fd0
leaq 0x1ff4(%rip), %rsi      # 0x50ff
callq 0x21f0
movq %rax, (%rsp)
jmp 0x3116
movq (%rsp), %rdi
movq 0x3e9f(%rip), %rsi      # 0x6fc0
callq 0x2220
jmp 0x3128
movl $0x0, 0x4f4(%rsp)
leaq 0x160(%rsp), %rdi
callq 0x2130
leaq 0x188(%rsp), %rdi
callq 0x3450
leaq 0x1e0(%rsp), %rdi
callq 0x2130
leaq 0x270(%rsp), %rdi
callq 0x3500
leaq 0x4c8(%rsp), %rdi
callq 0x2130
movl 0x4f4(%rsp), %eax
addq $0x4f8, %rsp            # imm = 0x4F8
retq
leaq 0x160(%rsp), %rdi
callq 0x2130
leaq 0x188(%rsp), %rdi
callq 0x3450
leaq 0x1e0(%rsp), %rdi
callq 0x2130
leaq 0x270(%rsp), %rdi
callq 0x3500
leaq 0x4c8(%rsp), %rdi
callq 0x2130
movq 0x4b8(%rsp), %rdi
callq 0x23d0
nopw %cs:(%rax,%rax)
nopl (%rax,%rax)