:- dynamic toAssert/1, current/2, current/3.

:- use_module(into_cycl_form,[decompound/3]).

:- setOption(loadMicrotheories,true).
:- setOption(larkcAccessMethod,pengines).
%% setOption(larkcAccessMethod,direct).

%% noFunctionsInMicrotheoryNames(0).
%% FIXME: need to implement proper error handling

load_larkc :-
	larkc_load_contexts_into_larkc('Agent1','Yaswi1',['Org::Cyc::BaseKB']).

larkc_load_contexts_into_larkc(AgentName,FormalogName,Contexts) :-
	cleanLarkcLoading,
	getOption(loadMicrotheories,LoadMicrotheories),
	(   LoadMicrotheories == true ->
	    (	
		getVar(AgentName,FormalogName,'context',Var),
		kbs2Data(Var,CurrentContext),
		forall(member(Context,Contexts),
		       (   
			   setContext(AgentName,FormalogName,Context),
			   nl,write('LOADING CONTEXT INTO LARKC: '),write(Context),nl,
			   ensureMicrotheoryExists(Context,Microtheory,Result1),
			   %% see also formalog_load_database
			   larkc_populate_microtheory(AgentName,FormalogName,Microtheory)
		       )),
		setContext(AgentName,FormalogName,CurrentContext)
	    ) ;
	    true).

cleanLarkcLoading :-
	retractall(current(_,_)),
	retractall(current(_,_,_)).

ensureMicrotheoryExists(Context,Microtheory,Result) :-
	split_string(Context,'::','',TmpItems),
	findall(Item,(member(Item,TmpItems),Item \= ""),Items),
	append([['LarKC-'],Items,['-Mt']],TmpMicrotheory),
	atomic_list_concat(TmpMicrotheory,'-',Microtheory),
	view(Microtheory),
	larkc_wrappers:f(Microtheory,Result1),
	larkc_wrappers:cycAssert([isa,Microtheory,'Microtheory'],'BaseKB',Result2),
	Result = [Result1,Result2].

larkc_populate_microtheory(AgentName,FormalogName,Microtheory) :-
	kquery(AgentName,FormalogName,nil,Assertions),
	sort(Assertions,SortedAssertions),
	larkc_assert_list(SortedAssertions,Microtheory,AllResults).

%% see notable-chatlogs/incoming/#logicmoo-20190518.txt for a
%% discussion of converting PDDL domain and problem to CycL

larkc_assert_list(Assertions,Microtheory,AllAllResults) :-
	view([1]),
	findall(AllResults,
		forall(member(Assertion,Assertions),
		       (   
			   view([2]),
			   findall(Results1,
				   (   current(assertion,Assertion,Microtheory) ->
				       true ;
				       (   
					   view([3]),
					   create_bookkeeping_statements(Assertion,Microtheory,BookkeepingStatements),
					   view([4]),
					   findall(Result1,
						   (   
						       member(BookkeepingStatement,BookkeepingStatements),
						       (   current(statement,BookkeepingStatement) ->
							   Result1 = nil ;
							   (   
							       doLarkcCLEval(BookkeepingStatement,Result1)
							   )
						       )
						   ),
						   Results1),
					   view([6])
				       ))
				  ,AllResults))),
		AllAllResults).

%% %%	(   f "at")
%% %%	(   a '(#$isa #$at #$BinaryPredicate) #$BaseKB)
%% %%	(   a '(#$arity #$at 2) #$BaseKB)
%% %%	(   a '(#$argIsa #$at 1 #$Thing) #$BaseKB)
%% %%	(   a '(#$argIsa #$at 2 #$Thing) #$BaseKB)
%% %%	(   f "sleeping-bag")
%% %%	(   a '(#$isa #$sleeping-bag #$Thing) #$BaseKB)
%% %%	(   f "flagstaff-hill")
%% %%	(   a '(#$isa #$flagstaff-hill #$Thing) #$BaseKB)
%% %%	(   a '(#$at #$sleeping-bag #$flagstaff-hill) #$BaseKB)
%% %%	(   q '(#$at ?X ?Y) #$BaseKB)

create_bookkeeping_statements(Assertion,_,_) :-
	writeln([toAssert,Assertion]),
	retractall(toAssert(_)),
	fail.
create_bookkeeping_statements(TmpAssertion,Microtheory,_) :-
	fixTimesLarKC(TmpAssertion,Tmp2Assertion),
	writeln([tmp2Assertion,Tmp2Assertion]),
	decompound(Microtheory,Tmp2Assertion,Decompounded),
	writeln([decompounded,Decompounded]),
	create_bookkeeping_statements_helper(Decompounded,Microtheory,Assertion,_),
	view([finalAssertion,Assertion]),
	makeAssertion(['CYC-ASSERT',[quote,Assertion],Microtheory]),
	view([21]),
	fail.
create_bookkeeping_statements(_,_,BookkeepingStatements) :-
	findall(BookkeepingStatement,toAssert(BookkeepingStatement),BookkeepingStatements),
	writeln([bookkeepingStatements,BookkeepingStatements]),
	retractall(toAssert(_)).

%% (clear-contents-from-mts (list #$LarKC--Org-Cyc-BaseKB--Mt))

%% [completed,[evalProlog,[recurrenceFn,['TheList',[action,[evalProlog,regenerateNotificationsAndRecurrencesTemporarySchedule]],['TheList',[itemDateTime,['SecondFn',0,['MinuteFn',0,['HourFn',1,['DayFn',29,['MonthFn',['YearFn',2017]]]]]]],['TheList',[recurrenceDateTime,['SecondFn',0,['MinuteFn',0,['HourFn',1,['DayFn',28,['MonthFn',['YearFn',2017]]]]]]],_131496]]]]]]

create_bookkeeping_statements_helper(TmpAssertion,Microtheory,Assertion,_) :-
	view([tmpAssertion,TmpAssertion]),
	TmpAssertion = [TmpP|Args],
	(   TmpP = '[|]' -> P = 'TheList' ;
	    (	TmpP = [] -> P = 'TheEmptyList' ;
		P = TmpP)),
	view([p,P,args,Args]),
	make_quoted_string(P,QP),
	(   constantDefinedInMicrotheory(P,Microtheory) ->
	    true ;
	    createBookkeepingAssertionsForConstant(P,Args,Microtheory,Result)),
	view([16]),
	findall(FinalArg,
		(   
		    view([17]),
		    member(TmpArg,Args),
		    view([18]),
		    (	not(is_list(TmpArg) ; compound(TmpArg)) ->
			(   
			    view([19]),
			    view([tmpArg1,TmpArg]),
			    make_quoted_string(TmpArg,QTmpArg),
			    (	satisfiesCycConstantSyntax(TmpArg),not(atomnumberp(TmpArg)) ->
				(   
				    (	not(constantDefinedInMicrotheory(TmpArg,Microtheory)) ->
					(
					 FinalArg = TmpArg,
					 makeAssertion(['FIND-OR-CREATE-CONSTANT',QTmpArg]),
					 makeAssertion(['CYC-ASSERT',[quote,[isa,FinalArg,'Thing']],Microtheory])
					) ;
					FinalArg = TmpArg)
				) ;
				(   TmpArg = [] -> FinalArg = 'TheEmptyList' ;
				    (	writeln([tmpArgTmp,TmpArg]),
					(   atomnumberp(TmpArg) -> (FinalArg = TmpArg) ; (FinalArg = QTmpArg))))),
			    view([finalArg1,FinalArg])
			) ;
			(   
			    (	TmpArg = [] -> FinalArg = 'TheEmptyList' ;
				(   create_bookkeeping_statements_helper(TmpArg,Microtheory,FinalArg,_) -> true ; true)),
			    view([finalArg2,FinalArg])
			)
		    )
		),
		FinalArgs),
	view([20]),
	view([finalArgs,FinalArgs]),
	append([[P],FinalArgs],Assertion),
	view([myAssertion,Assertion]).


constantDefinedInMicrotheory(C,Microtheory) :-
	writeln(['is constant',C,'defined in Mt',Microtheory]),
 	member(C,['[|]','TheList','TheEmptyList','January','February','March','April','May','June','July','August','September','October','November','December','YearFn','MonthFn','DayFn','HourFn','MinuteFn','SecondFn']).

%% constantDefinedInMicrotheory(C,Microtheory) :-
%% 	writeln(['is constant',C,'defined in Mt',Microtheory]),
%% 	(   member(C,['[|]','TheList','January','February','March','April','May','June','July','August','September','October','November','December','YearFn','MonthFn','DayFn','HourFn','MinuteFn','SecondFn']) ;
%% 	    (	
%% 		(   larkc_wrappers:clEval(['CONSTANT-DEFINED-IN-MICROTHEORY',C,Microtheory],Result) -> true ; true),
%% 		view([result,Result]),
%% 		Result \= []
%% 	    )).

%% (mapcar #'assertion-mt (all-term-assertions #$AndrewDougherty))
%% %% fix this, use the txt__d20 roundtrip here if needed
%% (   doLarkcCLEval(['FIND-CONSTANT',QP],Result1) -> true ; true),
%% Result1 = [].

createBookkeepingAssertionsForConstant(P,Args,Microtheory,Result) :-
	make_quoted_string(P,QP),
	makeAssertion(['FIND-OR-CREATE-CONSTANT',QP]),
	view([11]),
	length(Args,Arity),
	view([12]),
	(   Arity = 1 -> PredicateType = 'UnaryPredicate' ;
	    (	Arity = 2 -> PredicateType = 'BinaryPredicate' ;
		(   Arity = 3 -> PredicateType = 'TernaryPredicate' ;
		    (	writeln('ERROR: larger predicate than weve defined'),fail)))),
	view([13]),
	makeAssertion(['CYC-ASSERT',[quote,[isa,P,PredicateType]],Microtheory]),
	view([14]),
	makeAssertion(['CYC-ASSERT',[quote,[arity,P,Arity]],Microtheory]),
	view([15]),
	forall(between(1,Arity,N),
	       makeAssertion(['CYC-ASSERT',[quote,[argIsa,P,N,'Thing']],Microtheory])).



make_quoted_string(A,QA) :-
	atomic_list_concat(['"',A,'"'],'',QA).

makeAssertion(Assertion) :-
	viewIf([assertion,Assertion]),
	assertz(toAssert(Assertion)).

satisfiesCycConstantSyntax(PotentialConstant) :-
	 string_match_p(PotentialConstant,"^[a-zA-Z0-9_-]+$").

atomnumberp(Atom) :-
	(   atom(Atom) -> (atom_number(Atom,Number),number(Number)) ; number(Atom)).

doLarkcCLEval(Statement,Result) :-
	view([a]),
	getOption(larkcAccessMethod,AccessMethod),
	view([b]),
	(   AccessMethod = pengines ->
	    (	
		view([c]),
		view([statement,Statement]),
		(   larkc_wrappers:clEval(Statement,Result1) ->
		    (	
			view([d]),
			write('Evaled: '),write_term(Statement,[quoted(true)]),nl,
			Result = Result1,
			write('Result: '),write_term(Result,[quoted(true)]),nl,
			assert(current(statement,Statement))
		    ) ;	
		    (	
			view([e]),
			write('Assertion failed: '),write_term(Statement,[quoted(true)]),nl,
			Result = fail,
			write('Result: '),write_term(Result,[quoted(true)]),nl
		    ))) ;
	    fail).

%% doLarkcAssert(Assertion,Microtheory,Result) :-
%% 	view(['A']),
%% 	getOption(larkcAccessMethod,AccessMethod),
%% 	view(['B']),
%% 	(   AccessMethod = pengines ->
%% 	    (	
%% 		view(['C']),
%% 		view([assertion1,Assertion,microthoery,Microtheory,result1,Result1]),
%% 		larkc_wrappers:cycAssert(Assertion,Microtheory,Result1) ->
%% 		(   
%% 		    view(['D']),
%% 		    write('Asserted: '),write_term(Assertion,[quoted(true)]),nl,
%% 		    Result = Result1,
%% 		    view(['E']),
%% 		    assert(current(assertion,Assertion,Microtheory))
%% 		) ;	
%% 		(   
%% 		    view(['F']),
%% 		    write('Assertion failed: '),write_term(Assertion,[quoted(true)]),nl,
%% 		    Result = fail
%% 		)) ;
%% 	    fail).

%% larkcAssert(Assertion,Context,[Result1,Result2]) :-
%% 	(   noFunctionsInMicrotheoryNames(1) -> 
%% 	    ensureMicrotheoryExists(Context,Microtheory,Result1) ;
%% 	    ensureContextMtExists(Context,Microtheory,Result1)),
%% 	ensureConstantsInTermExist(Assertion),
%% 	cycAssert(Assertion,Microtheory,Result2).
	
%% larkcUnassert(Assertion,Context,[Result1,Result2]) :-
%% 	(   noFunctionsInMicrotheoryNames(1) -> 
%% 	    ensureMicrotheoryExists(Context,Microtheory,Result1) ;
%% 	    ensureContextMtExists(Context,Microtheory,Result1)),
%% 	%% ensureConstantsInTermExist(Assertion),
%% 	cycUnassert(Assertion,Microtheory,Result2).

%% larkcQuery(Query,Context,[Result1,Result2]) :-
%% 	(   noFunctionsInMicrotheoryNames(1) -> 
%% 	    ensureMicrotheoryExists(Context,Microtheory,Result1) ;
%% 	    ensureContextMtExists(Context,Microtheory,Result1)),
%% 	%% ensureConstantsInTermExist(Query),
%% 	cycQuery(Query,Microtheory,Result2).

%% ensureContextMtExists(Context,Microtheory,Result) :-
%% 	make_quoted_string(Context,QContext),
%% 	Microtheory = ['larkcMtFn',QContext],
%% 	cycAssert([isa,Microtheory,'Microtheory'],'BaseKB',Result).
	

%% ensureConstantsInTermExist(Assertion) :-
%% 	getAllConstantsInTerm(Assertion,Constants),
%% 	print_term(Constants,[]),
%% 	forall(member(Constant,Constants),findConstant(Constant,Result)).

%% getAllConstantsInTerm(Term,Constants) :-
%% 	(   is_list(Term) ->
%% 	    (   
%% 		findall(TmpResults,(member(Item,Term),getAllConstantsInTerm(Item,TmpResults)),AllTmpResults),
%% 		append(AllTmpResults,Results)
%% 	    ) ;
%% 	    (	Term =.. [P|Args] -> 
%% 	    	(   getAllConstantsInTerm(Args,TmpResults),append([[P],TmpResults],Results)) ;
%% 		   Results = [Term])),
%% 	print_term(Results,[]),
%% 	list_to_set(Results,Constants).

%% defineLarkcMyFn :-
%% larkc_assert_list	f(larkcMtFn,_),
%% 	cycAssert([isa,larkcMtFn,'UnaryFunction'],'BaseKB',_),
%% 	cycAssert([resultIsa,larkcMtFn,'Microtheory'],'BaseKB',_),
%% 	cycAssert([arg1Isa,larkcMtFn,'CharacterString'],'BaseKB',_),
%% 	cycAssert([arity,larkcMtFn,1],'BaseKB',_),
%% 	cycAssert([isa,[larkcMtFn,'"Org::CYC::Base"'],'Microtheory'],'BaseKB',X).

%% testLarkcMyFn :-
%% 	cl_eval(['CYC-ASSERT',[quote,[isa,'AndrewDougherty','Person']],[quote,[larkcMtFn,'"Org::Cyc::BaseKB"']]],X),
%% 	cl_eval(['ALL-ISA',larkcMtFn,'BaseKB'],X),
%% 	cycQuery([arity,larkcMtFn,'?X'],'BaseKB',X),
%% 	cl_eval(['ALL-ISA','AndrewDougherty','POSICommunityMt'],X),
%% 	f('MaximilianDougherty',_),
%% 	cl_eval(['CYC-ASSERT',[quote,[isa,'MaximilianDougherty','Dog']],[quote,[larkcMtFn,'"Org::Cyc::BaseKB"']]],X),
%% 	cl_eval(['ALL-ISA','MaximilianDougherty',[quote,[larkcMtFn,'"Org::Cyc::BaseKB"']]],X),
%% 	cl_eval(['HL-WHY-NOT-WFF',[quote,[isa,'MaximilianDougherty','Dog']],[quote,[larkcMtFn,'"Org::Cyc::BaseKB"']]],X).


%% %% completed(evalProlog(recurrenceFn([action(evalProlog(regenerateFLPInternalSchedules(recurrences))),itemDateTime([2017-6-30,11:0:0]),recurrenceDateTime([2017-6-30,11:0:'0.999999999']),type(recurrence(event))])))

%% %%	(   f "completed")
%% %%	(   a '(#$isa #$completed #$UnaryPredicate) #$BaseKB)
%% %%	(   a '(#$arity #$completed 1) #$BaseKB)
%% %%	(   a '(#$argIsa #$completed 1 #$Thing) #$BaseKB)

%% go over each of the args, if it's a compound term, recursively call the 
%% %%	(   f "sleeping-bag")
%% %%	(   a '(#$isa #$sleeping-bag #$Thing) #$BaseKB)
%% %%	(   f "flagstaff-hill")
%% %%	(   a '(#$isa #$flagstaff-hill #$Thing) #$BaseKB)
%% %%	(   a '(#$completed #$sleeping-bag #$flagstaff-hill) #$BaseKB)
%% %%	(   q '(#$completed ?X ?Y) #$BaseKB)

ensure_number(AorN,N) :-
	(   number(AorN) -> N = AorN ;
	    (	atom(AorN) ->
		(   atom_number(AorN,N) ->
		    true ;
		    N = AorN) ;
		N = AorN)).

ensure_atom(AorN,N) :-
	(   number(AorN) -> atom_number(N,AorN) ;
	    (	atom(AorN) -> N = AorN ; N = AorN )).


fixTimesLarKC(Entry,FixedEntry) :-
	(   Entry = [Y-M-D,H:Mi:S] ->
	    (
	     FixedEntry = [Y-M-D,H:Mi:1]
	    ) ;
	    (	is_list(Entry) ->
		findall(FixedSubEntry,(member(SubEntry,Entry),fixTimesLarKC(SubEntry,FixedSubEntry)),FixedEntry) ;
		(   Entry =.. [P|Args] ->
		    (
		     findall(FixedSubArgs,(member(SubArgs,Args),fixTimesLarKC(SubArgs,FixedSubArgs)),FixedArgs),
		     FixedEntry =.. [P|FixedArgs]
		     )	;
		    (	is_atom(Entry) -> FixedEntry = Entry ;
			true )))).
