// File: 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
subq $0x1c0, %rsp            # imm = 0x1C0
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
cmpl $0x3, -0x8(%rbp)
je 0x1830
movq 0xe7ea(%rip), %rax      # 0xffe0
movq (%rax), %rdi
leaq 0x8807(%rip), %rsi      # 0xa007
movb $0x0, %al
callq 0x1150
movq 0xe7d2(%rip), %rax      # 0xffe0
movq (%rax), %rdi
movq -0x10(%rbp), %rax
movq (%rax), %rdx
leaq 0x87f0(%rip), %rsi      # 0xa00f
movb $0x0, %al
callq 0x1150
movl $0x1, %edi
callq 0x1130
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rsi
leaq 0x87ed(%rip), %rdi      # 0xa02c
xorl %eax, %eax
callq 0x1030
leaq -0x40(%rbp), %rdi
callq 0x2450
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
leaq 0x87e3(%rip), %rsi      # 0xa041
callq 0x1110
movq %rax, -0x138(%rbp)
jmp 0x186c
movq -0x138(%rbp), %rax
movq %rax, -0x48(%rbp)
cmpq $0x0, -0x48(%rbp)
jne 0x18c2
movq 0xe75b(%rip), %rax      # 0xffe0
movq (%rax), %rdi
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdx
leaq 0x87ad(%rip), %rsi      # 0xa044
movb $0x0, %al
callq 0x1150
movl $0x1, %edi
callq 0x1130
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x50(%rbp)
movl %eax, -0x54(%rbp)
leaq -0x40(%rbp), %rdi
callq 0x2ad0
jmp 0x20af
jmp 0x18c4
movq -0x48(%rbp), %rdi
callq 0x1180
cmpl $0x0, %eax
setne %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x18db
jmp 0x1931
movq -0x48(%rbp), %rcx
leaq -0x55(%rbp), %rdi
movl $0x1, %edx
movq %rdx, %rsi
callq 0x1170
movq %rax, -0x140(%rbp)
jmp 0x18f9
movq -0x140(%rbp), %rax
movl %eax, -0x5c(%rbp)
cmpl $0x0, -0x5c(%rbp)
jne 0x190b
jmp 0x1931
leaq -0x40(%rbp), %rdi
leaq -0x55(%rbp), %rsi
callq 0x2470
movq %rax, -0x148(%rbp)
jmp 0x1921
movq -0x148(%rbp), %rax
movl (%rax), %ecx
addl $0x1, %ecx
movl %ecx, (%rax)
jmp 0x18c4
movb $0x0, -0x5d(%rbp)
leaq -0x40(%rbp), %rdi
leaq -0x5d(%rbp), %rsi
callq 0x2550
movq %rax, -0x150(%rbp)
jmp 0x194b
movq -0x150(%rbp), %rax
movl (%rax), %ecx
addl $0x1, %ecx
movl %ecx, (%rax)
leaq -0x68(%rbp), %rdi
callq 0x2630
leaq -0x40(%rbp), %rdi
callq 0x2650
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rax
movq %rax, -0x68(%rbp)
leaq -0x40(%rbp), %rdi
callq 0x26b0
movq %rax, -0x78(%rbp)
leaq -0x68(%rbp), %rdi
leaq -0x78(%rbp), %rsi
callq 0x2680
testb $0x1, %al
jne 0x1997
jmp 0x19ff
movl $0x8, %edi
callq 0x1140
movq %rax, -0x80(%rbp)
leaq -0x68(%rbp), %rdi
movq %rdi, -0x158(%rbp)
callq 0x26e0
movq -0x158(%rbp), %rdi
movsbl (%rax), %ecx
movq -0x80(%rbp), %rax
movl %ecx, (%rax)
callq 0x26e0
movl 0x4(%rax), %ecx
movq -0x80(%rbp), %rax
movl %ecx, 0x4(%rax)
leaq 0xe72d(%rip), %rdi      # 0x10108
leaq -0x80(%rbp), %rsi
callq 0x2700
jmp 0x19e6
jmp 0x19e8
leaq -0x68(%rbp), %rdi
xorl %esi, %esi
callq 0x2770
movq %rax, -0x88(%rbp)
jmp 0x1977
leaq 0xe702(%rip), %rdi      # 0x10108
movq %rdi, -0x160(%rbp)
callq 0x2800
movq -0x160(%rbp), %rdi
movq %rax, -0x90(%rbp)
callq 0x2830
movq %rax, -0x98(%rbp)
movq -0x90(%rbp), %rdi
movq -0x98(%rbp), %rsi
leaq -0x691(%rip), %rdx      # 0x13b0
callq 0x27b0
jmp 0x1a48
movl $0x0, -0x9c(%rbp)
leaq 0xe6af(%rip), %rdi      # 0x10108
callq 0x2860
cmpq $0x1, %rax
jbe 0x1bfd
leaq 0xe699(%rip), %rdi      # 0x10108
movq %rdi, -0x168(%rbp)
callq 0x2860
movq -0x168(%rbp), %rdi
movl %eax, -0xa0(%rbp)
movl -0xa0(%rbp), %eax
decl %eax
movslq %eax, %rsi
callq 0x2880
movq -0x168(%rbp), %rdi
movq (%rax), %rax
movq %rax, -0xa8(%rbp)
movl -0xa0(%rbp), %eax
addl $-0x2, %eax
movslq %eax, %rsi
callq 0x2880
movq (%rax), %rax
movq %rax, -0xb0(%rbp)
movl $0x8, %edi
callq 0x1140
movq -0x168(%rbp), %rdi
movq %rax, -0xb8(%rbp)
movq -0xa8(%rbp), %rax
movl 0x4(%rax), %ecx
movq -0xb0(%rbp), %rax
movl 0x4(%rax), %eax
addl %eax, %ecx
movq -0xb8(%rbp), %rax
movl %ecx, 0x4(%rax)
movl -0x9c(%rbp), %ecx
notl %ecx
movq -0xb8(%rbp), %rax
movl %ecx, (%rax)
movl -0x9c(%rbp), %eax
incl %eax
movl %eax, -0x9c(%rbp)
callq 0x28a0
movq -0x168(%rbp), %rdi
callq 0x28a0
movq -0x168(%rbp), %rdi
leaq -0xb8(%rbp), %rsi
callq 0x2700
jmp 0x1b41
leaq 0xe5c0(%rip), %rdi      # 0x10108
movq %rdi, -0x170(%rbp)
callq 0x2800
movq -0x170(%rbp), %rdi
movq %rax, -0xc0(%rbp)
callq 0x2830
movq %rax, -0xc8(%rbp)
movq -0xc0(%rbp), %rdi
movq -0xc8(%rbp), %rsi
leaq -0x7d3(%rip), %rdx      # 0x13b0
callq 0x27b0
jmp 0x1b8a
movl $0xc, %edi
callq 0x1140
movq %rax, -0xd0(%rbp)
movq -0xa8(%rbp), %rax
movl (%rax), %ecx
movq -0xd0(%rbp), %rax
movl %ecx, (%rax)
movq -0xb0(%rbp), %rax
movl (%rax), %ecx
movq -0xd0(%rbp), %rax
movl %ecx, 0x4(%rax)
movq -0xd0(%rbp), %rax
movb $0x0, 0x8(%rax)
leaq 0xe54e(%rip), %rdi      # 0x10120
leaq -0xd0(%rbp), %rsi
callq 0x28d0
jmp 0x1be0
movq -0xa8(%rbp), %rdi
callq 0x1120
movq -0xb0(%rbp), %rdi
callq 0x1120
jmp 0x1a52
leaq 0xe504(%rip), %rdi      # 0x10108
movq %rdi, -0x178(%rbp)
xorl %eax, %eax
movl %eax, %esi
callq 0x2880
movq (%rax), %rdi
callq 0x1120
movq -0x178(%rbp), %rdi
callq 0x28a0
callq 0x1460
jmp 0x1c2f
callq 0x1490
jmp 0x1c36
leaq 0xe4fb(%rip), %rdi      # 0x10138
movq %rdi, -0x180(%rbp)
callq 0x2990
movq -0x180(%rbp), %rdi
movq %rax, -0xd8(%rbp)
callq 0x29c0
movq %rax, -0xe0(%rbp)
movq -0xd8(%rbp), %rdi
movq -0xe0(%rbp), %rsi
leaq -0x628(%rip), %rdx      # 0x1650
callq 0x2940
jmp 0x1c7f
callq 0x1570
callq 0x1680
jmp 0x1c8b
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rsi
leaq 0x83bc(%rip), %rdi      # 0xa056
xorl %eax, %eax
callq 0x1030
jmp 0x1ca3
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdi
leaq 0x83ba(%rip), %rsi      # 0xa06c
callq 0x1110
movq %rax, -0x188(%rbp)
jmp 0x1cc0
movq -0x188(%rbp), %rax
movq %rax, -0xe8(%rbp)
cmpq $0x0, -0xe8(%rbp)
jne 0x1d02
movq 0xe301(%rip), %rax      # 0xffe0
movq (%rax), %rdi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdx
leaq 0x837e(%rip), %rsi      # 0xa06f
movb $0x0, %al
callq 0x1150
movl $0x1, %edi
callq 0x1130
leaq 0xe42f(%rip), %rdi      # 0x10138
callq 0x2350
movb %al, -0xe9(%rbp)
movq -0xe8(%rbp), %rcx
leaq -0xe9(%rbp), %rdi
movl $0x1, %edx
movq %rdx, %rsi
callq 0x11c0
jmp 0x1d31
movl $0x0, -0xf0(%rbp)
movslq -0xf0(%rbp), %rax
movq %rax, -0x190(%rbp)
leaq 0xe3e8(%rip), %rdi      # 0x10138
callq 0x2350
movq %rax, %rcx
movq -0x190(%rbp), %rax
cmpq %rcx, %rax
jae 0x1da5
movslq -0xf0(%rbp), %rsi
leaq 0xe3c6(%rip), %rdi      # 0x10138
callq 0x2330
movq (%rax), %rdi
movq -0xe8(%rbp), %rcx
movl $0x8, %esi
movl $0x1, %edx
callq 0x11c0
jmp 0x1d92
jmp 0x1d94
movl -0xf0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xf0(%rbp)
jmp 0x1d3b
movq -0x48(%rbp), %rdi
xorl %edx, %edx
movl %edx, %esi
callq 0x1100
jmp 0x1db4
movl $0x0, -0xf4(%rbp)
movl $0x0, -0xf8(%rbp)
movq -0x48(%rbp), %rdi
callq 0x1180
cmpl $0x0, %eax
setne %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x1de2
jmp 0x1eec
movq -0x48(%rbp), %rcx
leaq -0xf9(%rbp), %rdi
movl $0x1, %edx
movq %rdx, %rsi
callq 0x1170
movq %rax, -0x198(%rbp)
jmp 0x1e03
movq -0x198(%rbp), %rax
movl %eax, -0x100(%rbp)
cmpl $0x0, -0x100(%rbp)
jne 0x1e1e
jmp 0x1eec
leaq 0xe32b(%rip), %rdi      # 0x10150
leaq -0xf9(%rbp), %rsi
callq 0x2370
movq %rax, -0x1a0(%rbp)
jmp 0x1e3a
movq -0x1a0(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x108(%rbp)
movl -0xf8(%rbp), %esi
movq -0x108(%rbp), %rax
movl (%rax), %edx
movq -0x108(%rbp), %rax
leaq -0xf4(%rbp), %rdi
movsbl 0x4(%rax), %ecx
callq 0x1790
movq -0x108(%rbp), %rax
movsbl 0x4(%rax), %eax
addl -0xf8(%rbp), %eax
movl %eax, -0xf8(%rbp)
cmpl $0x8, -0xf8(%rbp)
jl 0x1ee7
movzbl -0xf1(%rbp), %eax
movl %eax, -0x10c(%rbp)
movb -0x10c(%rbp), %al
movb %al, -0x10d(%rbp)
movq -0xe8(%rbp), %rcx
leaq -0x10d(%rbp), %rdi
movl $0x1, %edx
movq %rdx, %rsi
callq 0x11c0
jmp 0x1ec7
movl -0xf4(%rbp), %eax
shll $0x8, %eax
movl %eax, -0xf4(%rbp)
movl -0xf8(%rbp), %eax
subl $0x8, %eax
movl %eax, -0xf8(%rbp)
jmp 0x1e88
jmp 0x1dc8
movb $0x0, -0x119(%rbp)
leaq 0xe256(%rip), %rdi      # 0x10150
leaq -0x119(%rbp), %rsi
callq 0x29f0
movq %rax, -0x1a8(%rbp)
jmp 0x1f0f
movq -0x1a8(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x118(%rbp)
movl -0xf8(%rbp), %esi
movq -0x118(%rbp), %rax
movl (%rax), %edx
movq -0x118(%rbp), %rax
leaq -0xf4(%rbp), %rdi
movsbl 0x4(%rax), %ecx
callq 0x1790
movq -0x118(%rbp), %rax
movsbl 0x4(%rax), %eax
addl -0xf8(%rbp), %eax
movl %eax, -0xf8(%rbp)
cmpl $0x0, -0xf8(%rbp)
jle 0x1fbc
movzbl -0xf1(%rbp), %eax
movl %eax, -0x120(%rbp)
movb -0x120(%rbp), %al
movb %al, -0x121(%rbp)
movq -0xe8(%rbp), %rcx
leaq -0x121(%rbp), %rdi
movl $0x1, %edx
movq %rdx, %rsi
callq 0x11c0
jmp 0x1f9c
movl -0xf4(%rbp), %eax
shll $0x8, %eax
movl %eax, -0xf4(%rbp)
movl -0xf8(%rbp), %eax
subl $0x8, %eax
movl %eax, -0xf8(%rbp)
jmp 0x1f5d
movq -0x48(%rbp), %rdi
callq 0x10c0
jmp 0x1fc7
movq -0xe8(%rbp), %rdi
callq 0x10c0
jmp 0x1fd5
movl $0x0, -0x128(%rbp)
movslq -0x128(%rbp), %rax
movq %rax, -0x1b0(%rbp)
leaq 0xe12c(%rip), %rdi      # 0x10120
callq 0x22a0
movq %rax, %rcx
movq -0x1b0(%rbp), %rax
cmpq %rcx, %rax
jae 0x2034
movslq -0x128(%rbp), %rsi
leaq 0xe10a(%rip), %rdi      # 0x10120
callq 0x2280
movq (%rax), %rdi
callq 0x1120
movl -0x128(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x128(%rbp)
jmp 0x1fdf
movl $0x0, -0x12c(%rbp)
movslq -0x12c(%rbp), %rax
movq %rax, -0x1b8(%rbp)
leaq 0xe0e5(%rip), %rdi      # 0x10138
callq 0x2350
movq %rax, %rcx
movq -0x1b8(%rbp), %rax
cmpq %rcx, %rax
jae 0x2093
movslq -0x12c(%rbp), %rsi
leaq 0xe0c3(%rip), %rdi      # 0x10138
callq 0x2330
movq (%rax), %rdi
callq 0x1120
movl -0x12c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x12c(%rbp)
jmp 0x203e
movl $0x0, -0x4(%rbp)
leaq -0x40(%rbp), %rdi
callq 0x2ad0
movl -0x4(%rbp), %eax
addq $0x1c0, %rsp            # imm = 0x1C0
popq %rbp
retq
movq -0x50(%rbp), %rdi
callq 0x11b0
nopl (%rax,%rax)