// File: /workspace/github_c_makefile_star2_O0/teodorst[P]app-huffman/huffman_codification_mpi.c
// Function: huffman_compress
int huffman_compress(char* input_filename, char* output_filename, char* codification_filename) {

	int myrank;
	int nr_proc;
	MPI_Status status;
	
	MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
	MPI_Comm_size(MPI_COMM_WORLD, &nr_proc);

	char *input_buffer;

	int size;
	int process_size;
    int i;
	// read file only by master process


    char codification_v[CODIFICATION_V_SIZE];
    char** codification = (char**) calloc(128, sizeof(char*));

    FILE* input_file;
    FILE* output_file;
    FILE* codification_file;

   	if (myrank == MASTER_PROCESS) {
		// open files
        input_file = open_file(input_filename, "r");
        output_file = open_file(output_filename, "w");
        codification_file = open_file(codification_filename, "w");

	    // compute input file size
		fseek(input_file, 0, SEEK_END);
		size = ftell(input_file);
		process_size = size / (nr_proc-1);
		fseek(input_file, 0, SEEK_SET);

   		input_buffer = (char *) malloc(size * sizeof(char));

   		fread(input_buffer, 1, size, input_file);

   		unsigned long long int *frequency = (unsigned long long int*) calloc(128, sizeof(unsigned long long int));
   		// compute frequency
		for (i = 0; i < size; i ++) {
			frequency[(unsigned char)input_buffer[i]] ++;
		}
        
        // create huffman_tree
        node_t* root_holder = build_huffman_tree(frequency);
        char path[MAX_BITS_CODE];
        find_codification(root_holder, path, 0, codification);

        // transform the codification matrix into a vector 
        int row, i;
        for (row = 0; row < 128; row++)
        {
            if (codification[row]) {
                for (i = 0; i < strlen(codification[row]) ; i++)
                    codification_v[row * 20 + i] = codification[row][i];
                
                for (i = strlen(codification[row]); i < 20; i++)
                    codification_v[row * 20 + i] = '\0';
                }
            else {
                for (i = 0; i < 20; i++)
                    codification_v[row * 20 + i] = '\0';
            }
        }
   	} 

    MPI_Bcast(codification_v, CODIFICATION_V_SIZE, MPI_CHAR, 0, MPI_COMM_WORLD);

    if (myrank == MASTER_PROCESS) {
        for (i = 1; i < nr_proc; i ++) {
            MPI_Send(&process_size, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
            MPI_Send(input_buffer + (i - 1) * process_size, process_size, MPI_CHAR, i, 0, MPI_COMM_WORLD);
            printf("%d a trimis la %d input buffer\n", myrank, i);
        }

        int output_buffer_contors[nr_proc - 1];
        unsigned long long int nbits_buffer[nr_proc - 1];
        for (i = 1; i < nr_proc; i ++) {
            MPI_Recv(output_buffer_contors + i - 1, 1, MPI_INT, i, 0, MPI_COMM_WORLD, &status);
            MPI_Recv(nbits_buffer + i - 1, 1, MPI_UNSIGNED_LONG, i, 0, MPI_COMM_WORLD, &status);
            MPI_Recv(input_buffer + (i - 1) * process_size, process_size, MPI_CHAR, i, 0, MPI_COMM_WORLD, &status);
        }

        for (i = 0; i < nr_proc-1; i++) {
            fwrite(input_buffer + i * process_size, 1, output_buffer_contors[i], output_file);
        }

        write_metadata_file_pthreads(codification_file, codification, size, nr_proc-1, nbits_buffer, output_buffer_contors);

        // close files
        fclose(input_file);
        fclose(output_file);
        fclose(codification_file);
    }

    if (myrank != MASTER_PROCESS) {
        
        for (i = 0; i < 128; i ++) {
            if (strlen(codification_v + i * 20) > 0) {
                codification[i] = strdup(codification_v + i * 20);
            }
        }

    
        MPI_Recv(&process_size, 1, MPI_INT, MASTER_PROCESS, 0, MPI_COMM_WORLD, &status);
        printf("%d \n", process_size);
        input_buffer = (char *) malloc(process_size * sizeof(char));
        char* output_buffer = (char *) malloc(process_size * sizeof(char));

        MPI_Recv(input_buffer, process_size, MPI_CHAR, MASTER_PROCESS, 0, MPI_COMM_WORLD, &status);
        
        printf("%d a primit\n", myrank);

        int output_buffer_contor = 0;
        unsigned long long int nbits = 0;
        write_codification_for_chunk_pthreads(input_buffer, 0, process_size, codification, output_buffer, &output_buffer_contor, &nbits);

        printf("%d a codificat in %d chars %llu bits\n", myrank, output_buffer_contor, nbits);

        MPI_Send(&output_buffer_contor, 1, MPI_INT, MASTER_PROCESS, 0, MPI_COMM_WORLD);
        MPI_Send(&nbits, 1, MPI_UNSIGNED_LONG, MASTER_PROCESS, 0, MPI_COMM_WORLD);
        MPI_Send(output_buffer, output_buffer_contor, MPI_CHAR, MASTER_PROCESS, 0, MPI_COMM_WORLD);

    }

    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xb50, %rsp            # imm = 0xB50
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq 0x4c32(%rip), %rdi      # 0x5fe0
leaq -0x1c(%rbp), %rsi
callq 0x1150
movq 0x4c22(%rip), %rdi      # 0x5fe0
leaq -0x20(%rbp), %rsi
callq 0x1100
movl $0x80, %edi
movl $0x8, %esi
callq 0x11a0
movq %rax, -0xa58(%rbp)
cmpl $0x0, -0x1c(%rbp)
jne 0x1672
movq -0x8(%rbp), %rdi
leaq 0x2c12(%rip), %rsi      # 0x4004
callq 0x12f0
movq %rax, -0xa60(%rbp)
movq -0x10(%rbp), %rdi
leaq 0x2bfd(%rip), %rsi      # 0x4006
callq 0x12f0
movq %rax, -0xa68(%rbp)
movq -0x18(%rbp), %rdi
leaq 0x2be6(%rip), %rsi      # 0x4006
callq 0x12f0
movq %rax, -0xa70(%rbp)
movq -0xa60(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0x2, %edx
callq 0x1080
movq -0xa60(%rbp), %rdi
callq 0x1060
movl %eax, -0x44(%rbp)
movl -0x44(%rbp), %eax
movl -0x20(%rbp), %ecx
subl $0x1, %ecx
cltd
idivl %ecx
movl %eax, -0x48(%rbp)
movq -0xa60(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
xorl %edx, %edx
callq 0x1080
movslq -0x44(%rbp), %rdi
shlq $0x0, %rdi
callq 0x10b0
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rdi
movslq -0x44(%rbp), %rdx
movq -0xa60(%rbp), %rcx
movl $0x1, %esi
callq 0x1140
movl $0x80, %edi
movl $0x8, %esi
callq 0x11a0
movq %rax, -0xa78(%rbp)
movl $0x0, -0x4c(%rbp)
movl -0x4c(%rbp), %eax
cmpl -0x44(%rbp), %eax
jge 0x14ea
movq -0xa78(%rbp), %rax
movq -0x40(%rbp), %rcx
movslq -0x4c(%rbp), %rdx
movzbl (%rcx,%rdx), %ecx
movq (%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, (%rax,%rcx,8)
movl -0x4c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
jmp 0x14b8
movq -0xa78(%rbp), %rdi
callq 0x2d90
movq %rax, -0xa80(%rbp)
movq -0xa80(%rbp), %rdi
leaq -0xb00(%rbp), %rsi
movq -0xa58(%rbp), %rcx
xorl %edx, %edx
callq 0x2ae0
movl $0x0, -0xb04(%rbp)
cmpl $0x80, -0xb04(%rbp)
jge 0x1670
movq -0xa58(%rbp), %rax
movslq -0xb04(%rbp), %rcx
cmpq $0x0, (%rax,%rcx,8)
je 0x161d
movl $0x0, -0xb08(%rbp)
movslq -0xb08(%rbp), %rax
movq %rax, -0xb40(%rbp)
movq -0xa58(%rbp), %rax
movslq -0xb04(%rbp), %rcx
movq (%rax,%rcx,8), %rdi
callq 0x10f0
movq %rax, %rcx
movq -0xb40(%rbp), %rax
cmpq %rcx, %rax
jae 0x15cd
movq -0xa58(%rbp), %rax
movslq -0xb04(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movslq -0xb08(%rbp), %rcx
movb (%rax,%rcx), %cl
imull $0x14, -0xb04(%rbp), %eax
addl -0xb08(%rbp), %eax
cltq
movb %cl, -0xa50(%rbp,%rax)
movl -0xb08(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xb08(%rbp)
jmp 0x1556
movq -0xa58(%rbp), %rax
movslq -0xb04(%rbp), %rcx
movq (%rax,%rcx,8), %rdi
callq 0x10f0
movl %eax, -0xb08(%rbp)
cmpl $0x14, -0xb08(%rbp)
jge 0x161b
imull $0x14, -0xb04(%rbp), %eax
addl -0xb08(%rbp), %eax
cltq
movb $0x0, -0xa50(%rbp,%rax)
movl -0xb08(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xb08(%rbp)
jmp 0x15ea
jmp 0x165a
movl $0x0, -0xb08(%rbp)
cmpl $0x14, -0xb08(%rbp)
jge 0x1658
imull $0x14, -0xb04(%rbp), %eax
addl -0xb08(%rbp), %eax
cltq
movb $0x0, -0xa50(%rbp,%rax)
movl -0xb08(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xb08(%rbp)
jmp 0x1627
jmp 0x165a
jmp 0x165c
movl -0xb04(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xb04(%rbp)
jmp 0x1523
jmp 0x1672
leaq -0xa50(%rbp), %rdi
movl $0xa00, %esi            # imm = 0xA00
movq 0x492b(%rip), %rdx      # 0x5fb0
xorl %ecx, %ecx
movq 0x4952(%rip), %r8       # 0x5fe0
callq 0x1170
cmpl $0x0, -0x1c(%rbp)
jne 0x1907
movl $0x1, -0x4c(%rbp)
movl -0x4c(%rbp), %eax
cmpl -0x20(%rbp), %eax
jge 0x171c
movl -0x4c(%rbp), %ecx
leaq -0x48(%rbp), %rdi
movl $0x1, %esi
movq 0x4901(%rip), %rdx      # 0x5fc0
xorl %r8d, %r8d
movq 0x4917(%rip), %r9       # 0x5fe0
callq 0x1030
movq -0x40(%rbp), %rdi
movl -0x4c(%rbp), %eax
subl $0x1, %eax
imull -0x48(%rbp), %eax
cltq
addq %rax, %rdi
movl -0x48(%rbp), %esi
movl -0x4c(%rbp), %ecx
movq 0x48c2(%rip), %rdx      # 0x5fb0
xorl %r8d, %r8d
movq 0x48e8(%rip), %r9       # 0x5fe0
callq 0x1030
movl -0x1c(%rbp), %esi
movl -0x4c(%rbp), %edx
leaq 0x28fe(%rip), %rdi      # 0x4008
movb $0x0, %al
callq 0x1040
movl -0x4c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
jmp 0x16a4
movl -0x20(%rbp), %eax
decl %eax
movq %rsp, %rcx
movq %rcx, -0xb10(%rbp)
leaq 0xf(,%rax,4), %rdx
andq $-0x10, %rdx
movq %rsp, %rcx
subq %rdx, %rcx
movq %rcx, -0xb50(%rbp)
movq %rcx, %rsp
movq %rax, -0xb18(%rbp)
movl -0x20(%rbp), %eax
decl %eax
leaq 0xf(,%rax,8), %rdx
andq $-0x10, %rdx
movq %rsp, %rcx
subq %rdx, %rcx
movq %rcx, -0xb48(%rbp)
movq %rcx, %rsp
movq %rax, -0xb20(%rbp)
movl $0x1, -0x4c(%rbp)
movl -0x4c(%rbp), %eax
cmpl -0x20(%rbp), %eax
jge 0x185e
movq -0xb50(%rbp), %rdi
movslq -0x4c(%rbp), %rax
shlq $0x2, %rax
addq %rax, %rdi
addq $-0x4, %rdi
movl -0x4c(%rbp), %ecx
movl $0x1, %esi
movq 0x4812(%rip), %rdx      # 0x5fc0
xorl %r8d, %r8d
movq 0x4828(%rip), %r9       # 0x5fe0
leaq -0x38(%rbp), %rax
subq $0x10, %rsp
movq %rax, (%rsp)
callq 0x1130
movq -0xb48(%rbp), %rdi
addq $0x10, %rsp
movslq -0x4c(%rbp), %rax
shlq $0x3, %rax
addq %rax, %rdi
addq $-0x8, %rdi
movl -0x4c(%rbp), %ecx
movl $0x1, %esi
movq 0x47f6(%rip), %rdx      # 0x5fe8
xorl %r8d, %r8d
movq 0x47e4(%rip), %r9       # 0x5fe0
leaq -0x38(%rbp), %rax
subq $0x10, %rsp
movq %rax, (%rsp)
callq 0x1130
addq $0x10, %rsp
movq -0x40(%rbp), %rdi
movl -0x4c(%rbp), %eax
subl $0x1, %eax
imull -0x48(%rbp), %eax
cltq
addq %rax, %rdi
movl -0x48(%rbp), %esi
movl -0x4c(%rbp), %ecx
movq 0x477f(%rip), %rdx      # 0x5fb0
xorl %r8d, %r8d
movq 0x47a5(%rip), %r9       # 0x5fe0
leaq -0x38(%rbp), %rax
subq $0x10, %rsp
movq %rax, (%rsp)
callq 0x1130
addq $0x10, %rsp
movl -0x4c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
jmp 0x177d
movl $0x0, -0x4c(%rbp)
movl -0x4c(%rbp), %eax
movl -0x20(%rbp), %ecx
subl $0x1, %ecx
cmpl %ecx, %eax
jge 0x18ae
movq -0xb50(%rbp), %rax
movq -0x40(%rbp), %rdi
movl -0x4c(%rbp), %ecx
imull -0x48(%rbp), %ecx
movslq %ecx, %rcx
addq %rcx, %rdi
movslq -0x4c(%rbp), %rcx
movslq (%rax,%rcx,4), %rdx
movq -0xa68(%rbp), %rcx
movl $0x1, %esi
callq 0x11c0
movl -0x4c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
jmp 0x1865
movq -0xb50(%rbp), %r9
movq -0xb48(%rbp), %r8
movq -0xa70(%rbp), %rdi
movq -0xa58(%rbp), %rsi
movslq -0x44(%rbp), %rdx
movl -0x20(%rbp), %ecx
subl $0x1, %ecx
callq 0x2750
movq -0xa60(%rbp), %rdi
callq 0x11b0
movq -0xa68(%rbp), %rdi
callq 0x11b0
movq -0xa70(%rbp), %rdi
callq 0x11b0
movq -0xb10(%rbp), %rax
movq %rax, %rsp
cmpl $0x0, -0x1c(%rbp)
je 0x1af2
movl $0x0, -0x4c(%rbp)
cmpl $0x80, -0x4c(%rbp)
jge 0x1970
leaq -0xa50(%rbp), %rdi
imull $0x14, -0x4c(%rbp), %eax
cltq
addq %rax, %rdi
callq 0x10f0
cmpq $0x0, %rax
jbe 0x1963
leaq -0xa50(%rbp), %rdi
imull $0x14, -0x4c(%rbp), %eax
cltq
addq %rax, %rdi
callq 0x1160
movq %rax, %rdx
movq -0xa58(%rbp), %rax
movslq -0x4c(%rbp), %rcx
movq %rdx, (%rax,%rcx,8)
jmp 0x1965
movl -0x4c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
jmp 0x1918
leaq -0x48(%rbp), %rdi
movl $0x1, %esi
movq 0x4640(%rip), %rdx      # 0x5fc0
xorl %r8d, %r8d
movq 0x4656(%rip), %r9       # 0x5fe0
leaq -0x38(%rbp), %rax
subq $0x10, %rsp
movl %r8d, %ecx
movq %rax, (%rsp)
callq 0x1130
addq $0x10, %rsp
movl -0x48(%rbp), %esi
leaq 0x267c(%rip), %rdi      # 0x4028
movb $0x0, %al
callq 0x1040
movslq -0x48(%rbp), %rdi
shlq $0x0, %rdi
callq 0x10b0
movq %rax, -0x40(%rbp)
movslq -0x48(%rbp), %rdi
shlq $0x0, %rdi
callq 0x10b0
movq %rax, -0xb28(%rbp)
movq -0x40(%rbp), %rdi
movl -0x48(%rbp), %esi
movq 0x45ca(%rip), %rdx      # 0x5fb0
xorl %r8d, %r8d
movq 0x45f0(%rip), %r9       # 0x5fe0
leaq -0x38(%rbp), %rax
subq $0x10, %rsp
movl %r8d, %ecx
movq %rax, (%rsp)
callq 0x1130
addq $0x10, %rsp
movl -0x1c(%rbp), %esi
leaq 0x261b(%rip), %rdi      # 0x402d
movb $0x0, %al
callq 0x1040
movl $0x0, -0xb2c(%rbp)
movq $0x0, -0xb38(%rbp)
movq -0x40(%rbp), %rdi
movl -0x48(%rbp), %edx
movq -0xa58(%rbp), %rcx
movq -0xb28(%rbp), %r8
xorl %esi, %esi
leaq -0xb2c(%rbp), %r9
leaq -0xb38(%rbp), %rax
subq $0x10, %rsp
movq %rax, (%rsp)
callq 0x2470
addq $0x10, %rsp
movl -0x1c(%rbp), %esi
movl -0xb2c(%rbp), %edx
movq -0xb38(%rbp), %rcx
leaq 0x25bf(%rip), %rdi      # 0x403a
movb $0x0, %al
callq 0x1040
leaq -0xb2c(%rbp), %rdi
movl $0x1, %esi
movq 0x452b(%rip), %rdx      # 0x5fc0
xorl %r8d, %r8d
movq 0x4541(%rip), %r9       # 0x5fe0
movl %r8d, %ecx
callq 0x1030
leaq -0xb38(%rbp), %rdi
movl $0x1, %esi
movq 0x452e(%rip), %rdx      # 0x5fe8
xorl %r8d, %r8d
movq 0x451c(%rip), %r9       # 0x5fe0
movl %r8d, %ecx
callq 0x1030
movq -0xb28(%rbp), %rdi
movl -0xb2c(%rbp), %esi
movq 0x44d0(%rip), %rdx      # 0x5fb0
xorl %r8d, %r8d
movq 0x44f6(%rip), %r9       # 0x5fe0
movl %r8d, %ecx
callq 0x1030
xorl %eax, %eax
movq %rbp, %rsp
popq %rbp
retq
nopl (%rax)