package nars.operator;

import com.google.common.collect.Lists;
import java.util.ArrayList;
import nars.core.Memory;
import nars.core.Parameters;
import nars.entity.Task;
import nars.io.Symbols;
import nars.language.CompoundTerm;
import nars.language.Inheritance;
import nars.language.Product;
import nars.language.Term;
import nars.language.Variable;


/** 
 * Superclass of functions that execute synchronously (blocking, in thread) and take
 * N input parameters and one variable argument (as the final argument), generating a new task
 * with the result of the function substituted in the variable's place.
 */
public abstract class SynchronousFunctionOperator extends Operator {

    
    protected SynchronousFunctionOperator(String name) {
        super(name);
    }

    /** y = function(x) 
     * @return y, or null if unsuccessful
     */
    abstract protected Term function(Memory memory, Term[] x);
    
    /** the term that the output will inherit from; analogous to the 'Range' of a function in mathematical terminology */
    @Deprecated abstract protected Term getRange();
        
    //abstract protected int getMinArity();
    //abstract protected int getMaxArity();
    
    @Override
    protected ArrayList<Task> execute(Operation operation, Term[] args, Memory m) {
        //TODO make memory access optional by constructor argument
        //TODO allow access to NAR instance?
        int numArgs = args.length;
        if (args[args.length-1].equals(Term.SELF))
            numArgs--;
        
        if (numArgs < 2) {
            throw new RuntimeException("Requires at least 2 arguments");
        }
        
        //last argument a variable?
        Term lastTerm = args[numArgs-1];
        boolean variable = lastTerm instanceof Variable;
        
        int numParam = numArgs-1;
        Term[] x = new Term[numParam];
        System.arraycopy(args, 0, x, 0, numParam);
        
        Term y;
        //try {
            y = function(m, x);
            if (y == null) {
                return null;
            }
            //m.emit(SynchronousFunctionOperator.class, Arrays.toString(x) + " | " + y);
        /*}
        catch (Exception e) {
            throw e;
        }*/
            
        Term actual = operation.setComponent(0, 
                ((CompoundTerm)operation.getSubject()).setComponent(
                        numArgs-1, y, m), m);            
        
        if (variable) {
            return Lists.newArrayList( 
                    m.newTask(actual, Symbols.JUDGMENT_MARK, 
                            1f, 0.99f, 
                            Parameters.DEFAULT_JUDGMENT_PRIORITY, 
                            Parameters.DEFAULT_JUDGMENT_DURABILITY, operation.getTask()
            ));    
        }
        else {
            /*float equal = equals(lastTerm, y);
            
            
            
            float confidence = 0.99f;
            ArrayList<Task> rt = Lists.newArrayList( 
                    m.newTask(actual, Symbols.JUDGMENT_MARK, 
                            1.0f, confidence, 
                            Parameters.DEFAULT_JUDGMENT_PRIORITY, 
                            Parameters.DEFAULT_JUDGMENT_DURABILITY, 
                            operation.getTask()));    
            
            if (equal < 1.0f) {
                rt.add(m.newTask(operation, Symbols.JUDGMENT_MARK, 
                            equal, confidence, 
                            Parameters.DEFAULT_JUDGMENT_PRIORITY, 
                            Parameters.DEFAULT_JUDGMENT_DURABILITY, 
                            operation.getTask()));
            }
            return rt;
            */
            
            return null;
            
        }
    }

    /** (can be overridden in subclasses) the extent to which it is truth 
     * that the 2 given terms are equal.  in other words, a distance metric
     */
    public float equals(Term a, Term b) {
        //default: Term equality
        return a.equals(b) ? 1.0f : 0.0f;
    }
}

@@ -164,16 +164,53 @@
 y.Task;%0A
+import nars.inference.TemporalRules;%0A
 import n
@@ -256,24 +256,58 @@
 mpoundTerm;%0A
+import nars.language.Implication;%0A
 import nars.
@@ -358,16 +358,49 @@
 roduct;%0A
+import nars.language.Similarity;%0A
 import n
@@ -1873,32 +1873,100 @@
 iable;%0A        %0A
+        if(!variable) %7B%0A            return null;%0A        %7D%0A        %0A
         int numP
@@ -2396,32 +2396,535 @@
     
+%0A
   
-%0A        Term actual =
+      //since Peis approach needs it to directly generate op(...,$output) =%7C%3E %3C$output %3C-%3E result%3E,%0A        //which wont happen on temporal induction with dependent variable for good reason,%0A        //because in general the two dependent variables of event1 and event2%0A        //can not be assumed to be related, but here we have to assume%0A        //it if we don't want to use the %22resultof%22-relation.%0A        Variable var=new Variable(%22$1%22);%0A        Term actual_part = Similarity.make(var, y);%0A        operation=(Operation)
  ope
@@ -3051,17 +3051,19 @@
 Args-1, 
-y
+var
 , m), m)
@@ -3064,19 +3064,17 @@
 m), m); 
-   
+%0A
         
@@ -3075,27 +3075,110 @@
       %0A     
+   
-   
+Term actual=Implication.make(operation, actual_part, TemporalRules.ORDER_FORWARD);%0A
 %0A        if 

correct operator feedback like Peis approach needs.