%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%               Fuzzy XPATH                       %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%						  %
%                PARSER		                  %
%                                                 %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% NUMBERS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
real(R) --> numero(N),".",numero(M), {append(N,".",R1), append(R1,M,R)},!.
real(R) --> numero(R),!.
numero([C|D]) --> [C], {name(L,[C]), number(L)}, numero(D),!.
numero([]) --> [].

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% String
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cadena(Cadena) --> cadenaL(CadenaL), {name(Cadena, CadenaL)}.
cadenaL([Ascii|B]) --> [Ascii], {symbol(Ascii)}, cadenaL(B), !.
cadenaL([]) --> [].
symbol(Ascii) :- (name(L,[Ascii]), number(L)); (Ascii >= 97, Ascii =< 122 ; Ascii >= 65, Ascii =< 90;
						Ascii = 95); Ascii = 45; Ascii = 46; Ascii = 64.

frase(Frase) --> blanks, [39], blanks, fraseL(Frase), blanks, [39], blanks, !. % 39 = '
frase(Frase) --> blanks, [34], blanks, fraseL(Frase), blanks, [34], blanks, !. % 34 = "
fraseL(Frase) --> cadena(Frase).
fraseL(Frase) --> cadena(Cadena), blanks, fraseL(Cadena2), {concat(Cadena,' ', Aux), concat(Aux, Cadena2, Frase)}.
fraseL('') --> blanks,!.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% White Space
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
blank --> " ", !.
blank --> [10], !.
blanks --> blank, blanks, !.
blanks --> [], !.

/*-----------------------------------------------------------------------------------------------------------------------------*/

/* Si es que existen OPERADORES que realizana algun cambio a los valores de verdad.*/
consultBox(Constraint) --> "[", blanks, constraintDeDo(Constraint), blanks, "]", !.
consultBox(Constraint) --> "[", blanks, constraintDown(Constraint), blanks, "]", !.
consultBox(Constraint) --> "[", blanks, constraintDeep(Constraint), blanks, "]", !.
consultBox(Debug)      --> "[", blanks, debugQuery(Debug), blanks, "]", !.
consultBox(Swap)       --> "[", blanks, debugSwap(Swap),   blanks, "]", !.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% DEBUG
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
debugQuery(debug(Debug1))--> "DEBUG", blanks, "=", blanks, real(Debug), !, {name(Debug1,Debug)}.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Penalty swap
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
debugSwap(swap(Swap1))--> "SWAP", blanks, "=", blanks, real(Swap), !, {name(Swap1,Swap)}.
debugSwap(swap(Swap1))--> "DELETE", blanks, "=", blanks, real(Swap), !, {name(Swap1,Swap)}.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Constraint DEEP y DOWN
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
constraintDeDo(conDeDo(tv(Deep1,[]),tv(Down1,[])))--> "DEEP", blanks, "=", blanks, real(Deep), blanks, ";",
	                                      blanks, "DOWN", blanks, "=", blanks, real(Down), !,
                        	             {name(Deep1,Deep),name(Down1,Down)}.

constraintDeDo(conDeDo(tv(Deep1,[]),tv(Down1,[])))--> "DOWN", blanks, "=", blanks, real(Down), blanks, ";",
	                                      blanks, "DEEP", blanks, "=", blanks, real(Deep), !,
                        	             {name(Deep1,Deep),name(Down1,Down)}.

constraintDown(conDown(tv(Down1,[])))--> "DOWN", blanks, "=", blanks, real(Down), !, {name(Down1,Down)}.
constraintDeep(conDeep(tv(Deep1,[])))--> "DEEP", blanks, "=", blanks, real(Deep), !, {name(Deep1,Deep)}.
constraintDeep(conDeep(tv(Deep1,[])))--> "JUMP", blanks, "=", blanks, real(Deep), !, {name(Deep1,Deep)}.
/*-----------------------------------------------------------------------------------------------------------------------------*/

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Term...
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
termino(Termino) --> "@", cadena(Term1), {Termino=..[attr,Term1]}, !.
termino(text) --> "text()", !.
termino(Termino) --> frase(Termino), !.
termino(Termino) --> cadena(Termino), !.
terminoTv(tValue(Termino)) --> termino(Termino),!.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% TAGs
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
tag([relativePath|TagR]) --> blanks, "//", tag(TagR), !. % Se quito antes de tag(TagR) "/"
tag(TagR) --> "/", tag(TagR), !.
tag([Tag|TagR]) --> cadena(Tag), {Tag \= ''}, tag(TagR), !. % Se quito antes de tag(TagR) "/"
tag([Tag]) --> termino(Tag), {Tag \= ''}, !.
%tag([]) --> [], !.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Relational Operator
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
opRel('\\=') --> "<>", !.

opRel('=<') --> "<=", !.
opRel('=<') --> "=<", !.
opRel('>=') --> ">=", !.
opRel('>=') --> "=>", !.

opRel('>') --> ">", !.
opRel('<') --> "<", !.
opRel('=') --> "=", !.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Logical Operator
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Luka Logic
opLog('and_luka')  --> "and-".
opLog('or_luka')   --> "or-".

% Godel Logic
opLog('and_godel')  --> "and+".
opLog('or_godel')   --> "or+".

% Logic Product
opLog('and')  --> "and".
opLog('or')   --> "or".


% Average or Prioritization
opLog(Op) --> "avg{", numero(N1), ",", numero(N2), "}", {name(N3,N1), name(N4, N2), Op=..[avg,N3,N4]}, !.
opLog('avg')  --> "avg".



/*-----------------------------------------------------------------------------------------------------------------------------*/

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Query
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Examples of predicate condition....
% condicion(ABC,"ab=1 or cd > 2 avg ef=3",[]).
% condicion(ABC,"ab=1 or (cd > 2 avg ef=3)",[]).
% condicion(ABC,"ab=1 or cd > 2 avg ef=3 and gh=4",[]).
% condicion(Cond, "( @year=1994 avg @year>1994 ) avg @year<2000",[]).

condicionB(Condicion)   --> blanks, "(", blanks, condicion(Condicion), ")", blanks, !.

condicionB(tree(op(Op,T1,T2), nil, nil)) --> blanks, consulta(T1), blanks, opRel(Op), blanks, termino(T2),!.
condicionB(tree(exist(T1), nil, nil)) --> blanks, consulta(T1), !.

condicion(B) --> condicionB(A), blanks, condicion2(A,B), !.

%new - se compara con un valor de verdad
condicion2(A,tree(op(Op,[A],[B]), nil, nil)) --> opRel(Op), blanks, terminoTv(B), blanks,!.
%                                  {Condicion=..[OpR, [A], B]}.

%new - se comparan dos tv... revisar.
condicion2(A,tree(op(Op,[A],[B]), nil, nil)) --> opRel(Op), !, blanks, condicion(B), blanks, !.
%,                                 {Condicion=..[OpR, [A], B]}.
%
condicion2(A,tree(OpLog, A, B)) --> opLog(OpLog), blanks, condicion(B), blanks, !.





%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% old
condicion2(A,A) --> [].


/*-----------------------------------------------------------------------------------------------------------------------------*/

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% In this section is assembled the query
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Indicates the end of the consultation.
consulta([])--> "ż", !.

% for relative path
consulta([relativePath|Consult]) -->  "//", blanks, consulta(Consult), !.

% for deleted /
consulta(Consult) --> "/", blanks, consulta(Consult), !.

% for Box... for example: Constraint, Debug, Swap, ...
consulta([Box|Consult]) -->  consultBox(Box), blanks, consulta(Consult), !.


% If there is one condition
consulta([Cond|Consult]) --> "[", !, blanks, condicion(Cond), blanks, "]", blanks, consulta(Consult), !.

% for Tag --> Tag es una lista de valores.
consulta(Consult) --> tag(Tag), consulta(Aux), { append(Tag,Aux,Consult)},!.

% Si tenemos A > 5, entonces el tag A, termina en blanks....
consulta([]) --> blanks, !.


/*-----------------------------------------------------------------------------------------------------------------------------*/

isBox([Box|BoxR])--> consultBox(Box), blanks, isBox(BoxR),!.
isBox([]) --> blanks, !.

isRoot(relativePath) --> "//",!.
isRoot(absolutePath) --> "/",!.

consultRoot(Consult0) --> blanks, isBox(Box), blanks, isRoot(Root), !, blanks, consulta(Consult), blanks, !,
	                                    {append(Box,[Root|Consult],Consult0)}.

/*-----------------------------------------------------------------------------------------------------------------------------*/

%%%%%%%%%%%%%%%%%%%%%%%
% FuzzyXPath Consult  %
%%%%%%%%%%%%%%%%%%%%%%%
% load_fuzzyXPath('/bib/book[@price<30 avg{3,1} @year<2006]', ListFXPath).
% load_fuzzyXPath('', ListFXPath).
% /bib/book[@price<30 avg{3,1} @year<2006]
load_fuzzyXPath(FuzzyXPath, ListFXPath2):-
				name(FuzzyXPath, X),
				append(X, "ż", X2),
				consultRoot(ListFXPath, X2, []),
				sortConsult(ListFXPath,ListFXPath2).

sortConsult([],[]).
sortConsult([relativePath,relativePath|Rest],[relativePath|Rest]):-!.
sortConsult([conDeep(tv(X, [])),conDeep(tv(X, []))|Rest],[conDeep(tv(X, []))|Rest]):-!.
sortConsult([conDown(tv(X, [])),conDown(tv(X, []))|Rest],[conDown(tv(X, []))|Rest]):-!.

sortConsult([relativePath,swap(X)|Rest],[swap(X),relativePath|Rest]):-!.
sortConsult([relativePath,conDeep(X)|Rest],[conDeep(X),relativePath|Rest]):-!.
sortConsult([relativePath,conDown(X)|Rest],[conDown(X),relativePath|Rest]):-!.
sortConsult([relativePath,conDeDo(X,Y)|Rest],[conDeDo(X,Y),relativePath|Rest]):-!.
sortConsult([Other|Rest],[Other|Rest3]):-!, sortConsult(Rest,Rest2),
					 ((Rest==Rest2, !, Rest3=Rest);(sortConsult([Other|Rest2],[Other|Rest3]))).









