// File: /workspace/github_cpp_makefile_star2_O2/dm4[P]huffman-homework/decode.cc
// Function: main
int main(int argc, const char *argv[]) {
    if (argc != 4) {
        fprintf(stderr, "Usage:\n");
        fprintf(stderr, "    %s huff_table_name compressed.txt decoded_symbol.txt\n", argv[0]);
        exit(1);
    }

    // read symbol-codeword table to construct symbol vector
    printf("Read symbol-codeword table from file: %s\n", argv[1]);
    FILE *fp = fopen(argv[1], "r");
    if (fp == NULL) {
        fprintf(stderr, "Invalid file: %s\n", argv[1]);
        exit(1);
    }
    Symbol tmp;
    while (fscanf(fp, "%s\n%s\n", tmp.symbol, tmp.codeword) != EOF) {
        Symbol *ptr = (Symbol *)malloc(sizeof(Symbol));
        strcpy(ptr->symbol, tmp.symbol);
        strcpy(ptr->codeword, tmp.codeword);
        ptr->cl = strlen(tmp.codeword);
        symbols.push_back(ptr);
    }
    fclose(fp);

    // sort
    printf("Sort by codewords\n");
    sort(symbols.begin(), symbols.end(), cmpSymbol);

    // LUT
    printf("Construct LUT\n");
    map<int, int> buildLUT;
    int height = 0;
    int previousBuildLUT = -1;
    for (int i = 0; i < symbols.size(); i++) {
        Symbol *p = symbols[i];
        if (p->cl > height) {
            height += 4;
        }

        // build new lookup
        int nowBuildLUT = bin2dec(0, height - 4, p->codeword);
        if (nowBuildLUT != previousBuildLUT) {
            Lookup *ptr = (Lookup *)malloc(sizeof(Lookup));
            LUT.push_back(ptr);
            buildLUT[nowBuildLUT] = LUT.size() - 1;
            previousBuildLUT = nowBuildLUT;

            // set link
            if (height >= 8) {
                int previousLUT = buildLUT[bin2dec(0, height - 8, p->codeword)];
                Lookup *previous = LUT[previousLUT];
                int index = bin2dec(height - 8, height - 4, p->codeword);
                previous->isSymbol[index] = false;
                previous->next[index] = LUT.size() - 1;
            }
        }

        // set lookup entries
        int depth = height - p->cl;
        int subNum  = 1 << depth;
        // 1111 1111 10, base is 8
        int base = calcBase(height, p->codeword);
        for (int j = 0; j < subNum; j++) {
            LUT[LUT.size() - 1]->isSymbol[base + j] = true;
            LUT[LUT.size() - 1]->next[base + j] = i;
        }
    }

    // print LUT
    if (1) {
        for (int i = 0; i < LUT.size(); i++) {
            printf("LUT[%d]\n", i);
            for (int j = 0; j < 16; j++) {
                Lookup *ptr = LUT[i];
                if (ptr->isSymbol[j]) {
                    printf("[%2d] %s %s\n", j, symbols[ptr->next[j]]->symbol, symbols[ptr->next[j]]->codeword);
                }
                else {
                    printf("[%2d] LUT[%d]\n", j, ptr->next[j]);
                }
            }
        }
    }

    // read from compressed text file
    printf("Read compressed text from file: %s\n", argv[2]);
    FILE *cfp = fopen(argv[2], "r");
    if (cfp == NULL) {
        fprintf(stderr, "Invalid file: %s\n", argv[2]);
        exit(1);
    }
    FILE *fout = fopen(argv[3], "w");
    if (fout == NULL) {
        fprintf(stderr, "Couldn't open file: %s\n", argv[3]);
        exit(1);
    }
    char buf[5] = {0};
    int  nowLUT = 0;
    int  nowCL  = 0;
    while(!feof(cfp)) {
        // align buffer to left
        alignBuf(buf);

        // read from compressed text
        bool isEOF = false;
        for (int i = 0; i < 4; i++) {
            if (buf[i] == 0) {
                int c;
                while (c = fgetc(cfp)) {
                    if (c == '0' || c == '1' || c == EOF)
                        break;
                }
                if (c == EOF) {
                    isEOF = true;
                    break;
                }
                buf[i] = c;
            }
        }
        if (isEOF && strlen(buf) == 0)
            break;

        //
        int index = bin2dec(0, 4, buf);
        printf("Bufffer %s\n", buf);
        Lookup *table = LUT[nowLUT];
        if (table->isSymbol[index]) {
            Symbol *s = symbols[table->next[index]];
            printf("Symbol  %s\n", s->symbol);
            fprintf(fout, "%s\n", s->symbol);
            int shift = s->cl - nowCL;
            for (int i = 0; i < shift; i++) {
                buf[i] = 0;
            }
            nowCL  = 0;
            nowLUT = 0;
        }
        else {
            printf("Jump to LUT[%d]\n", table->next[index]);
            nowLUT = table->next[index];
            nowCL += 4;
            for (int i = 0; i < 4; i++) {
                buf[i] = 0;
            }
        }
    }
    fclose(cfp);
    fclose(fout);

    // deconstruct symbol vector
    for (int i = 0; i < symbols.size(); i++) {
        free(symbols[i]);
    }

    // deconstruct LUT
    for (int i = 0; i < LUT.size(); i++) {
        free(LUT[i]);
    }
    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x88, %rsp
movq %rsi, %r14
cmpl $0x4, %edi
jne 0x19c3
movq 0x8(%r14), %rsi
leaq 0x1ba1(%rip), %rdi      # 0x3062
xorl %eax, %eax
callq 0x1030
movq %r14, -0x50(%rbp)
movq 0x8(%r14), %rdi
leaq 0x1bb5(%rip), %rsi      # 0x308c
callq 0x1120
testq %rax, %rax
je 0x19ee
movq %rax, %rbx
leaq -0xa8(%rbp), %r14
leaq -0xac(%rbp), %r12
leaq -0x90(%rbp), %r13
movq %rbx, %rdi
leaq 0x1b99(%rip), %rsi      # 0x30a0
movq %r12, %rdx
movq %r14, %rcx
xorl %eax, %eax
callq 0x1200
cmpl $-0x1, %eax
je 0x155f
pushq $0x1c
popq %rdi
callq 0x1150
movq %rax, %r15
movq %rax, -0x90(%rbp)
movq %rax, %rdi
movq %r12, %rsi
callq 0x10d0
leaq 0x4(%r15), %rdi
movq %r14, %rsi
callq 0x10d0
movq %r14, %rdi
callq 0x1080
movl %eax, 0x18(%r15)
leaq 0x3bdb(%rip), %rdi      # 0x5130
movq %r13, %rsi
callq 0x1a6a
jmp 0x14fd
movq %rbx, %rdi
callq 0x10e0
leaq 0x1bd6(%rip), %rdi      # 0x3144
callq 0x11a0
movq 0x3bb6(%rip), %rdi      # 0x5130
movq 0x3bb7(%rip), %rsi      # 0x5138
leaq -0x1fc(%rip), %rdx      # 0x138c
callq 0x1d98
leaq 0x1bc2(%rip), %rdi      # 0x3156
callq 0x11a0
leaq -0x88(%rbp), %rax
andl $0x0, (%rax)
andq $0x0, 0x8(%rax)
movq %rax, 0x10(%rax)
movq %rax, 0x18(%rax)
andq $0x0, 0x20(%rax)
xorl %r15d, %r15d
pushq $-0x1
popq %rax
movl %eax, -0x3c(%rbp)
xorl %r13d, %r13d
xorl %r14d, %r14d
movq 0x3b6d(%rip), %rcx      # 0x5138
movq 0x3b5e(%rip), %rax      # 0x5130
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %r13, %rcx
jbe 0x172d
movq (%rax,%r13,8), %r12
movl 0x18(%r12), %ebx
leal 0x4(%r14), %eax
cmpl %r14d, %ebx
cmovgl %eax, %r14d
leal -0x4(%r14), %esi
leaq 0x4(%r12), %rdx
xorl %edi, %edi
movl %esi, -0x44(%rbp)
movq %rdx, -0x38(%rbp)
callq 0x13de
movl %eax, -0x40(%rbp)
cmpl -0x3c(%rbp), %eax
je 0x16db
pushq $0x50
popq %rdi
callq 0x1150
movq %rax, -0x30(%rbp)
leaq 0x3b1c(%rip), %rdi      # 0x5148
leaq -0x30(%rbp), %rsi
callq 0x1a8e
movq 0x3b14(%rip), %rbx      # 0x5150
movq 0x3b05(%rip), %r15      # 0x5148
leaq -0x90(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0x1ab2
subq %r15, %rbx
shrq $0x3, %rbx
decl %ebx
movl %ebx, (%rax)
movl -0x40(%rbp), %eax
movl %eax, -0x3c(%rbp)
cmpl $0x8, %r14d
jl 0x16d3
leal -0x8(%r14), %ebx
xorl %edi, %edi
movl %ebx, %esi
movq -0x38(%rbp), %r15
movq %r15, %rdx
callq 0x13de
movl %eax, -0x48(%rbp)
leaq -0x90(%rbp), %rdi
leaq -0x48(%rbp), %rsi
callq 0x1b04
movslq (%rax), %rax
movq 0x3aad(%rip), %rcx      # 0x5148
movq %rcx, -0x60(%rbp)
movq (%rcx,%rax,8), %rax
movq %rax, -0x58(%rbp)
movl %ebx, %edi
movl -0x44(%rbp), %esi
movq %r15, %rdx
callq 0x13de
cltq
movq -0x58(%rbp), %rdx
movb $0x0, 0x40(%rdx,%rax)
movq 0x3a8a(%rip), %rcx      # 0x5150
subq -0x60(%rbp), %rcx
shrq $0x3, %rcx
decl %ecx
movl %ecx, (%rdx,%rax,4)
movl 0x18(%r12), %ebx
xorl %r15d, %r15d
movl %r14d, %ecx
subl %ebx, %ecx
pushq $0x1
popq %rax
movl %eax, %ebx
shll %cl, %ebx
movl %r14d, %edi
movq -0x38(%rbp), %rsi
callq 0x13b1
movq 0x3a56(%rip), %rcx      # 0x5150
movq 0x3a47(%rip), %rdx      # 0x5148
subq %rdx, %rcx
cltq
testl %ebx, %ebx
cmovlel %r15d, %ebx
subq $0x1, %rbx
jb 0x1725
movq -0x8(%rdx,%rcx), %rsi
movb $0x1, 0x40(%rsi,%rax)
movl %r13d, (%rsi,%rax,4)
incq %rax
jmp 0x170c
incq %r13
jmp 0x15c4
leaq 0x1986(%rip), %rbx      # 0x30ba
leaq 0x196c(%rip), %r14      # 0x30a7
leaq 0x1972(%rip), %r15      # 0x30b4
xorl %r12d, %r12d
movq 0x3a04(%rip), %rax      # 0x5150
subq 0x39f5(%rip), %rax      # 0x5148
sarq $0x3, %rax
cmpq %r12, %rax
jbe 0x17be
movq %rbx, %rdi
movl %r12d, %esi
xorl %eax, %eax
callq 0x1030
xorl %r13d, %r13d
cmpq $0x10, %r13
je 0x17b9
movq 0x39cf(%rip), %rax      # 0x5148
movq (%rax,%r12,8), %rax
movslq (%rax,%r13,4), %rdx
cmpb $0x1, 0x40(%rax,%r13)
jne 0x17a7
movq 0x39a0(%rip), %rax      # 0x5130
movq (%rax,%rdx,8), %rdx
leaq 0x4(%rdx), %rcx
movq %r14, %rdi
movl %r13d, %esi
xorl %eax, %eax
callq 0x1030
jmp 0x17b4
movq %r15, %rdi
movl %r13d, %esi
xorl %eax, %eax
callq 0x1030
incq %r13
jmp 0x176c
incq %r12
jmp 0x1745
movq -0x50(%rbp), %rbx
movq 0x10(%rbx), %rsi
leaq 0x18f6(%rip), %rdi      # 0x30c3
xorl %eax, %eax
callq 0x1030
movq 0x10(%rbx), %rdi
leaq 0x18ad(%rip), %rsi      # 0x308c
callq 0x1120
testq %rax, %rax
je 0x1a02
movq %rax, %r14
movq 0x18(%rbx), %rdi
leaq 0x18ec(%rip), %rsi      # 0x30e7
callq 0x1120
movq %rax, -0x38(%rbp)
testq %rax, %rax
je 0x1a19
leaq -0x30(%rbp), %r15
movb $0x0, 0x4(%r15)
andl $0x0, (%r15)
xorl %ebx, %ebx
xorl %r13d, %r13d
movq %r14, %rdi
callq 0x11b0
testl %eax, %eax
jne 0x193e
movq %r15, %rdi
callq 0x1459
xorl %r12d, %r12d
cmpq $0x4, %r12
je 0x187b
cmpb $0x0, -0x30(%rbp,%r12)
jne 0x1866
movq %r14, %rdi
callq 0x11c0
leal -0x30(%rax), %ecx
cmpl $0x2, %ecx
jb 0x1861
cmpl $-0x1, %eax
je 0x186b
testl %eax, %eax
jne 0x1848
movb %al, -0x30(%rbp,%r12)
incq %r12
jmp 0x183a
cmpq $0x3, %r12
ja 0x187b
cmpb $0x0, -0x30(%rbp)
je 0x193e
xorl %edi, %edi
pushq $0x4
popq %rsi
movq %r15, %rdx
callq 0x13de
movl %eax, %r12d
leaq 0x186f(%rip), %rdi      # 0x3101
movq %r15, %rsi
xorl %eax, %eax
callq 0x1030
movslq %ebx, %rax
movq 0x38a2(%rip), %rcx      # 0x5148
movq (%rcx,%rax,8), %rbx
movslq %r12d, %r12
movslq (%rbx,%r12,4), %rsi
cmpb $0x1, 0x40(%rbx,%r12)
je 0x18e6
leaq 0x1859(%rip), %rdi      # 0x3119
xorl %eax, %eax
callq 0x1030
movl (%rbx,%r12,4), %ebx
xorl %eax, %eax
cmpq $0x4, %rax
je 0x18dd
movb $0x0, -0x30(%rbp,%rax)
incq %rax
jmp 0x18cd
addl $0x4, %r13d
jmp 0x181f
movq 0x3843(%rip), %rax      # 0x5130
movq (%rax,%rsi,8), %r12
leaq 0x1815(%rip), %rdi      # 0x310d
movq %r12, %rsi
xorl %eax, %eax
callq 0x1030
movq -0x38(%rbp), %rdi
leaq 0x1796(%rip), %rsi      # 0x30a3
movq %r12, %rdx
xorl %eax, %eax
callq 0x1180
movl 0x18(%r12), %eax
subl %r13d, %eax
testl %eax, %eax
movl $0x0, %ecx
cmovlel %ecx, %eax
xorl %ecx, %ecx
cmpq %rcx, %rax
je 0x181a
movb $0x0, -0x30(%rbp,%rcx)
incq %rcx
jmp 0x192b
movq %r14, %rdi
callq 0x10e0
movq -0x38(%rbp), %rdi
callq 0x10e0
xorl %ebx, %ebx
movq 0x37e0(%rip), %rcx      # 0x5138
movq 0x37d1(%rip), %rax      # 0x5130
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbx, %rcx
jbe 0x1979
movq (%rax,%rbx,8), %rdi
callq 0x1130
incq %rbx
jmp 0x1951
xorl %ebx, %ebx
movq 0x37ce(%rip), %rcx      # 0x5150
movq 0x37bf(%rip), %rax      # 0x5148
subq %rax, %rcx
sarq $0x3, %rcx
cmpq %rbx, %rcx
jbe 0x19a3
movq (%rax,%rbx,8), %rdi
callq 0x1130
incq %rbx
jmp 0x197b
leaq -0x90(%rbp), %rdi
callq 0x1b64
xorl %eax, %eax
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x3616(%rip), %rbx      # 0x4fe0
movq (%rbx), %rcx
leaq 0x164c(%rip), %rdi      # 0x3020
pushq $0x7
popq %rsi
pushq $0x1
popq %rdx
callq 0x1210
movq (%rbx), %rdi
movq (%r14), %rdx
leaq 0x163c(%rip), %rsi      # 0x3028
jmp 0x1a2e
movq 0x35eb(%rip), %rax      # 0x4fe0
movq (%rax), %rdi
movq -0x50(%rbp), %rax
movq 0x8(%rax), %rdx
jmp 0x1a10
movq 0x35d7(%rip), %rax      # 0x4fe0
movq (%rax), %rdi
movq 0x10(%rbx), %rdx
leaq 0x1677(%rip), %rsi      # 0x308e
jmp 0x1a2e
movq 0x35c0(%rip), %rax      # 0x4fe0
movq (%rax), %rdi
movq 0x18(%rbx), %rdx
leaq 0x16bb(%rip), %rsi      # 0x30e9
xorl %eax, %eax
callq 0x1180
pushq $0x1
popq %rdi
callq 0x1140
jmp 0x1a3f
movq %rax, %rbx
leaq -0x90(%rbp), %rdi
callq 0x1b64
movq %rbx, %rdi
callq 0x11f0