close all;
clear all;

% errorPerc = 0.8;
addpath('..\matlab');
addpath('..\hw\fpga\models');
addpath('..\ref_impl\matlab\DecoderFunctions');
addpath('..\ref_impl\matlab\MatricesGenerationByPos');

tb_filePath = '..\\hw\\sim\\data\\vbc';


% This value are read from the LEDA tables.

%% LEDA params:
% Code cat 4, n0=2
% p   = 7547; 
% n0  = 4;
% d_v = 13;
% m_v = [2 2 2 1];

%% System Parameters
useTestValues = 1;

if useTestValues==1
    % USED FOR TESTING This is a test for some particular value we want to simulator for perf.
    % p = 31;
    p = 499; % 9643;
    n0 = 3;
    Nb = 16;
    d_v = 13; 
    m_v = [3 2 2];
    extra_bits = 0; % 2; % 0;
else
    % LEDA p values: 14939,7853,7547; 25693,16067,14341; 36877,27437,22691
    p = 14341; % 22691;
    Nb = 16;
    extra_bits = 2;
    [n0, d_v, m_v] = getLEDAParams(p);
end


%% Code generation
LVec = GenLMat(p, n0, d_v, m_v);

LPos_1 = zeros(1, d_v);
LPos_2 = zeros(1, d_v);
LPos_3 = zeros(1, d_v);
LPos_4 = zeros(1, d_v);
if n0 == 2
    LPos_1 = sort(LVec(1, :));
    LPos_2 = sort(LVec(2, :));
elseif n0 == 3
    LPos_1 = sort(LVec(1, :));
    LPos_2 = sort(LVec(2, :));
    LPos_3 = sort(LVec(3, :));
elseif n0 == 4
    LPos_1 = sort(LVec(1, :));
    LPos_2 = sort(LVec(2, :));
    LPos_3 = sort(LVec(3, :));
    LPos_4 = sort(LVec(4, :));
end

% Make sure we have not boggus values
if n0 == 2
    assert(isempty(LPos_1(LPos_1 == -1)));
    assert(isempty(LPos_2(LPos_2 == -1)));
elseif n0 == 3
    assert(isempty(LPos_1(LPos_1 == -1)));
    assert(isempty(LPos_2(LPos_2 == -1)));
    assert(isempty(LPos_3(LPos_3 == -1)));
elseif n0 == 4
    assert(isempty(LPos_1(LPos_1 == -1)));
    assert(isempty(LPos_2(LPos_2 == -1)));
    assert(isempty(LPos_3(LPos_3 == -1)));
    assert(isempty(LPos_4(LPos_4 == -1)));
end




% Now for convinience we add 0 to reach a memory that have a number of entries that is a power of two. 
d_v_add_rows = 2^nextpow2(d_v)-d_v;
d_v_ext = 2^nextpow2(d_v);

pos_mem = LPos_1;
pos_mem_ext = [pos_mem zeros(1, d_v_add_rows)];

p_in_bits = ceil(log2(p));

%% In Files
% First generate the folders, if they are not existing
checkDir(sprintf('%s\\in\\%d\\%d', tb_filePath, p, Nb));
checkDir(sprintf('%s\\out\\%d\\%d', tb_filePath, p, Nb));

outDvMemFile = fopen(sprintf('%s\\in\\%d\\%d\\pos_mem_%d.txt', tb_filePath,  p, Nb, d_v), 'w');
outMessageMemFile = fopen(sprintf('%s\\in\\%d\\%d\\msg_mem.txt', tb_filePath, p, Nb), 'w');

%%  Out Files
outRefFile = fopen(sprintf('%s\\out\\%d\\%d\\ref_mem_%d.txt', tb_filePath, p, Nb, d_v), 'w');

%%


% First generate the a_data mem!
a_data = round(rand(1, p));

% Than make it into a memory.
mem_row_num = ceil(p/Nb);

% Make an extendeddata arraw containing 0s in oreder to be row aligned
a_data_ext = [a_data zeros(1, mem_row_num*Nb - p)];
a_data_mem = reshape(a_data_ext, Nb, mem_row_num)'; 

% First write the current config value to the file, the tb read this to
% config the memory appropratly.
fprintf(outMessageMemFile, sprintf('### %d, %d, %d\n', p, n0, Nb));

% Save the result to the file!
for idx=1:mem_row_num
    row_bits = a_data_mem(idx, :);
   
   
   % NOTE: MATLAB don't allow to write big array using bi2de/dec2bin because
   % long sequence would result in value overflow, so we stupidly write
   % char by char!
   writeBigArray(outMessageMemFile, row_bits); 
end

% Save the positions of ones
% First write the current config value to the file, the tb read this to
% config the memory appropratly.
fprintf(outDvMemFile, sprintf('### %d, %d, %d(%d)\n', p, n0, d_v, d_v_ext));

for idx=1:d_v_ext
    fprintf(outDvMemFile, sprintf('%s\n', dec2bin(pos_mem_ext(idx), p_in_bits)));
end


fclose(outDvMemFile);
fclose(outMessageMemFile);

% Now perform the reference multiplication, first we have to transponse the
% the b_data indices.
pos_tran = mod(p-pos_mem, p);
refResult = VectorByCirculant(a_data, pos_tran, 0);

refResultHW = FFT_VecByCirc_HW(a_data, pos_mem, p, extra_bits);

diff = find(refResult ~= refResultHW);
assert(isempty(diff)); 

% Create a new memory for the result, same code as above. 
% We know it have the same row number and Nb
refResult_ext = [refResult zeros(1, mem_row_num*Nb - p)];
refMem = reshape(refResult_ext, Nb, mem_row_num)';

for idx=1:mem_row_num
    ref_bits = refMem(idx, :);
    writeBigArray(outRefFile, ref_bits); 
end

fclose(outRefFile);

fprintf('Done Generating Inputs! TB generics are:\n');
fprintf('\t p: %d, Nb: %d, D_V: %d  \n', p, Nb, d_v); 

% Help Functions
function [lMat] = GenLMat(p, n0, d_v, m_v)
    if n0 == 2
        [LPos] = Key_generator(n0, p, d_v, m_v);
    elseif n0 == 3
        [LPos] = Key_generator_n0_3(n0, p, d_v, m_v);
    elseif n0 == 4
        [LPos] = Key_generator_n0_4(n0, p, d_v, m_v);
    end
    
    % Remove boggus LPos value, also set this to 0 based not 1 based
    LPos = LPos - 1;
    LPos(LPos==-1) = [];
    
    % We need in our imp the values of L to be sorted.
    lMat = LPos;
end
