%% =====================================================================
%% Refactoring: En el caso que aparezca una función con una sola instrucción case, se sustituye dicha instrucción por guardas de la función
%% =====================================================================

-module(refac2_CaseFun).

-export([refac_CaseFun/1, refac_CaseFun_eclipse/1]).

-include("../include/wrangler.hrl").

-spec(refac_CaseFun/1::(filename()) -> 
	     {error, string()} | {question, string()} |{ok, [filename()], boolean()}).
refac_CaseFun(FileName) ->
    refac_CaseFun(FileName,emacs).

-spec(refac_CaseFun_eclipse/1::(filename()) ->
	     {error, string()} | {question, string()} | {warning, string()} |
		 {ok, [{filename(), filename(), string()}]}).
refac_CaseFun_eclipse(FileName) ->
    refac_CaseFun(FileName,eclipse).


refac_CaseFun(FileName,Editor) ->
	
	{ok,X} = smerl:for_file(FileName),
	Forms=smerl:get_forms(X),
	NXX = smerl:set_forms(X,lists:reverse(applyRefacCaseFun(Forms))),
	smerl:to_src(NXX,FileName),
	{ok,[]}.





%******************************************************************************************************************
%******************************************************************************************************************
%******************************************************************************************************************

applyRefacCaseFun([])->[];
applyRefacCaseFun([{function,LINE_FUN,Name,Arity,Clauses}|Funs]) ->
	[{function,LINE_FUN,Name,Arity,applyRefac_clausesGeneric(applyRefacCaseFunRecursive(Clauses))}|applyRefacCaseFun(Funs)];
applyRefacCaseFun(Other)->
	Other.

applyRefacCaseFunRecursive([])->[];
% cas especial de que sols siga un casae dins de la funció
applyRefacCaseFunRecursive([{clause,LINE_CLAUSE,Patterns,Guards,[{'case',LINE_CASE,VarCase,ClausesCase}]}|ClausesTail])->
	case VarCase of 
		[{_,_,_}] -> 	NewClauses=fusionaClauses(Patterns,VarCase,ClausesCase),
						applyRefac_clausesGeneric(NewClauses) ++ applyRefacCaseFunRecursive(ClausesTail);
		{_,_,_} -> 		NewClauses=fusionaClauses(Patterns,VarCase,ClausesCase),
						applyRefac_clausesGeneric(NewClauses)++ applyRefacCaseFunRecursive(ClausesTail);
		_ -> 	[{clause,LINE_CLAUSE,Patterns,Guards,[{'case',LINE_CASE,VarCase,ClausesCase}]}] ++ applyRefacCaseFunRecursive(ClausesTail)
	end;
applyRefacCaseFunRecursive([{clause,LINE_CLAUSE,Patterns,Guards,Body}|ClausesTail])->
	[{clause,LINE_CLAUSE,Patterns,Guards,Body}|applyRefacCaseFunRecursive(ClausesTail)].




fusionaClauses(ArgsFunc,VarCase,ClausesCase) -> 
 arguments i anem posantlos com a patterns de la clause i quan trobem el de la x el substituim pels patrons de la clause.
	NewPatterns=marcaPatterns(ArgsFunc,VarCase),
	addPatterns(NewPatterns,ClausesCase).
	
marcaPatterns([],_)->[];
marcaPatterns(Args,[])->Args;
marcaPatterns([{Tipo,_,Valor}|ArgTail],{Tipo,_,Valor})->
	[{Tipo,x,Valor}|ArgTail];
marcaPatterns([ArgHead|ArgTail],VarCase)->
	[ArgHead|marcaPatterns(ArgTail,VarCase)].



addPatterns(_,[]) -> [];
addPatterns(Args,[{clause,LINE_CLAUSE,Patterns,Guards,Body}|ClauseTail]) ->
	[{clause,LINE_CLAUSE,addPatternRecurs(Args,Patterns),Guards,Body}|addPatterns(Args,ClauseTail)].
	
	
addPatternRecurs([],_)->[];
addPatternRecurs([{_,x,_}|ArgsTail],Patterns)->Patterns++ArgsTail;
addPatternRecurs([Other|ArgsTail],Patterns)-> [Other|addPatternRecurs(ArgsTail,Patterns)].

	
	
%******************************************************************************************************************
%******************************************************************************************************************
%******************************************************************************************************************

applyRefac_clausesGeneric([]) -> [];
applyRefac_clausesGeneric([{clause,LINE,Patterns,Guards,Body}|Clauses])->
	NBody = applyRefac_expressionsGeneric(Body),
	NPatterns = applyRefac_expressionsGeneric(Patterns),
	NGuards = applyRefac_expressionsGeneric(Guards),
	[{clause,LINE,NPatterns,NGuards,NBody}|applyRefac_clausesGeneric(Clauses)];
applyRefac_clausesGeneric(Other)->
	Other.


applyRefac_expressionsGeneric([])->[];
applyRefac_expressionsGeneric([Exp|Exps])->
	[applyRefac_expressionGeneric(Exp)|applyRefac_expressionsGeneric(Exps)];
applyRefac_expressionsGeneric(Other)->
	applyRefac_expressionGeneric(Other).



applyRefac_expressionGeneric({match,LINE,E1,E2})->
	{match,LINE,applyRefac_expressionsGeneric(E1),
	 applyRefac_expressionsGeneric(E2)};
applyRefac_expressionGeneric({tuple,LINE,Exps})->
	{tuple,LINE,applyRefac_expressionsGeneric(Exps)};
applyRefac_expressionGeneric({cons,LINE,E1,E2})->
	{cons,LINE,applyRefac_expressionsGeneric(E1),
	 applyRefac_expressionsGeneric(E2)};
	
applyRefac_expressionGeneric({op,LINE,Op,E1,E2})->
	{op,LINE,Op,applyRefac_expressionsGeneric(E1),
	 applyRefac_expressionsGeneric(E2)};
applyRefac_expressionGeneric({op,LINE,Op,E})->
	{op,LINE,Op,applyRefac_expressionsGeneric(E)};

applyRefac_expressionGeneric({record,LINE,Name,RecordFields})->
	{record,LINE,Name,applyRefac_expressionsGeneric(RecordFields)};
applyRefac_expressionGeneric({record,LINE,E0,Name,RecordFields})->
	{record,LINE,applyRefac_expressionsGeneric(E0),Name,applyRefac_expressionsGeneric(RecordFields)};
applyRefac_expressionGeneric({record_index,LINE,Name,Field})->
	{record_index,LINE,Name,applyRefac_expressionsGeneric(Field)};
applyRefac_expressionGeneric({record_field,LINE,E0,Field})->
	{record_field,LINE,applyRefac_expressionsGeneric(E0),applyRefac_expressionsGeneric(Field)};
applyRefac_expressionGeneric({record_field,LINE,E0,Name,Field})->
	{record_field,LINE,applyRefac_expressionsGeneric(E0),Name,applyRefac_expressionsGeneric(Field)};

applyRefac_expressionGeneric({'catch',LINE,E})->
	{'catch',LINE,applyRefac_expressionsGeneric(E)};

applyRefac_expressionGeneric({block,LINE,E})->
	{block,LINE,applyRefac_expressionsGeneric(E)};
applyRefac_expressionGeneric({'if',LINE,Clasues})->
	{'if',LINE,applyRefac_clausesGeneric(Clasues)};
applyRefac_expressionGeneric({'case',LINE,E,Clasues})->
	{'case',LINE,applyRefac_expressionGeneric(E),
	applyRefac_clausesGeneric(Clasues)};
applyRefac_expressionGeneric({lc,LINE,E0,W})->
	{lc,LINE,applyRefac_expressionsGeneric(E0),applyRefac_expressionsGeneric(W)};
applyRefac_expressionGeneric({bc,LINE,E0,W})->
	{bc,LINE,applyRefac_expressionsGeneric(E0),applyRefac_expressionsGeneric(W)};

applyRefac_expressionGeneric({'try',LINE,B,[],[],A})->
	{'try',LINE,applyRefac_expressionsGeneric(B),[],[],applyRefac_expressionsGeneric(A)};
applyRefac_expressionGeneric({'try',LINE,B,[],C,[]})->
	{'try',LINE,applyRefac_expressionsGeneric(B),[],applyRefac_expressionsGeneric(C),[]};
applyRefac_expressionGeneric({'try',LINE,B,C,[],A})->
	{'try',LINE,applyRefac_expressionsGeneric(B),applyRefac_expressionsGeneric(C),[],applyRefac_expressionsGeneric(A)};
applyRefac_expressionGeneric({'try',LINE,B,[],C,A})->
	{'try',LINE,applyRefac_expressionsGeneric(B),[],applyRefac_expressionsGeneric(C),applyRefac_expressionsGeneric(A)};
applyRefac_expressionGeneric({'try',LINE,B,C,T,[]})->
	{'try',LINE,applyRefac_expressionsGeneric(B),applyRefac_expressionsGeneric(C),applyRefac_expressionsGeneric(T),[]};
applyRefac_expressionGeneric({'try',LINE,B,C,T,A})->
	{'try',LINE,applyRefac_expressionsGeneric(B),applyRefac_expressionsGeneric(C),applyRefac_expressionsGeneric(T),applyRefac_expressionGeneric(A)};

applyRefac_expressionGeneric({'fun',LINE,F})->
	{'fun',LINE,applyRefac_expressionsGeneric(F)};
applyRefac_expressionGeneric({'query',LINE,F})->
	{'query',LINE,applyRefac_expressionsGeneric(F)};
applyRefac_expressionGeneric({'receive',LINE,C})->
	{'receive',LINE,applyRefac_clausesGeneric(C)};
applyRefac_expressionGeneric({'receive',LINE,C,E,B})->
	{'receive',LINE,applyRefac_clausesGeneric(C),applyRefac_expressionsGeneric(E),applyRefac_expressionsGeneric(B)};
applyRefac_expressionGeneric({generate,LINE,P,E})->
	{generate,LINE,applyRefac_expressionsGeneric(P),applyRefac_expressionsGeneric(E)};
applyRefac_expressionGeneric({b_generate,LINE,P,E})->
	{b_generate,LINE,applyRefac_expressionsGeneric(P),applyRefac_expressionsGeneric(E)};

applyRefac_expressionGeneric({clauses,Clauses})->
	{clauses,applyRefac_clausesGeneric(Clauses)};

%Casos dels clause
applyRefac_expressionGeneric([A|B]) ->
	[applyRefac_expressionGeneric(A)|applyRefac_expressionsGeneric(B)];

applyRefac_expressionGeneric(Other)->
	Other.