/**
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/*
 * Here comes the text of your license
 * Each line should be prefixed with  * 
 */
package nars.control;

import nars.main.Parameters;
import nars.entity.Concept;
import nars.io.events.Events;
import nars.entity.Task;
import nars.entity.TermLink;
import nars.inference.BudgetFunctions;
import nars.inference.RuleTables;
import nars.storage.Memory;

/** Concept reasoning context - a concept is "fired" or activated by applying the reasoner */
public class GeneralInferenceControl {
    
    public static void selectConceptForInference(Memory mem) {
        Concept currentConcept = mem.concepts.takeNext();
        if (currentConcept==null)
            return;
        
        if(currentConcept.taskLinks.size() == 0) { //remove concepts without tasklinks and without termlinks
            mem.concepts.take(currentConcept.getTerm());
            mem.conceptRemoved(currentConcept);
            return;
        }
        if(currentConcept.termLinks.size() == 0) {  //remove concepts without tasklinks and without termlinks
            mem.concepts.take(currentConcept.getTerm());
            mem.conceptRemoved(currentConcept);
            return;
        }
        
        DerivationContext cont = new DerivationContext(mem);
        cont.setCurrentConcept(currentConcept);
        fireConcept(cont, 1);
    }
    
    public static void fireConcept(DerivationContext nal, int numTaskLinks) {     
        for (int i = 0; i < numTaskLinks; i++) {

            if (nal.currentConcept.taskLinks.size() == 0) 
                return;

            nal.currentTaskLink = nal.currentConcept.taskLinks.takeNext();                    
            if (nal.currentTaskLink == null)
                return;

            if (nal.currentTaskLink.budget.aboveThreshold()) {
                fireTaskLink(nal, Parameters.TERMLINK_MAX_REASONED);                    
            }

            nal.currentConcept.taskLinks.putBack(nal.currentTaskLink, nal.memory.cycles(nal.memory.param.taskLinkForgetDurations), nal.memory);
        }
        float forgetCycles = nal.memory.cycles(nal.memory.param.conceptForgetDurations);
        nal.currentConcept.setQuality(BudgetFunctions.or(nal.currentConcept.getQuality(),nal.memory.emotion.happy()));
        nal.memory.concepts.putBack(nal.currentConcept, forgetCycles, nal.memory);
    }
    
    protected static void fireTaskLink(DerivationContext nal, int termLinks) {
        final Task task = nal.currentTaskLink.getTarget();
        nal.setCurrentTerm(nal.currentConcept.term);
        nal.setCurrentTaskLink(nal.currentTaskLink);
        nal.setCurrentBeliefLink(null);
        nal.setCurrentTask(task); // one of the two places where this variable is set
        
        nal.memory.emotion.adjustBusy(nal.currentTaskLink.getPriority(),nal.currentTaskLink.getDurability(),nal);
        
        if (nal.currentTaskLink.type == TermLink.TRANSFORM) {
            nal.setCurrentBelief(null);
            //TermLink tasklink_as_termlink = new TermLink(nal.currentTaskLink.getTerm(), TermLink.TRANSFORM, nal.getCurrentTaskLink().index);
            //if(nal.currentTaskLink.novel(tasklink_as_termlink, nal.memory.time(), true)) { //then record yourself, but also here novelty counts
                RuleTables.transformTask(nal.currentTaskLink, nal); // to turn this into structural inference as below?
            //}
            
        } else {            
            while (termLinks > 0) {
                final TermLink termLink = nal.currentConcept.selectTermLink(nal.currentTaskLink, nal.memory.time());
                if (termLink == null) {
                    break;
                }
                fireTermlink(termLink, nal);
                nal.currentConcept.returnTermLink(termLink);
                termLinks--;
            }
        }
                
        nal.memory.emit(Events.ConceptFire.class, nal);
        //memory.logic.TASKLINK_FIRE.commit(currentTaskLink.budget.getPriority());
    }

    public static boolean fireTermlink(final TermLink termLink, DerivationContext nal) {
        nal.setCurrentBeliefLink(termLink);
        try {
            RuleTables.reason(nal.currentTaskLink, termLink, nal);
        } catch(Exception ex) {
            if(Parameters.DEBUG) {
                System.out.println("issue in inference");
            }
        }
        nal.memory.emit(Events.TermLinkSelect.class, termLink, nal.currentConcept, nal);
        //memory.logic.REASON.commit(termLink.getPriority());                    
        return true;
    }
}

@@ -1288,25 +1288,27 @@
 ncept==null)
+ %7B
 %0A
-
             
@@ -1307,32 +1307,42 @@
         return;%0A
+        %7D%0A
         %0A       
@@ -1858,20 +1858,19 @@
 Context 
-cont
+nal
  = new D
@@ -1900,20 +1900,19 @@
         
-cont
+nal
 .setCurr
@@ -1931,32 +1931,33 @@
 urrentConcept);%0A
+%0A
         fireConc
@@ -1964,17 +1964,352 @@
 ept(
-cont, 1);
+nal, 1);%0A%0A        %7B // put back%0A            float forgetCycles = nal.memory.cycles(nal.memory.param.conceptForgetDurations);%0A            nal.currentConcept.setQuality(BudgetFunctions.or(nal.currentConcept.getQuality(),nal.memory.emotion.happy()));%0A            nal.memory.concepts.putBack(nal.currentConcept, forgetCycles, nal.memory);%0A        %7D
 %0A   
@@ -2448,17 +2448,16 @@
  i++) %7B%0A
-%0A
         
@@ -2506,16 +2506,17 @@
 ) == 0) 
+%7B
 %0A       
@@ -2523,32 +2523,46 @@
          return;
+%0A            %7D
 %0A%0A            na
@@ -2686,16 +2686,18 @@
 == null)
+ %7B
 %0A       
@@ -2712,16 +2712,30 @@
  return;
+%0A            %7D
 %0A%0A      
@@ -3031,32 +3031,32 @@
 ), nal.memory);%0A
+
         %7D%0A      
@@ -3053,299 +3053,8 @@
   %7D%0A
-        float forgetCycles = nal.memory.cycles(nal.memory.param.conceptForgetDurations);%0A        nal.currentConcept.setQuality(BudgetFunctions.or(nal.currentConcept.getQuality(),nal.memory.emotion.happy()));%0A        nal.memory.concepts.putBack(nal.currentConcept, forgetCycles, nal.memory);%0A
     

refactor General Inference - semantics of concept take/putback