


function plotting_encoder(input, filename)
% input='ABBCBCABABCAABCAABAAABDEA';

[encoded_stream_plain, encoded_stream_fancy, comp_ratio, comp_rate, entropy, dic_fancy, number_of_bits_reference, number_of_bits_enc]=LZ78encoderB(input);

input=num2str(input);


%% Figure allignement
f=figure(); 
set(f,'visible','off');
set(gca,'visible','off');



x0=400;
y0=100;
width=600;
height=450;
set(gcf,'position',[x0,y0,width,height])


%% Drawing an empty dicitonary

   empty_latex_table = ['\begin{tabular}{|c|c|}  \multicolumn{2}{c}{\textbf{Encoder Dictionary}}\\ \hline Index&String\\ \hline & \\\hline & \\',...
 '\hline & \\\hline & \\\hline & \\\hline & \\\hline & \\\hline & \\\hline & \\\hline & \\\hline & \\\hline & \\\hline & \\\hline \end{tabular}']; 
a = annotation('textbox',[0.62 0.8 0.2 0.2], 'EdgeColor','none', 'FitBoxToText','on','interpreter', 'latex'); %[x y w h]    
a.FontSize=18;
    %set(a, 'String', empty_latex_table);

     a.String = empty_latex_table;

%%  Write the word "input"


b = annotation('textbox',[0 0.8 0.2 0.2], 'EdgeColor','none', 'FitBoxToText','on', 'String', '\underline{\underline{\textbf{Input:}}} \\',  'interpreter', 'latex'); %[x y w h]
b.FontSize=18;


     latex_input='\underline{\underline{\textbf{Input:}}} \\ ';
     %b.String = latex_input;
     %set(b, 'String', '');

%% Box for input

b = annotation('textbox',[0.01 0.72 0.60 0.2], 'EdgeColor','black','LineWidth',1,  'Interpreter', 'latex','String',''); %[x y w h]
b.FontSize=18;

     %set(b, 'String', '');

     %b.String = 'abc';

%% Draw Output

b = annotation('textbox',[0 0.5 0.2 0.2], 'EdgeColor','none', 'FitBoxToText','on', 'Interpreter', 'latex'); %[x y w h]
b.FontSize=18;
     latex_input='\underline{\underline{\textbf{Encoded Output:}}} \\ ';
     %set(b, 'String', latex_input);

     b.String = latex_input;

     
%% Box for Output

b = annotation('textbox',[0.01 0.32 0.60 0.3], 'EdgeColor','black','LineWidth',1, 'Interpreter', 'latex'); %[x y w h]
b.FontSize=18;
     %set(b, 'String','');
      b.String = '';


%% Save default figures
 %saveas(gcf,'default_figure.png')
%print(f, '-dpng','-r0', filename);

 new_filename = [filename '_0' ];
print(new_filename, '-dpng' );
 
 oldStr='';
 input_index=1;
output='';
input_string='';

fancy_index=1;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for i=1:length(dic_fancy)

f=figure(); 
set(f,'visible','off');
set(gca,'visible','off');

hold all

x0=400;
y0=100;
width=600;
height=450;
set(gcf,'position',[x0,y0,width,height])
%%  Write the word "input"

b = annotation('textbox',[0 0.8 0.2 0.2], 'EdgeColor','none', 'FitBoxToText','on', 'Interpreter', 'latex'); %[x y w h]
b.FontSize=18;
latex_input='\underline{\underline{\textbf{Input:}}} \\ ';
%set(b, 'String', latex_input);
     b.String = latex_input;

%% %% Box for input

b = annotation('textbox',[0.01 0.72 0.60 0.2], 'EdgeColor','black','LineWidth',1,  'Interpreter', 'latex'); %[x y w h]
b.FontSize=18;

input_string_2=[input_string, '\textbf{\underline{',input(input_index:input_index+length(dic_fancy{i})-1),'}}'];
input_string=[input_string, input(input_index:input_index+length(dic_fancy{i})-1),' '];

%set(b, 'String', input_string_2);
     b.String =['', input_string_2, ''];

input_index=input_index + length(dic_fancy{i});

%% Draw Encoder Dictionary

if i < 19  %To handle the error in drawing the dicitonary
   latex_table_2=['\begin{tabular}{|c|c|}  \multicolumn{2}{c}{\textbf{Encoder Dictionary}}\\ \hline Index&String\\ \hline',  ...
       [oldStr, '\textbf{\underline{',num2str(i),'}}','&','\textbf{\underline{', dic_fancy{i},'}}','\\ \hline'],...
            ]; 
   latex_table = ['\begin{tabular}{|c|c|}  \multicolumn{2}{c}{\textbf{Encoder Dictionary}}\\ \hline Index&String\\ \hline',  ...
       [oldStr, num2str(i),'&', dic_fancy{i},'\\ \hline'],...
            ]; 
   
   for j=1:(13-i)  %%adds empty cells
       latex_table = [latex_table, ' & \\\hline'];
       latex_table_2 = [latex_table_2, ' & \\\hline'];
   end
    latex_table=[latex_table,' \end{tabular}'];
    latex_table_2=[latex_table_2,' \end{tabular}'];

   oldStr=[oldStr, num2str(i),'&', dic_fancy{i},'\\ \hline'];

a = annotation('textbox',[0.62 0.8 0.2 0.2], 'EdgeColor','none', 'FitBoxToText','on', 'Interpreter', 'latex'); %[x y w h]    
    a.FontSize=18;
    %set(a, 'String', latex_table_2);
     a.String =['', latex_table_2,''];
else
    a = annotation('textbox',[0.62 0.8 0.2 0.2], 'EdgeColor','none', 'FitBoxToText','on', 'Interpreter', 'latex'); %[x y w h]    
    a.FontSize=18;
    %set(a, 'String', latex_table_2);
     a.String =['', latex_table,''];
end


%% Draw  "Encoded Output: "

b = annotation('textbox',[0 0.5 0.2 0.2], 'EdgeColor','none', 'FitBoxToText','on', 'Interpreter', 'latex'); %[x y w h]
b.FontSize=18;
     latex_input='\underline{\underline{\textbf{Encoded Output:}}} \\ ';
     %set(b, 'String', latex_input);
     b.String = latex_input;

%% Box for output
b = annotation('textbox',[0.01 0.32 0.60 0.3], 'EdgeColor','black','LineWidth',1, 'Interpreter', 'latex'); %[x y w h]
b.FontSize=18;

output_fancy='';
while encoded_stream_fancy(fancy_index) ~= ')'
output_fancy=[output_fancy encoded_stream_fancy(fancy_index)];
fancy_index= fancy_index + 1;
end

output_fancy =[output_fancy, ')'];

if fancy_index < length(encoded_stream_fancy)
fancy_index= fancy_index + 1;
end

output_2=[output, '\textbf{\underline{',output_fancy,'}} '];
output =[output, output_fancy,' '];

%set(b, 'String', output_2);
     b.String =['', output_2, ''];

%%

%% Draw Compression Ratio on last figure
if input_index == length(input)+1

 
 b = annotation('textbox',[0.01 0 0.6 0.3], 'EdgeColor','none','LineWidth',1, 'Interpreter', 'latex'); %[x y w h]
b.FontSize=18;
output =['\textbf{\textit{\# of bits uncompressed:}} ', num2str(number_of_bits_reference), '\\ \textbf{\textit{\# of bits compressed:}} ', num2str(number_of_bits_enc), '\\ \textbf{\textit{Compression Ratio (CR):}} ',num2str(comp_ratio)];
set(b, 'String', output);
end

hold off;
set(gca,'XTick',[]);
set(gca,'YTick',[]);
set(gca,'Box','off');

hold off;
 new_filename = [filename '_' num2str(i)];
print(new_filename, '-dpng' ); 

%    saveas(gcf,['input_', num2str(i),'.png'])
%print(f,[filename, '_', num2str(i)], '-dpng', '-r0');
%print(f, '-dpng','-r0', filename);

counter=i;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% handles the last input
if input_index == length(input)  || input_index < length(input)
  f=figure(); 
set(f,'visible','off');
set(gca,'visible','off');

x0=400;
y0=100;
width=600;
height=450;
set(gcf,'position',[x0,y0,width,height])
%%  Write the word "input"

b = annotation('textbox',[0 0.8 0.2 0.2], 'EdgeColor','none', 'FitBoxToText','on', 'Interpreter', 'latex'); %[x y w h]
b.FontSize=18;
latex_input='\underline{\underline{\textbf{Input:}}} \\ ';
%set(b, 'String', latex_input);
     b.String = latex_input;

%% %% Box for input

b = annotation('textbox',[0.01 0.72 0.60 0.2], 'EdgeColor','black','LineWidth',1,  'Interpreter', 'latex'); %[x y w h]
b.FontSize=18;

input_string=[input_string, '\textbf{\underline{',input(input_index:end),'}} '];
%set(b, 'String', input_string);
     b.String = input_string;

%% Draw Encoder Dictionary
   latex_table = ['\begin{tabular}{|c|c|}  \multicolumn{2}{c}{\textbf{Encoder Dictionary}}\\ \hline Index&String\\ \hline',  ...
       oldStr]; 
   
   for j=1:(13-length(dic_fancy))  %%adds empty cells
       latex_table = [latex_table, ' & \\\hline'];
   end
    latex_table=[latex_table,' \end{tabular}'];

    a = annotation('textbox',[0.62 0.8 0.2 0.2], 'EdgeColor','none', 'FitBoxToText','on', 'Interpreter', 'latex'); %[x y w h]    
    a.FontSize=18;
    %set(a, 'String', latex_table);
         a.String = latex_table;

%% Draw  "Encoded Output: "

b = annotation('textbox',[0 0.5 0.2 0.2], 'EdgeColor','none', 'FitBoxToText','on', 'Interpreter', 'latex'); %[x y w h]
b.FontSize=18;
     latex_input='\underline{\underline{\textbf{Encoded Output:}}} \\ ';
     %set(b, 'String', latex_input);
     b.String = latex_input;

%% Box for output
b = annotation('textbox',[0.01 0.32 0.60 0.3], 'EdgeColor','black','LineWidth',1, 'Interpreter', 'latex'); %[x y w h]
b.FontSize=18;
output =[output, '\textbf{\underline{',encoded_stream_fancy(5*(length(dic_fancy))+1:end),'}}'];
%set(b, 'String', output);
     b.String = output;

%% Draw Compression Ratio on last figure
 
 b = annotation('textbox',[0.01 0 0.6 0.3], 'EdgeColor','none','LineWidth',1, 'Interpreter', 'latex'); %[x y w h]
b.FontSize=18;
output =['\textbf{\textit{\# of bits uncompressed:}} ', num2str(number_of_bits_reference), '\\ \textbf{\textit{\# of bits compressed:}} ', num2str(number_of_bits_enc), '\\ \textbf{\textit{Compression Ratio (CR):}} ',num2str(comp_ratio)];
set(b, 'String', output);

 %saveas(gcf,['input_', num2str(length(dic_fancy)+1),'.png'])
%print(f,[filename, '_',num2str(length(dic_fancy)+1)], '-dpng', '-r0');

 new_filename = [filename '_' num2str(length(dic_fancy)+1)];
saveas(f,new_filename,'png');

counter=counter+1;
end



while counter < 40

new_filename = [filename '_' num2str(counter)];
saveas(f,new_filename,'png');
counter = counter + 1;

end



end




function [encoded_stream_plain, encoded_stream_fancy, comp_ratio, comp_rate, entropy, dic_fancy, number_of_bits_refrence, number_of_bit_in_encoded_stream] = LZ78encoderB(input_text)
input_text = num2str(input_text);
% clc;
% clear all;
% close all;

%Prepares the Output (encoded) file.
write_file = fopen('LZ78_encoded.txt','w');

write_file2 = fopen('LZ78_encoded_fancy.txt','w');
  

%Prepares input to be encoded in an array of characters
char_array = reshape(input_text,[],1);


number_of_chars_in_input=size(char_array, 1);

unique_chars = unique(char_array);

processing_array = dec2bin(double(char_array),8);

processing_array=processing_array.';


%% Prepare an empty dictionary and an empty encoded stream string
dic= [];  %empty array
dic_fancy=[];
encoded_stream_plain = ''; 
encoded_stream_fancy = '';  

prefix='';  
prefix_fancy='';


%% Calculates the character probability and the Entropy


char_probability_vector=[];

for i=1:length(unique_chars)
    char_probability_vector(i)= sum(char_array == unique_chars(i))./number_of_chars_in_input;
end

entropy = -sum(char_probability_vector.*log2(char_probability_vector));
%% Pre-processing

dic_index = 1;
index=1;
codeword_number=1;

%% The core of the encoding algorithm

while index <= size(processing_array,2)  %while there is still elements to be encoded

    next_char = reshape(processing_array(:,index),1,[]); %Fetch the next element
    next_char_fancy = char(bin2dec(next_char));
    
%     processing_array(1) = [];  %Removes the first element from the array
    
%     strcat(prefix,next_char)
    if ~isempty(find(ismember(dic, [prefix next_char])))  %checks if the processed input is in the dictionary
        
        prefix = [prefix next_char];  %if yes, adds it to prefix until an input is found which is not in the dictionary
        prefix_fancy=[prefix_fancy char(bin2dec(next_char))];
        
    else  %handles the case in which input is NOT in the dictionary
        
        %Calculate the number of bits needed for dic index representation
        if codeword_number == 1
            number_of_bits = 1;
        else
            number_of_bits = ceil(log2(codeword_number));
        end
        codeword_number = codeword_number + 1;
        
        if isempty(prefix) %the case where even the prefix of the input is not in the dictionary (brand new input)
            
            codeword = dec2bin(0, number_of_bits);
            codeword_fancy='0';
            
        else  %handles the case where the prefix of the input is in the dictionary (ex. if 'A' is in the dictionary and our input is 'AB')
            
            codeword = dec2bin(find(ismember(dic, prefix)), number_of_bits); %gets the index of the prefix
            codeword_fancy = num2str(find(ismember(dic, prefix)));
        end
        
        encoded_stream_plain=[encoded_stream_plain codeword next_char]; %inserts the encoded codeword in the encoded stream (without brackets & commas)
        encoded_stream_fancy=[encoded_stream_fancy '(' codeword_fancy ',' next_char_fancy ')']; %inserts the encoded codeword in the encoded stream (WITH brackets & commas)
        
        dic{dic_index}= [prefix next_char]; %adds the new codeword to the dictionary
        
        dic_fancy{dic_index}=[prefix_fancy next_char_fancy];
        
        dic_index = dic_index + 1;   %increments the dictionary index
        
        prefix = '';  %resets the prefix to empty
        prefix_fancy='';
        
    end
    
    index = index + 1;
           
end

%The following if statement encodes the last portion of the input stream
%and terminates the encoding processut
if ~isempty(prefix)
    
    codeword = dec2bin(find(ismember(dic, prefix)), number_of_bits);
    codeword_fancy = num2str(find(ismember(dic, prefix)));
    
    encoded_stream_plain=[encoded_stream_plain  codeword];   
    encoded_stream_fancy=[encoded_stream_fancy '(' codeword_fancy ', EOT)']; %'EOT' == end of text
        
end      
 encoded_stream_plain;
 encoded_stream_fancy;
fwrite(write_file, encoded_stream_plain, '*char');
fclose(write_file);
fwrite(write_file2, encoded_stream_fancy, '*char');
fclose(write_file2);

%% Calculates the compression ratio (CR) with refrence to 8 bits encoding

number_of_bits_refrence = 8*number_of_chars_in_input;
number_of_bit_in_encoded_stream = length(encoded_stream_plain);

comp_ratio = number_of_bits_refrence/number_of_bit_in_encoded_stream;

%% Calculates the average bits/character (Compression Rate)

comp_rate = length(encoded_stream_plain)/number_of_chars_in_input;


end