function [cfun, hdecl] = sym2c(varName, expr, funcname, cfun, hdecl)
%MATLAB symbolic expressions to C/C++ code. See documentation for details.
%basile.graf@epfl.ch

inline = '__inline'; % '__inline' for Microsoft compiler, 'inline' otherwise
inline = ''; %not possible to inline in an imported file... snif

if length(varName)~=length(expr)
    disp('Error: not the same number of variables and expressions!');
    return;
end



firstCfunLine = length(cfun)+1; %first line for this function

cfun{length(cfun)+1} = [inline ' void ' funcname '(datas *d) {' ' \n'];

hdecl{length(hdecl)+1} = [inline ' void ' funcname '(datas *d); \n \n']; %for header file




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%create C output variable names:
m=1;
for n=1:length(expr)    
    if length(expr{n})>1
        for k=1:length(expr{n})
            cVarNames{m} = [varName{n} '[' num2str(k-1) ']'];
            m=m+1;
        end
    else
        cVarNames{m} = varName{n};
        m=m+1;
    end
end

%Put corresponding expressions in a matrix:
exprM=[];
for n=1:length(expr)      
    for k=1:length(expr{n})
        exprM = [exprM; expr{n}(k)];
    end
end

%Find external variables (from data structure):
str=findsym(exprM); %variable names from exprM in a string str
eval(['ExternVars={''' strrep(str,', ',''', ''') '''};']); %Put the names in a cell

[subTrigExpr exprM TrigVars]=subsTrigo(exprM);

%Extract sub-expressions:
[r,s] = subexpr(exprM,'tempV');
rLen = length(r);
sLen = length(s);

toSub={};
toBeSub={};

%Substitute tempV(i) with tempVi:
for n=1:length(s)
    toBeSub = [toBeSub {['tempV(' num2str(n) ')']}];
    toSub = [toSub {['tempV' num2str(n)]}];
end
if length(s)==1
    toBeSub = {'tempV'};
    toSub = {'tempV1'};
end

syms dummySymbol real
if ~isempty(s)
    for k=1:length(r)
       % try
            r(k) = subs(r(k)+dummySymbol,toBeSub,toSub);
            r(k) = r(k)-dummySymbol; %To avoid strange error...
        %catch
           % error('Error while substituing!!!!')
        %end
    end
end


%Create C temporary variable names:
for n=1:length(s)
    cTempVar{n} = ['tempV[' num2str(n-1) ']'];
end


%Create C temporary expressions:
 cTempExpr={};
for n=1:length(s)
    %cTempExpr{n} = ccode(s(n));
    %cTempExpr{n} = cTempExpr{n}(12:end); %eliminate automatic 't0 = '
            %Strange behaviour...
     
    vpaexpr = vpa(s(n)); %transform for ex: 1 to 1. , 1/3 to 0.33333333 . Avoid integer confusion in resulting C code        
    cTempExpr{n} = [m2c(char(vpaexpr)) ';'];    %MATLAB to C expression     
    cTempExpr{n} = putspaces(cTempExpr{n});%put spaces to avoid variable mixes
    
    for m=1:length(ExternVars) %for all variables in expression
        cTempExpr{n} = strrep(cTempExpr{n}, [' ' ExternVars{m} ' '], [' d->' ExternVars{m}]); %Replace var by d->var in C expression
    end
    
    cTempExpr{n} = [cTempVar{n} ' = ' cTempExpr{n} ' \n']; % Build code-line
    cTempExpr{n} = strrep(cTempExpr{n}, ' ', ''); %Suppress all spaces
end


%Create C output expressions:
for n=1:length(r)
    %cExpr{n} = ccode(r(n))
    %cExpr{n} = cExpr{n}(12:end); %eliminate automatic 't0 = '
            %Strange behaviour...
    
    vpaexpr = vpa(r(n)); %transform for ex: 1 to 1. , 1/3 to 0.33333333 . Avoid integer confusion in resulting C code
    cExpr{n} = [m2c(char(vpaexpr)) ';'];  %MATLAB to C expression
    cExpr{n} = putspaces(cExpr{n});%put spaces to avoid variable mixes
    
    for m=1:length(ExternVars) %for all variables in expression
        cExpr{n} = strrep(cExpr{n}, [' ' ExternVars{m} ' '], [' d->' ExternVars{m}]); %Replace var by d->var in C expression
    end
    
    cExpr{n} = strrep(cExpr{n}, ' ', ''); %Suppress all spaces
    cExpr{n} = putspaces(cExpr{n});%put spaces to avoid variable mixes
    
    for k=1:length(s)
        cExpr{n} = strrep(cExpr{n}, [' tempV' num2str(k) ' '], [' tempV[' num2str(k-1) '] ']); %replace tempi with temp[i-1]
    end
    
    cExpr{n} = ['d->' cVarNames{n} ' = ' cExpr{n} ' \n'];
    cExpr{n} = strrep(cExpr{n}, ' ', ''); %Suppress all spaces
end

% [subTrigExpr Trigexpr TrigVars]=subsTrigo([cTempExpr, cExpr]);
% for  n=1:length(Trigexpr)
%     Trigexpr{n} = putspaces(Trigexpr{n});%put spaces to avoid variable mixes
%     for k=1:length(TrigVars)
%         Trigexpr{n} = strrep(Trigexpr{n},[' ' TrigVars{k} ' '], ['trigV[' num2str(k-1) ']']);
%     end
%     Trigexpr{n} = strrep(Trigexpr{n}, ' ', ''); %Suppress all spaces
% end
% for n=1:length(cTempExpr)
% cTempExpr{n} = Trigexpr{n};
% end
% for n=length(cTempExpr)+1:length(Trigexpr)
% cExpr{n-length(cTempExpr)} = Trigexpr{n};
% end
% 
 for k=1:length(TrigVars)
     sTri = m2c(char(vpa(sym(subTrigExpr{k}))));
     sTri = putspaces(sTri);
     
     for m=1:length(ExternVars) %for all variables in expression
        sTri = strrep(sTri, [' ' ExternVars{m} ' '], [' d->' ExternVars{m} ' ']); %Replace var by d->var in C expression 
     end
     
     for n=1:length(TrigVars)
        sTri = strrep(sTri,[' ' TrigVars{n} ' '], ['trigoV[' num2str(n-1) ']']);
     end
     
     cTrig{k} = ['trigoV[' num2str(k-1) ']=' sTri '; \n'];
     %cTrig{k} = ['trigoV[' num2str(k-1) ']=' subTrigExpr{k} '; \n'];
     cTrig{k} = strrep(cTrig{k}, ' ', ''); %Suppress all spaces
 end

for n=1:length(cTempExpr)
    cTempExpr{n} = putspaces(cTempExpr{n});%put spaces to avoid variable mixes
    for k=1:length(TrigVars)
             cTempExpr{n} = strrep(cTempExpr{n},[' ' TrigVars{k} ' '], ['trigoV[' num2str(k-1) ']']);
    end
    cTempExpr{n} = strrep(cTempExpr{n}, ' ', ''); %Suppress all spaces
end

for n=1:length(cExpr)
    cExpr{n} = putspaces(cExpr{n});%put spaces to avoid variable mixes
    for k=1:length(TrigVars)
             cExpr{n} = strrep(cExpr{n},[' ' TrigVars{k} ' '], ['trigoV[' num2str(k-1) ']']);
    end
    cExpr{n} = strrep(cExpr{n}, ' ', ''); %Suppress all spaces
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

cfun{length(cfun)+1} = ' \n';

if ~isempty(s)
    cfun{length(cfun)+1} = ['double tempV[' num2str(length(cTempVar)) '];' ' \n']; %Declare temporary variable vector
end

if ~isempty(TrigVars)
    cfun{length(cfun)+1} = ['double trigoV[' num2str(length(TrigVars)) '];' ' \n \n']; %Declare temporary variable vector
end

for n=1:length(TrigVars)
    cfun{length(cfun)+1} = cTrig{n};
end

cfun{length(cfun)+1} = ' \n';

for n=1:length(s)
    cfun{length(cfun)+1} = cTempExpr{n};
end

cfun{length(cfun)+1} = ' \n';

for n=1:length(cExpr)
    cfun{length(cfun)+1} = cExpr{n};
end

cfun{length(cfun)+1} = ['return; \n'];
cfun{length(cfun)+1} = ['} \n \n \n'];


for line=firstCfunLine:length(cfun)
   cfun{line} = strrep(cfun{line}, '=', ' = '); %C'est plus joli!
end






function str=putspaces(str)
str=strrep(str,'+',' + ');
str=strrep(str,'-',' - ');
str=strrep(str,'*',' * ');
str=strrep(str,'/',' / ');
str=strrep(str,'^',' ^ ');
str=strrep(str,'(',' ( ');
str=strrep(str,')',' ) ');
str=strrep(str,',',' , ');
str=strrep(str,';',' ; ');
str=strrep(str,'=',' = ');
str = [' ' str ' '];