%EUSIPCO 2012
%Imperial College London 
%Andriy Gelman, Jon Onativia and Pier Luigi Dragotti 

function [decoded_data, block_rate] = rate_allocation(compressed_output, bpp, layer_header,  r, c, k, total_segmentation_cost, rate, passes, distortion, distortion_scaled, information_data, index_distortion)

total_number_of_blocks = length(rate);
    
%desired_rate = bpp(inc)*r*c*k - ceil(total_segmentation_cost/8);
    
desired_rate = bpp*r*c*k - total_segmentation_cost;

if desired_rate > 0
    
    %recalculate incremental distortion if it is positive   
    %Evaluate optimum truncation points for this value of lamda
    %Choose two value for lamda, and obtain the optimum value by disection.
    
    %Initialize
    %desired_rate = desired_rate - floor(total_segmentation_cost/8);
    [optimum_pass] = lagrangian_multipliers_v2(rate, distortion_scaled, passes, desired_rate, index_distortion, total_number_of_blocks);
    
    load block_data.mat
    load decoded_data.mat
    load block_label_data.mat
    
    %Decode each data block
    block_rate= zeros(1, total_number_of_blocks);
    %Encode each of the subbands to the above rates, and extract the decoded
    %image
    for i = 1:length(index_distortion);
        
        if i == 85
            stop_here = 1;
        end
        if optimum_pass(index_distortion(i)) > 0
            
            information_buffer = information_data{index_distortion(i)};
            %[rows_dat] = information_buffer(7);
            %cols_dat = information_buffer(8);
            [rows_dat, cols_dat] = size(decoded_data{index_distortion(i)});
            
            largest_bit_plane = information_buffer(9);
            
            string_output = compressed_output{index_distortion(i)};
            rate_output = rate{index_distortion(i)};
            passes_buffer = passes{index_distortion(i)};
            distortion_buffer = distortion{index_distortion(i)};
            
            ind_loc = find(passes_buffer == optimum_pass(index_distortion(i)));
            ind_loc = ind_loc(1);
            %Write the data to a text file
            
            data_length = rate_output(ind_loc);
            data_length = data_length(1);
            %write only allowed data to text file
            fid = fopen('output_data.txt', 'wb');
            fwrite(fid, string_output(1:data_length));
            fclose(fid);
            
            
            %Ensure label data is in the right format, where all the
            %data is one
            buffer = block_label_data{index_distortion(i)};
            buffer(buffer>0) = 1;
            block_label_data{index_distortion(i)} = buffer;
            
            
            [decoded_data{index_distortion(i)}] = EBCOT_decompress(rows_dat, cols_dat, largest_bit_plane, optimum_pass(index_distortion(i)), block_label_data{index_distortion(i)});
            block_rate(index_distortion(i)) = data_length;
            
            %sum(sum((decoded_data{index_distortion(i)} - block_data{index_distortion(i)}).^2))
            %distortion_buffer(ind_loc)
            
            while (sum(sum((decoded_data{index_distortion(i)} - block_data{index_distortion(i)}).^2)) ~= distortion_buffer(ind_loc))
                
                %update data length
                data_length = data_length + 1;
                
                fid = fopen('output_data.txt', 'wb');
                if (data_length <= length(string_output))
                    fwrite(fid, string_output(1:data_length));
                    fclose(fid);
                else
                    stop_here = 1;
                end
                
                buffer = block_label_data{index_distortion(i)};
                buffer(buffer>0) = 1;
                block_label_data{index_distortion(i)} = buffer;
                
                [decoded_data{index_distortion(i)}] = EBCOT_decompress(rows_dat, cols_dat, largest_bit_plane, optimum_pass(index_distortion(i)), block_label_data{index_distortion(i)});
                block_rate(index_distortion(i)) = data_length; 
    
            end        
        end
    end
    
    clear block_data;
    clear block_label_data;
   
end