
/***********************************************************************************************
 * Copyright (c) 2012  DCA-FEEC-UNICAMP
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v3
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/lgpl.html
 * <p>
 * Contributors:
 * K. Raizer, A. L. O. Paraense, E. M. Froes, R. R. Gudwin - initial API and implementation
 ***********************************************************************************************/
package br.unicamp.cst.attention;

import br.unicamp.cst.core.entities.Codelet;
import br.unicamp.cst.core.entities.MemoryObject;
import br.unicamp.cst.core.entities.Mind;

import br.unicamp.cst.support.TimeStamp;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;



/**
 * Test for Codelet implementation of Feature Maps generated by the Attentional System of 
 * Conscious Attention-Based Integrated Model (CONAIM). The maps, from a bottom-
 * up perspective, provide information that present saliences in the state to 
 * which attention should be oriented to and that, if attended, will enhance the
 * corresponding region in the attentional map for a certain time and inhibit
 * it in the sequence (inhibition of return). From a top-down perspective, 
 * depending on the system goal and on the attentional dynamic current state 
 * (orienting, selecting or sustaining), voluntary attention can be directed to
 * a region of space or object in two ways: by deliberative enhancing a region
 * in the attentional map or by adjusting the weights that define the 
 * contribution of each feature dimension.
 * 
 * @author L. L. Rossi (leolellisr)
 * @see Codelet
 * @see MemoryObject
 * @see SensorBufferCodelet
 */
public class BottomUpFeapMapCodeletTest {

    /**
     * Test class initialization for the Bottom-Up Feature Map. Creates a test 
     * mind, with 1 input and 1 output. The codelet to be tested is initialized as 
     * a BottomUpFM and inserted into the created mind. 
     * Input and output are added to the codelet and it is set to 
     * publish-subscribe. The mind is then initiated.
     * 
     */
    public MemoryObject source;
    public MemoryObject destination;
    BottomUpFM testFeapMapCodelet, testFeapMapCodelet2;
    
    public BottomUpFeapMapCodeletTest() {
        Mind testMind = new Mind();
        source = testMind.createMemoryObject("SOURCE");
        //source.setI(0);
        destination = testMind.createMemoryObject("DESTINATION");
        destination.setI(new CopyOnWriteArrayList<Float>());
        
        testFeapMapCodelet = new BottomUpFM(0, "DESTINATION", 100, 16, 255, 
                4, 4, 3, 0, false, true);
        testMind.insertCodelet(testFeapMapCodelet);
        testFeapMapCodelet.addInput(source);
        testFeapMapCodelet.addOutput(destination);
        testFeapMapCodelet.setIsMemoryObserver(true);
	source.addMemoryObserver(testFeapMapCodelet);
        
        testFeapMapCodelet2 = new BottomUpFM(0, "DESTINATION", 100, 16, 255, 
                4, 4, 3, 0, true, false);
        testMind.insertCodelet(testFeapMapCodelet2);
        testFeapMapCodelet2.addInput(source);
        testFeapMapCodelet2.addOutput(destination);
        testFeapMapCodelet2.setIsMemoryObserver(true);
	source.addMemoryObserver(testFeapMapCodelet2);
        
        testMind.start();
        
        
        //List fulllist = (List)destination.getI();
        
        
    }
    
    /*
    * Test 1: After sensor separation, input have all elements equal to 100. 
    * With no saliences, the output array will only have elements equals 0.
    *
    * Test 2: After sensor separation, input have the following elements:
    * [[70.0, 210.0, 140.0, 140.0],
    * [70.0, 210.0, 140.0, 140.0],
    * [70.0, 210.0, 140.0, 140.0], 
    * [70.0, 210.0, 140.0, 140.0]]
    * Performing the average pool operation and normalization, the following 
    * array is obtained:
    * [[0.0, 0.27450982, 0.0, 0.0],
    * [0.0, 0.27450982, 0.0, 0.0],
    * [0.0, 0.27450982, 0.0, 0.0],
    * [0.0, 0.27450982, 0.0, 0.0]]
    *
    * Test 3: After sensor separation, input have the following elements:
    * [[0, 255, 0, 255],
    * [0, 255, 0, 255],
    * [0, 255, 0, 255], 
    * [0, 255, 0, 255]]
    * Performing the average pool operation and normalization, the following 
    * array is obtained:
    * [[0.0, 0.5, 0.0, 0.5],
    * [0.0, 0.5, 0.0, 0.5],
    * [0.0, 0.5, 0.0, 0.5],
    * [0.0, 0.5, 0.0, 0.5]]
    */
    @Test
    public void testFeapMapCodelet() {
        BottomUpFeapMapCodeletTest test = new BottomUpFeapMapCodeletTest();
        //for (int i=0;i<64;i++) {
            System.out.println("Testing ... ");
            long oldtimestamp = test.destination.getTimestamp();
            System.out.println("steps: "+test.testFeapMapCodelet.steps+" Timestamp before: "+TimeStamp.getStringTimeStamp(oldtimestamp, "dd/MM/yyyy HH:mm:ss.SSS"));
            
            // Test 1
            CopyOnWriteArrayList<Float> arrList_test = new CopyOnWriteArrayList<Float>();
            for (int i = 0; i < 16*3; i++) {
                arrList_test.add((float) (i%3)*50+100);
            }
            CopyOnWriteArrayList<Float> arrList_goal = new CopyOnWriteArrayList<Float>();
            for (int i = 0; i < 16; i++) {
                arrList_goal.add((float) 0.0);
            }
                    
            
            long newtimestamp = test.destination.getTimestamp();
            test.testFeapMapCodelet.resetTriggers();
            test.source.setI(arrList_test);
            while(test.testFeapMapCodelet.steps < 1) {
                newtimestamp = test.destination.getTimestamp();
                System.out.println("steps: "+test.testFeapMapCodelet.steps+" Timestamp during: "+TimeStamp.getStringTimeStamp(newtimestamp,"dd/MM/yyyy HH:mm:ss.SSS"));
            }
            System.out.println("steps: "+test.testFeapMapCodelet.steps+" Timestamp after: "+TimeStamp.getStringTimeStamp(newtimestamp,"dd/MM/yyyy HH:mm:ss.SSS"));
            System.out.println("   Input 1: "+test.source.getI());
            
            
            System.out.print("   Output 1: "+ test.destination.getI());
            System.out.print("  \n Goal 1: "+arrList_goal);
            List fulllist = (List) test.destination.getI();
            if (fulllist != null && fulllist.size() > 0) {
                //printList(fulllist);
                System.out.println("          sizef: "+((List)(test.destination.getI())).size()+"\n");
                
                
                assertEquals(fulllist.size(),16);
                assertEquals(fulllist,arrList_goal);
                
            }
            
            // Test 2
            oldtimestamp = test.destination.getTimestamp();
            System.out.println("steps: "+test.testFeapMapCodelet.steps+" Timestamp before: "+TimeStamp.getStringTimeStamp(oldtimestamp, "dd/MM/yyyy HH:mm:ss.SSS"));
            
            arrList_test = new CopyOnWriteArrayList<Float>();
            for (int i = 0; i < (int)16/2*3; i++) {
                arrList_test.add((float)70*((i % 2) + 1));
                arrList_test.add((float)70*((i % 2) + 2));
            }
            arrList_goal = new CopyOnWriteArrayList<Float>();
            for (int i = 0; i < 4; i++) {
                arrList_goal.add((float) 0.0);
                 arrList_goal.add((float) 0.27450982);
                arrList_goal.add((float) 0.0);
                arrList_goal.add((float) 0.0);
            }
            
            newtimestamp = test.destination.getTimestamp();
            test.testFeapMapCodelet.resetTriggers();
            test.source.setI(arrList_test);
            while(test.testFeapMapCodelet.steps < 1) {
                newtimestamp = test.destination.getTimestamp();
                System.out.println("steps: "+test.testFeapMapCodelet.steps+" Timestamp after: "+TimeStamp.getStringTimeStamp(newtimestamp,"dd/MM/yyyy HH:mm:ss.SSS"));
            }
            
            System.out.println("   Input 2: "+test.source.getI());
            
            
            System.out.print("   Output 2: "+ test.destination.getI());
            System.out.print(" \n  Goal 2: "+arrList_goal);
            fulllist = (List) test.destination.getI();
            if (fulllist != null && fulllist.size() > 0) {
                //printList(fulllist);
                System.out.println("          sizef: "+((List)(test.destination.getI())).size()+"\n");
                
                
                assertEquals(fulllist.size(),16);
                assertEquals(fulllist,arrList_goal);
                
            }
            
            // Test 3
            oldtimestamp = test.destination.getTimestamp();
            System.out.println("steps: "+test.testFeapMapCodelet.steps+" Timestamp before: "+TimeStamp.getStringTimeStamp(oldtimestamp, "dd/MM/yyyy HH:mm:ss.SSS"));
            
            arrList_test = new CopyOnWriteArrayList<Float>();
            for (int i = 0; i < 8*3; i++) {
                arrList_test.add((float) 0);
                arrList_test.add((float) 255);
            }
            arrList_goal = new CopyOnWriteArrayList<Float>();
            for (int i = 0; i < 8; i++) {
                arrList_goal.add((float) 0);
                arrList_goal.add((float) 0.5);
            }
            
            
            newtimestamp = test.destination.getTimestamp();        
            test.testFeapMapCodelet.resetTriggers();
            
            test.source.setI(arrList_test);
            while(test.testFeapMapCodelet.steps < 1) {
                newtimestamp = test.destination.getTimestamp();
                System.out.println("steps: "+test.testFeapMapCodelet.steps+" Timestamp after: "+TimeStamp.getStringTimeStamp(newtimestamp,"dd/MM/yyyy HH:mm:ss.SSS"));
            }
            System.out.println("   Input 3: "+test.source.getI());
            
            
            System.out.print("   Output 3: "+ test.destination.getI());
            System.out.print("  \n Goal 3: "+arrList_goal);
            fulllist = (List) test.destination.getI();
            if (fulllist != null && fulllist.size() > 0) {
                //printList(fulllist);
                System.out.println("          sizef: "+fulllist.size()+"\n");
                
                
                assertEquals(fulllist.size(),16);
                assertEquals(fulllist,arrList_goal);
                
            }
        //}
    }
}
