// File: /workspace/github_cpp_makefile_star2_O1/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, %r15
cmpl $0x3, %edi
jne 0x1cb5
movq 0x8(%r15), %rsi
leaq 0x290a(%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 %r15, -0x38(%rbp)
movq 0x8(%r15), %rdi
leaq 0x28ec(%rip), %rsi      # 0x405d
callq 0x1110
testq %rax, %rax
je 0x1cbd
movq %rax, %r13
leaq -0x30(%rbp), %r14
leaq -0x78(%rbp), %r15
movq %r13, %rdi
callq 0x11a0
testl %eax, %eax
jne 0x17c5
movl $0x1, %esi
movl $0x1, %edx
movq %r14, %rdi
movq %r13, %rcx
callq 0x1190
movq %rax, %r12
testl %r12d, %r12d
je 0x17c5
movq %r15, %rdi
movq %r14, %rsi
callq 0x1dc6
incl (%rax)
testl %r12d, %r12d
jne 0x178a
leaq -0x30(%rbp), %rsi
movb $0x0, (%rsi)
leaq -0x78(%rbp), %rdi
callq 0x1e2e
incl (%rax)
movq -0x60(%rbp), %r14
cmpq %rbx, %r14
je 0x183f
leaq 0x5931(%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 0x5912(%rip), %rsi      # 0x7120
cmpq 0x5913(%rip), %rsi      # 0x7128
je 0x1824
movq %rax, (%rsi)
addq $0x8, 0x58fe(%rip)      # 0x7120
jmp 0x182f
movq %r15, %rdi
movq %r12, %rdx
callq 0x25da
movq %r14, %rdi
callq 0x1090
movq %rax, %r14
cmpq %rbx, %rax
jne 0x17eb
movq 0x58d2(%rip), %r14      # 0x7118
movq 0x58d3(%rip), %r15      # 0x7120
cmpq %r15, %r14
je 0x188d
movq %r15, %rax
subq %r14, %rax
sarq $0x3, %rax
bsrq %rax, %rdx
xorl $0x3f, %edx
addl %edx, %edx
xorq $0x7e, %rdx
leaq -0x3e4(%rip), %rcx      # 0x148c
movq %r14, %rdi
movq %r15, %rsi
callq 0x271a
leaq -0x3f6(%rip), %rdx      # 0x148c
movq %r14, %rdi
movq %r15, %rsi
callq 0x2845
movq %r13, -0x40(%rbp)
movq 0x5888(%rip), %r14      # 0x7120
movq 0x5879(%rip), %rax      # 0x7118
movq %r14, %rcx
subq %rax, %rcx
cmpq $0x9, %rcx
jb 0x19fc
movl $0xffffffff, %ebx       # imm = 0xFFFFFFFF
shlq $0x1d, %rcx
movabsq $-0x100000000, %rdx     # imm = 0xFFFFFFFF00000000
addq %rcx, %rdx
sarq $0x1d, %rdx
movq (%rax,%rdx), %r12
movabsq $-0x200000000, %rdx     # imm = 0xFFFFFFFE00000000
addq %rdx, %rcx
sarq $0x1d, %rcx
movq (%rax,%rcx), %r13
movl $0x8, %edi
callq 0x1150
movq %rax, -0x30(%rbp)
movl 0x4(%r13), %ecx
addl 0x4(%r12), %ecx
movl %ecx, 0x4(%rax)
movl %ebx, (%rax)
addq $-0x10, %r14
movq %r14, 0x5817(%rip)      # 0x7120
cmpq 0x5818(%rip), %r14      # 0x7128
je 0x191f
movq %rax, (%r14)
addq $0x8, 0x5803(%rip)      # 0x7120
jmp 0x1932
leaq 0x57f2(%rip), %rdi      # 0x7118
movq %r14, %rsi
leaq -0x30(%rbp), %rdx
callq 0x25da
movq 0x57df(%rip), %r14      # 0x7118
movq 0x57e0(%rip), %r15      # 0x7120
cmpq %r15, %r14
je 0x1980
movq %r15, %rax
subq %r14, %rax
sarq $0x3, %rax
bsrq %rax, %rdx
xorl $0x3f, %edx
addl %edx, %edx
xorq $0x7e, %rdx
movq %r14, %rdi
movq %r15, %rsi
leaq -0x4dd(%rip), %rcx      # 0x148c
callq 0x271a
movq %r14, %rdi
movq %r15, %rsi
leaq -0x4ef(%rip), %rdx      # 0x148c
callq 0x2845
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 0x5792(%rip), %rsi      # 0x7138
cmpq 0x5793(%rip), %rsi      # 0x7140
je 0x19bc
movq %rax, (%rsi)
addq $0x8, 0x577e(%rip)      # 0x7138
jmp 0x19cc
leaq 0x576d(%rip), %rdi      # 0x7130
leaq -0x48(%rbp), %rdx
callq 0x2c04
movq %r12, %rdi
callq 0x1120
movq %r13, %rdi
callq 0x1120
movq 0x573d(%rip), %r14      # 0x7120
movq 0x572e(%rip), %rax      # 0x7118
movq %r14, %rcx
subq %rax, %rcx
decl %ebx
cmpq $0x8, %rcx
ja 0x18b4
movq (%rax), %rdi
callq 0x1120
addq $-0x8, 0x5714(%rip)     # 0x7120
movq 0x5725(%rip), %rdi      # 0x7138
subq 0x5716(%rip), %rdi      # 0x7130
shrq $0x3, %rdi
decl %edi
movl $0x1, %esi
callq 0x149b
callq 0x1500
movq 0x5712(%rip), %r14      # 0x7148
movq 0x5713(%rip), %r15      # 0x7150
cmpq %r15, %r14
je 0x1a7d
movq %r15, %rax
subq %r14, %rax
sarq $0x3, %rax
bsrq %rax, %rdx
xorl $0x3f, %edx
addl %edx, %edx
xorq $0x7e, %rdx
leaq -0x419(%rip), %rcx      # 0x1647
movq %r14, %rdi
movq %r15, %rsi
callq 0x2d44
leaq -0x42b(%rip), %rdx      # 0x1647
movq %r14, %rdi
movq %r15, %rsi
callq 0x2e6f
callq 0x15f6
callq 0x1656
movq -0x38(%rbp), %rbx
movq 0x10(%rbx), %rsi
leaq 0x25dc(%rip), %rdi      # 0x4072
xorl %eax, %eax
callq 0x1030
movq 0x10(%rbx), %rdi
leaq 0x25e0(%rip), %rsi      # 0x4088
callq 0x1110
testq %rax, %rax
movq -0x40(%rbp), %r12
je 0x1cca
movq %rax, %r15
movl 0x568d(%rip), %eax      # 0x7150
subl 0x567f(%rip), %eax      # 0x7148
shrl $0x3, %eax
movsbl %al, %edi
movq %r15, %rsi
callq 0x1140
movq 0x566a(%rip), %rax      # 0x7148
cmpq %rax, 0x566b(%rip)      # 0x7150
je 0x1b1c
xorl %ebx, %ebx
movq (%rax,%rbx,8), %rdi
movl $0x8, %esi
movl $0x1, %edx
movq %r15, %rcx
callq 0x11e0
incq %rbx
movq 0x5647(%rip), %rcx      # 0x7150
movq 0x5638(%rip), %rax      # 0x7148
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbx, %rcx
ja 0x1ae9
xorl %r14d, %r14d
movq %r12, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x1100
xorl %r12d, %r12d
movq -0x40(%rbp), %rbx
movq %rbx, %rdi
callq 0x11a0
testl %eax, %eax
jne 0x1bc6
movl $0x1, %esi
movl $0x1, %edx
leaq -0x30(%rbp), %r13
movq %r13, %rdi
movq %rbx, %rcx
callq 0x1190
movq %rax, -0x38(%rbp)
testl %eax, %eax
je 0x1bae
leaq 0x55f6(%rip), %rdi      # 0x7160
movq %r13, %rsi
callq 0x1d5e
movq (%rax), %rax
movl (%rax), %ebx
movsbl 0x4(%rax), %eax
addl %eax, %r12d
movl %r12d, %ecx
negb %cl
shll %cl, %ebx
orl %r14d, %ebx
cmpl $0x8, %r12d
jl 0x1bb1
movl %ebx, %edi
sarl $0x18, %edi
movq %r15, %rsi
callq 0x1140
shll $0x8, %ebx
leal -0x8(%r12), %r13d
cmpl $0xf, %r12d
movl %r13d, %r12d
jg 0x1b8e
jmp 0x1bb4
movl %r14d, %ebx
movl %r12d, %r13d
movl %ebx, %r14d
movl %r13d, %r12d
cmpl $0x0, -0x38(%rbp)
jne 0x1b2e
jmp 0x1bcc
movl %r14d, %ebx
movl %r12d, %r13d
leaq -0x30(%rbp), %rsi
movb $0x0, (%rsi)
leaq 0x5586(%rip), %rdi      # 0x7160
callq 0x1e96
movq (%rax), %rdx
movsbl 0x4(%rdx), %eax
leal (%rax,%r13), %ecx
testl %ecx, %ecx
jle 0x1c1a
movl (%rdx), %r14d
negb %cl
shll %cl, %r14d
orl %ebx, %r14d
leal (%rax,%r13), %ebx
addl $0x8, %ebx
movl %r14d, %edi
sarl $0x18, %edi
movq %r15, %rsi
callq 0x1140
shll $0x8, %r14d
addl $-0x8, %ebx
cmpl $0x8, %ebx
jg 0x1c00
movq -0x40(%rbp), %rdi
callq 0x10c0
movq %r15, %rdi
callq 0x10c0
movq 0x54fe(%rip), %rax      # 0x7130
cmpq %rax, 0x54ff(%rip)      # 0x7138
je 0x1c63
xorl %ebx, %ebx
movq (%rax,%rbx,8), %rdi
callq 0x1120
incq %rbx
movq 0x54e8(%rip), %rcx      # 0x7138
movq 0x54d9(%rip), %rax      # 0x7130
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbx, %rcx
ja 0x1c3d
movq 0x54de(%rip), %rax      # 0x7148
cmpq %rax, 0x54df(%rip)      # 0x7150
je 0x1c9b
xorl %ebx, %ebx
movq (%rax,%rbx,8), %rdi
callq 0x1120
incq %rbx
movq 0x54c8(%rip), %rcx      # 0x7150
movq 0x54b9(%rip), %rax      # 0x7148
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbx, %rcx
ja 0x1c75
leaq -0x78(%rbp), %rdi
callq 0x1f6a
xorl %eax, %eax
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %r15, %rdi
callq 0x1200
movq -0x38(%rbp), %rdi
addq $0x8, %rdi
callq 0x126c
addq $0x10, %rbx
movq %rbx, %rdi
callq 0x1242
jmp 0x1ce6
jmp 0x1ce6
jmp 0x1ce6
jmp 0x1ce6
jmp 0x1ce6
jmp 0x1ce6
jmp 0x1ce6
jmp 0x1ce6
movq %rax, %rbx
leaq -0x78(%rbp), %rdi
callq 0x1f6a
movq %rbx, %rdi
callq 0x11d0