// File: /workspace/github_cpp_makefile_star2_O2/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, %r14
cmpl $0x3, %edi
jne 0x1a02
movq 0x8(%r14), %rsi
leaq 0x2a28(%rip), %rdi      # 0x4048
xorl %eax, %eax
callq 0x1030
leaq -0x70(%rbp), %rbx
andl $0x0, (%rbx)
andq $0x0, 0x8(%rbx)
movq %rbx, 0x10(%rbx)
movq %rbx, 0x18(%rbx)
andq $0x0, 0x20(%rbx)
movq %r14, -0x40(%rbp)
movq 0x8(%r14), %rdi
leaq 0x2a0e(%rip), %rsi      # 0x405d
callq 0x1110
testq %rax, %rax
je 0x1a2d
movq %rax, %r13
leaq -0x30(%rbp), %r14
pushq $0x1
popq %r15
leaq -0x78(%rbp), %r12
movq %r13, %rdi
callq 0x11a0
testl %eax, %eax
jne 0x169c
movq %r14, %rdi
movq %r15, %rsi
movq %r15, %rdx
movq %r13, %rcx
callq 0x1190
testl %eax, %eax
je 0x169c
movq %r12, %rdi
movq %r14, %rsi
callq 0x1b2e
incl (%rax)
jmp 0x166c
movq %r13, -0x38(%rbp)
leaq -0x30(%rbp), %rsi
movb $0x0, (%rsi)
leaq -0x78(%rbp), %rdi
callq 0x1b80
incl (%rax)
movq -0x60(%rbp), %r13
pushq $0x8
popq %r14
leaq 0x5a57(%rip), %r15      # 0x7118
leaq -0x30(%rbp), %r12
cmpq %rbx, %r13
je 0x16fc
movq %r14, %rdi
callq 0x1150
movq %rax, -0x30(%rbp)
movsbl 0x20(%r13), %ecx
movl %ecx, (%rax)
movl 0x24(%r13), %ecx
movl %ecx, 0x4(%rax)
movq %r15, %rdi
movq %r12, %rsi
callq 0x1bd2
movq %r13, %rdi
callq 0x1090
movq %rax, %r13
jmp 0x16c5
movq 0x5a15(%rip), %rdi      # 0x7118
movq 0x5a16(%rip), %rsi      # 0x7120
leaq -0x355(%rip), %rdx      # 0x13bc
callq 0x26b2
pushq $-0x1
popq %rbx
leaq -0x48(%rbp), %r13
movq 0x59fc(%rip), %r12      # 0x7120
movq 0x59ed(%rip), %rax      # 0x7118
movq %r12, %rcx
subq %rax, %rcx
cmpq $0x9, %rcx
jb 0x17f8
shlq $0x1d, %rcx
movabsq $-0x100000000, %rdx     # imm = 0xFFFFFFFF00000000
addq %rcx, %rdx
sarq $0x1d, %rdx
movq (%rax,%rdx), %r14
movabsq $-0x200000000, %rdx     # imm = 0xFFFFFFFE00000000
addq %rdx, %rcx
sarq $0x1d, %rcx
movq (%rax,%rcx), %r15
pushq $0x8
popq %rdi
callq 0x1150
movq %rax, -0x30(%rbp)
movl 0x4(%r15), %ecx
addl 0x4(%r14), %ecx
movl %ecx, 0x4(%rax)
movl %ebx, (%rax)
addq $-0x10, %r12
movq %r12, 0x5993(%rip)      # 0x7120
leaq 0x5984(%rip), %rdi      # 0x7118
leaq -0x30(%rbp), %rsi
callq 0x1bd2
movq 0x5974(%rip), %rdi      # 0x7118
movq 0x5975(%rip), %rsi      # 0x7120
leaq -0x3f6(%rip), %rdx      # 0x13bc
callq 0x26b2
pushq $0xc
popq %rdi
callq 0x1150
movq %rax, -0x48(%rbp)
movl (%r14), %ecx
movl %ecx, (%rax)
movl (%r15), %ecx
movl %ecx, 0x4(%rax)
movb $0x0, 0x8(%rax)
leaq 0x5957(%rip), %rdi      # 0x7130
movq %r13, %rsi
callq 0x1bf6
movq %r14, %rdi
callq 0x1120
movq %r15, %rdi
callq 0x1120
decl %ebx
jmp 0x171d
movq (%rax), %rdi
callq 0x1120
addq $-0x8, 0x5918(%rip)     # 0x7120
callq 0x1414
callq 0x1437
movq 0x592f(%rip), %rdi      # 0x7148
movq 0x5930(%rip), %rsi      # 0x7150
leaq -0x2f2(%rip), %rdx      # 0x1535
callq 0x2e2c
callq 0x14e6
callq 0x1544
movq -0x40(%rbp), %rbx
movq 0x10(%rbx), %rsi
leaq 0x282d(%rip), %rdi      # 0x4072
xorl %eax, %eax
callq 0x1030
movq 0x10(%rbx), %rdi
leaq 0x2831(%rip), %rsi      # 0x4088
callq 0x1110
testq %rax, %rax
movq -0x38(%rbp), %r13
je 0x1a48
movq %rax, %r15
movl 0x58de(%rip), %eax      # 0x7150
subl 0x58d0(%rip), %eax      # 0x7148
shrl $0x3, %eax
movsbl %al, %edi
movq %r15, %rsi
callq 0x1140
xorl %ebx, %ebx
pushq $0x8
popq %r14
pushq $0x1
popq %r12
movq 0x58b9(%rip), %rcx      # 0x7150
movq 0x58aa(%rip), %rax      # 0x7148
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbx, %rcx
jbe 0x18c1
movq (%rax,%rbx,8), %rdi
movq %r14, %rsi
movq %r12, %rdx
movq %r15, %rcx
callq 0x11e0
incq %rbx
jmp 0x1890
xorl %ebx, %ebx
movq %r13, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x1100
xorl %r13d, %r13d
movq -0x38(%rbp), %r14
movq %r14, %rdi
callq 0x11a0
testl %eax, %eax
jne 0x193b
leaq -0x30(%rbp), %r12
movq %r12, %rdi
pushq $0x1
popq %rdx
movq %rdx, %rsi
movq %r14, %rcx
callq 0x1190
testl %eax, %eax
je 0x193b
leaq 0x585e(%rip), %rdi      # 0x7160
movq %r12, %rsi
callq 0x1adc
movq (%rax), %rax
movl (%rax), %edx
movsbl 0x4(%rax), %eax
addl %eax, %r13d
movl %r13d, %ecx
negb %cl
shll %cl, %edx
orl %edx, %ebx
cmpl $0x8, %r13d
jl 0x18d6
movl %ebx, %edi
sarl $0x18, %edi
movq %r15, %rsi
callq 0x1140
shll $0x8, %ebx
addl $-0x8, %r13d
jmp 0x191f
leaq -0x30(%rbp), %rsi
movb $0x0, (%rsi)
leaq 0x5817(%rip), %rdi      # 0x7160
callq 0x1c1a
movq (%rax), %rax
movl (%rax), %r14d
movsbl 0x4(%rax), %eax
addl %eax, %r13d
movl %r13d, %ecx
negb %cl
shll %cl, %r14d
orl %ebx, %r14d
testl %r13d, %r13d
jle 0x1983
movl %r14d, %edi
sarl $0x18, %edi
movq %r15, %rsi
callq 0x1140
shll $0x8, %r14d
addl $-0x8, %r13d
jmp 0x1966
movq -0x38(%rbp), %rdi
callq 0x10c0
movq %r15, %rdi
callq 0x10c0
xorl %ebx, %ebx
movq 0x579b(%rip), %rcx      # 0x7138
movq 0x578c(%rip), %rax      # 0x7130
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbx, %rcx
jbe 0x19be
movq (%rax,%rbx,8), %rdi
callq 0x1120
incq %rbx
jmp 0x1996
xorl %ebx, %ebx
movq 0x5789(%rip), %rcx      # 0x7150
movq 0x577a(%rip), %rax      # 0x7148
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbx, %rcx
jbe 0x19e8
movq (%rax,%rbx,8), %rdi
callq 0x1120
incq %rbx
jmp 0x19c0
leaq -0x78(%rbp), %rdi
callq 0x1cd6
xorl %eax, %eax
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x55d7(%rip), %rbx      # 0x6fe0
movq (%rbx), %rcx
leaq 0x2610(%rip), %rdi      # 0x4023
pushq $0x7
popq %rsi
pushq $0x1
popq %rdx
callq 0x11e0
movq (%rbx), %rdi
movq (%r14), %rdx
leaq 0x2600(%rip), %rsi      # 0x402b
jmp 0x1a5d
movq 0x55ac(%rip), %rax      # 0x6fe0
movq (%rax), %rdi
movq -0x40(%rbp), %rax
movq 0x8(%rax), %rdx
leaq 0x261a(%rip), %rsi      # 0x4060
jmp 0x1a5d
movq 0x5591(%rip), %rax      # 0x6fe0
movq (%rax), %rdi
movq 0x10(%rbx), %rdx
leaq 0x262e(%rip), %rsi      # 0x408b
xorl %eax, %eax
callq 0x1170
pushq $0x1
popq %rdi
callq 0x1130
jmp 0x1a7c
jmp 0x1a7c
jmp 0x1a7c
jmp 0x1a7c
jmp 0x1a7c
jmp 0x1a7c
jmp 0x1a7c
jmp 0x1a7c
movq %rax, %rbx
leaq -0x78(%rbp), %rdi
callq 0x1cd6
movq %rbx, %rdi
callq 0x11d0