// File: /workspace/github_cpp_makefile_star2_O3/dm4[P]huffman-homework/my_encode.cc
// Function: main
int main(int argc, const char *argv[]) {
    if (argc != 3) {
        fprintf(stderr, "Usage:\n");
        fprintf(stderr, "    %s input.txt output.bin\n", argv[0]);
        exit(1);
    }

    // Read input
    printf("Read input file: %s\n", argv[1]);
    map<char, int> count;
    FILE *fp = fopen(argv[1], "rb");
    if (fp == NULL) {
        fprintf(stderr, "Invalid file: %s\n", argv[1]);
        exit(1);
    }
    while(!feof(fp)) {
        char c;
        int size = fread(&c, 1, 1, fp);
        if (size == 0)
            break;
        count[c]++;
    }
    count['\0']++;

    // sort and convert to symbolCount
    map<char, int>::iterator it;
    for (it = count.begin(); it != count.end(); it++) {
        BuildCL *tmp = (BuildCL *)malloc(sizeof(BuildCL));
        tmp->symbol = it->first;
        tmp->count  = it->second;
        symbolCount.push_back(tmp);
    }
    sort(symbolCount.begin(), symbolCount.end(), sortByCountDescending);

    // print
    if (DEBUG) {
        for (int i = 0; i < symbolCount.size(); i++) {
            printf("%3d => %d\n", symbolCount[i]->symbol, symbolCount[i]->count);
        }
    }

    // merge to build CLRecord
    int CLRIndex = 0;
    while(symbolCount.size() > 1) {
        int size = symbolCount.size();
        BuildCL *s1 = symbolCount[size - 1];
        BuildCL *s2 = symbolCount[size - 2];
        BuildCL *newS = (BuildCL *)malloc(sizeof(BuildCL));
        newS->count = s1->count + s2->count;
        newS->symbol = ~CLRIndex;
        CLRIndex++;
        symbolCount.pop_back();
        symbolCount.pop_back();
        symbolCount.push_back(newS);
        sort(symbolCount.begin(), symbolCount.end(), sortByCountDescending);
        CLRecordEntry *entry = (CLRecordEntry *)malloc(sizeof(CLRecordEntry));
        entry->s1 = s1->symbol;
        entry->s2 = s2->symbol;
        entry->cl = 0;
        CLRecord.push_back(entry);
        free(s1);
        free(s2);
    }
    free(symbolCount[0]);
    symbolCount.pop_back();

    assignCL();
    buildSymbols();
    sort(symbols.begin(), symbols.end(), sortSymbolsByCL);
    buildSymbolsCodeword();
    buildSymbolsMap();

    // open output file
    printf("Open output file: %s\n", argv[2]);
    FILE *fout = fopen(argv[2], "wb");
    if (fout == NULL) {
        fprintf(stderr, "Couldn't open file: %s\n", argv[2]);
        exit(1);
    }

    // write symbols
    char n = symbols.size();
    fwrite(&n, sizeof(char), 1, fout);
    for (int i = 0; i < symbols.size(); i++) {
        fwrite(symbols[i], sizeof(Symbol), 1, fout);
    }

    // read from start of input file
    fseek(fp, 0, SEEK_SET);
    unsigned int buf = 0;
    int bufLen = 0;
    while(!feof(fp)) {
        char c;
        int size = fread(&c, 1, 1, fp);
        if (size == 0)
            break;
        Symbol *s = symbolsMap[c];
        appendBuffer(&buf, bufLen, s->codeword, s->cl);
        bufLen += s->cl;
        while (bufLen >= 8) {
            unsigned int remain = buf >> 24;
            char r = remain;
            fwrite(&r, sizeof(char), 1, fout);
            buf <<= 8;
            bufLen -= 8;
        }
    }
    Symbol *s = symbolsMap[0];
    appendBuffer(&buf, bufLen, s->codeword, s->cl);
    bufLen += s->cl;
    while (bufLen > 0) {
        unsigned int remain = buf >> 24;
        char r = remain;
        fwrite(&r, sizeof(char), 1, fout);
        buf <<= 8;
        bufLen -= 8;
    }

    fclose(fp);
    fclose(fout);

    // print
    if (DEBUG) {
        for (int i = 0; i < symbols.size(); i++) {
            printf("symbol %d\tcl %d\t", symbols[i]->symbol, symbols[i]->cl);
            p(symbols[i]->codeword, symbols[i]->cl);
        }
    }

    // free memory
    for (int i = 0; i < CLRecord.size(); i++) {
        free(CLRecord[i]);
    }
    for (int i = 0; i < symbols.size(); i++) {
        free(symbols[i]);
    }

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movq %rsi, %r12
cmpl $0x3, %edi
jne 0x1cda
movq 0x8(%r12), %rsi
leaq 0x2904(%rip), %rdi      # 0x4048
xorl %r14d, %r14d
xorl %eax, %eax
callq 0x1030
leaq -0x70(%rbp), %rbx
movl $0x0, (%rbx)
movq %r14, 0x8(%rbx)
movq %rbx, 0x10(%rbx)
movq %rbx, 0x18(%rbx)
movq %r14, 0x20(%rbx)
movq 0x8(%r12), %rdi
leaq 0x28e9(%rip), %rsi      # 0x405d
callq 0x1110
testq %rax, %rax
je 0x1ce2
movq %rax, %r13
movq %rax, %rdi
callq 0x11a0
testl %eax, %eax
jne 0x17cb
leaq -0x30(%rbp), %r14
leaq -0x78(%rbp), %r15
movl $0x1, %esi
movl $0x1, %edx
movq %r14, %rdi
movq %r13, %rcx
callq 0x1190
testl %eax, %eax
je 0x17cb
movq %r15, %rdi
movq %r14, %rsi
callq 0x1dea
incl (%rax)
movq %r13, %rdi
callq 0x11a0
testl %eax, %eax
je 0x1799
movq %r12, -0x38(%rbp)
leaq -0x30(%rbp), %rsi
movb $0x0, (%rsi)
leaq -0x78(%rbp), %rdi
callq 0x1e52
incl (%rax)
movq -0x60(%rbp), %r14
cmpq %rbx, %r14
je 0x1849
leaq 0x5927(%rip), %r15      # 0x7118
leaq -0x30(%rbp), %r12
movl $0x8, %edi
callq 0x1150
movq %rax, -0x30(%rbp)
movsbl 0x20(%r14), %ecx
movl %ecx, (%rax)
movl 0x24(%r14), %ecx
movl %ecx, 0x4(%rax)
movq 0x5908(%rip), %rsi      # 0x7120
cmpq 0x5909(%rip), %rsi      # 0x7128
je 0x182e
movq %rax, (%rsi)
addq $0x8, 0x58f4(%rip)      # 0x7120
jmp 0x1839
movq %r15, %rdi
movq %r12, %rdx
callq 0x25e6
movq %r14, %rdi
callq 0x1090
movq %rax, %r14
cmpq %rbx, %rax
jne 0x17f5
movq %r13, -0x40(%rbp)
movq 0x58c4(%rip), %r13      # 0x7118
movq 0x58c5(%rip), %r14      # 0x7120
cmpq %r14, %r13
je 0x18a9
movq %r14, %rax
subq %r13, %rax
sarq $0x3, %rax
bsrq %rax, %rdx
xorl $0x3f, %edx
addl %edx, %edx
xorq $0x7e, %rdx
leaq -0x3f2(%rip), %rcx      # 0x148c
movq %r13, %rdi
movq %r14, %rsi
callq 0x2726
leaq -0x404(%rip), %rdx      # 0x148c
movq %r13, %rdi
movq %r14, %rsi
callq 0x2851
movq 0x587e(%rip), %r14      # 0x7120
movq 0x586f(%rip), %r13      # 0x7118
movq %r14, %rax
subq %r13, %rax
cmpq $0x9, %rax
jb 0x1a15
movl $0xffffffff, %r15d      # imm = 0xFFFFFFFF
shlq $0x1d, %rax
movabsq $-0x100000000, %rcx     # imm = 0xFFFFFFFF00000000
addq %rax, %rcx
sarq $0x1d, %rcx
movq (%r13,%rcx), %r12
movabsq $-0x200000000, %rcx     # imm = 0xFFFFFFFE00000000
addq %rcx, %rax
sarq $0x1d, %rax
movq (%r13,%rax), %r13
movl $0x8, %edi
callq 0x1150
movq %rax, -0x30(%rbp)
movl 0x4(%r13), %ecx
addl 0x4(%r12), %ecx
movl %ecx, 0x4(%rax)
movl %r15d, (%rax)
addq $-0x10, %r14
movq %r14, 0x5809(%rip)      # 0x7120
cmpq 0x580a(%rip), %r14      # 0x7128
je 0x1937
movq %rax, (%r14)
movq 0x57f6(%rip), %r14      # 0x7120
addq $0x8, %r14
movq %r14, 0x57eb(%rip)      # 0x7120
jmp 0x1951
leaq 0x57da(%rip), %rdi      # 0x7118
movq %r14, %rsi
leaq -0x30(%rbp), %rdx
callq 0x25e6
movq 0x57cf(%rip), %r14      # 0x7120
movq 0x57c0(%rip), %rbx      # 0x7118
cmpq %r14, %rbx
je 0x1998
movq %r14, %rax
subq %rbx, %rax
sarq $0x3, %rax
bsrq %rax, %rdx
xorl $0x3f, %edx
addl %edx, %edx
xorq $0x7e, %rdx
movq %rbx, %rdi
movq %r14, %rsi
leaq -0x4f5(%rip), %rcx      # 0x148c
callq 0x2726
movq %rbx, %rdi
movq %r14, %rsi
leaq -0x507(%rip), %rdx      # 0x148c
callq 0x2851
movl $0xc, %edi
callq 0x1150
movq %rax, -0x48(%rbp)
movl (%r12), %ecx
movl %ecx, (%rax)
movl (%r13), %ecx
movl %ecx, 0x4(%rax)
movb $0x0, 0x8(%rax)
movq 0x577a(%rip), %rsi      # 0x7138
cmpq 0x577b(%rip), %rsi      # 0x7140
je 0x19d4
movq %rax, (%rsi)
addq $0x8, 0x5766(%rip)      # 0x7138
jmp 0x19e4
leaq 0x5755(%rip), %rdi      # 0x7130
leaq -0x48(%rbp), %rdx
callq 0x2bea
movq %r12, %rdi
callq 0x1120
movq %r13, %rdi
callq 0x1120
movq 0x5725(%rip), %r14      # 0x7120
movq 0x5716(%rip), %r13      # 0x7118
movq %r14, %rax
subq %r13, %rax
decl %r15d
cmpq $0x8, %rax
ja 0x18bf
movq (%r13), %rdi
callq 0x1120
addq $-0x8, 0x56fa(%rip)     # 0x7120
movq 0x570b(%rip), %rdi      # 0x7138
subq 0x56fc(%rip), %rdi      # 0x7130
shrq $0x3, %rdi
decl %edi
movl $0x1, %esi
callq 0x149b
callq 0x1507
movq 0x56f8(%rip), %r14      # 0x7148
movq 0x56f9(%rip), %r15      # 0x7150
cmpq %r15, %r14
je 0x1a97
movq %r15, %rax
subq %r14, %rax
sarq $0x3, %rax
bsrq %rax, %rdx
xorl $0x3f, %edx
addl %edx, %edx
xorq $0x7e, %rdx
leaq -0x42e(%rip), %rcx      # 0x164c
movq %r14, %rdi
movq %r15, %rsi
callq 0x2d2a
leaq -0x440(%rip), %rdx      # 0x164c
movq %r14, %rdi
movq %r15, %rsi
callq 0x2e55
callq 0x15fb
callq 0x165b
movq -0x38(%rbp), %rbx
movq 0x10(%rbx), %rsi
leaq 0x25c2(%rip), %rdi      # 0x4072
xorl %eax, %eax
callq 0x1030
movq 0x10(%rbx), %rdi
leaq 0x25c6(%rip), %rsi      # 0x4088
callq 0x1110
testq %rax, %rax
movq -0x40(%rbp), %r14
je 0x1cee
movq %rax, %r15
movl 0x5673(%rip), %eax      # 0x7150
subl 0x5665(%rip), %eax      # 0x7148
shrl $0x3, %eax
movsbl %al, %edi
movq %r15, %rsi
callq 0x1140
movq 0x5650(%rip), %rax      # 0x7148
cmpq %rax, 0x5651(%rip)      # 0x7150
je 0x1b36
xorl %ebx, %ebx
movq (%rax,%rbx,8), %rdi
movl $0x8, %esi
movl $0x1, %edx
movq %r15, %rcx
callq 0x11e0
incq %rbx
movq 0x562d(%rip), %rcx      # 0x7150
movq 0x561e(%rip), %rax      # 0x7148
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbx, %rcx
ja 0x1b03
xorl %ebx, %ebx
movq %r14, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x1100
movq %r14, %rdi
callq 0x11a0
movl $0x0, %r12d
testl %eax, %eax
jne 0x1bee
xorl %r13d, %r13d
movl $0x0, -0x38(%rbp)
movl $0x1, %esi
movl $0x1, %edx
leaq -0x30(%rbp), %rbx
movq %rbx, %rdi
movq %r14, %rcx
callq 0x1190
testl %eax, %eax
je 0x1be6
leaq 0x55d8(%rip), %rdi      # 0x7160
movq %rbx, %rsi
callq 0x1d82
movq (%rax), %rax
movl (%rax), %ebx
movsbl 0x4(%rax), %eax
addl %eax, %r13d
movl %r13d, %ecx
negb %cl
shll %cl, %ebx
orl -0x38(%rbp), %ebx
cmpl $0x8, %r13d
jl 0x1bcb
movl %ebx, %edi
sarl $0x18, %edi
movq %r15, %rsi
callq 0x1140
shll $0x8, %ebx
leal -0x8(%r13), %r12d
cmpl $0xf, %r13d
movl %r12d, %r13d
ja 0x1bac
jmp 0x1bce
movl %r13d, %r12d
movq -0x40(%rbp), %r14
movq %r14, %rdi
callq 0x11a0
movl %r12d, %r13d
movl %ebx, -0x38(%rbp)
testl %eax, %eax
je 0x1b64
jmp 0x1bee
movl -0x38(%rbp), %eax
movl %eax, %ebx
movl %r13d, %r12d
leaq -0x30(%rbp), %rsi
movb $0x0, (%rsi)
leaq 0x5564(%rip), %rdi      # 0x7160
callq 0x1eba
movq (%rax), %rdx
movsbl 0x4(%rdx), %eax
leal (%r12,%rax), %ecx
testl %ecx, %ecx
movq -0x40(%rbp), %r13
jle 0x1c40
movl (%rdx), %r14d
negb %cl
shll %cl, %r14d
orl %ebx, %r14d
leal (%r12,%rax), %ebx
addl $0x8, %ebx
movl %r14d, %edi
sarl $0x18, %edi
movq %r15, %rsi
callq 0x1140
shll $0x8, %r14d
addl $-0x8, %ebx
cmpl $0x8, %ebx
ja 0x1c26
movq %r13, %rdi
callq 0x10c0
movq %r15, %rdi
callq 0x10c0
movq 0x54d9(%rip), %rax      # 0x7130
cmpq %rax, 0x54da(%rip)      # 0x7138
je 0x1c88
xorl %ebx, %ebx
movq (%rax,%rbx,8), %rdi
callq 0x1120
incq %rbx
movq 0x54c3(%rip), %rcx      # 0x7138
movq 0x54b4(%rip), %rax      # 0x7130
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbx, %rcx
ja 0x1c62
movq 0x54b9(%rip), %rax      # 0x7148
cmpq %rax, 0x54ba(%rip)      # 0x7150
je 0x1cc0
xorl %ebx, %ebx
movq (%rax,%rbx,8), %rdi
callq 0x1120
incq %rbx
movq 0x54a3(%rip), %rcx      # 0x7150
movq 0x5494(%rip), %rax      # 0x7148
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbx, %rcx
ja 0x1c9a
leaq -0x78(%rbp), %rdi
callq 0x1f8e
xorl %eax, %eax
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %r12, %rdi
callq 0x1200
addq $0x8, %r12
movq %r12, %rdi
callq 0x126c
addq $0x10, %rbx
movq %rbx, %rdi
callq 0x1242
jmp 0x1d0a
jmp 0x1d0a
jmp 0x1d0a
jmp 0x1d0a
jmp 0x1d0a
jmp 0x1d0a
jmp 0x1d0a
jmp 0x1d0a
movq %rax, %rbx
leaq -0x78(%rbp), %rdi
callq 0x1f8e
movq %rbx, %rdi
callq 0x11d0