gt: 				for (Instance si : members) {
context: /*
     
      This file is part of the Xapagy Cognitive Architecture 
      Copyright (C) 2008-2017 Ladislau Boloni
  
      This program is free software: you can redistribute it and/or modify
      it under the terms of the GNU Affero 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 Affero General Public License for more details.
  
      You should have received a copy of the GNU Affero General Public License
      along with this program.  If not, see <http://www.gnu.org/licenses/>.
     
  */
  package org.xapagy.storyline;
  
  import java.util.AbstractMap.SimpleEntry;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.Map.Entry;
  import java.util.Set;
  
  import org.xapagy.agents.Agent;
  import org.xapagy.concepts.ConceptOverlay;
  import org.xapagy.concepts.Hardwired;
  import org.xapagy.concepts.VerbOverlay;
  import org.xapagy.instances.Instance;
  import org.xapagy.instances.RelationHelper;
  import org.xapagy.instances.SceneHelper;
  import org.xapagy.instances.VerbInstance;
  import org.xapagy.instances.ViClassifier;
  import org.xapagy.instances.ViClassifier.ViClass;
  import org.xapagy.instances.ViStructureHelper;
  import org.xapagy.instances.ViStructureHelper.ViPart;
  import org.xapagy.instances.ViStructureHelper.ViType;
  import org.xapagy.set.EnergyColors;
  import org.xapagy.set.ViSet;
  import org.xapagy.shadows.Shadows;
  import org.xapagy.ui.TextUi;
  import org.xapagy.ui.formatters.Formatter;
  import org.xapagy.ui.smartprint.SpInstance;
  import org.xapagy.ui.smartprint.XapiPrint;
  import org.xapagy.util.SimpleEntryComparator;
  
  public class StoryLineReasoning {
  
  	/**
  	 * Second experiment for a renarration stuff.
  	 * 
  	 * All the instances are created on-demand, but in the same scene.
  	 * 
  	 * @param agent
  	 *            - the agent
  	 * @param narrative
  	 *            - the narrative, which is a collection of VIs selected from
  	 *            the original story line
  	 * @param sline
  	 *            - the original story line, now likely in the AM and likely in
  	 *            the shadows
  	 * @param f2sInstanceMap
  	 * @param ec
  	 * @return
  	 */
  	public static List<VerbInstance> createRenarrate(Agent agent, List<VerbInstance> narrative, StoryLine sline) {
  		List<VerbInstance> retval = new ArrayList<>();
  		// the object which will store the mapping between the created and old
  		// story line
  		slrMapping mapping = new slrMapping(agent);
  		// iterate over the narrative
  		for (VerbInstance svi : narrative) {
  			// don't recall the relations, let the creation do it
  			if (ViClassifier.decideViClass(ViClass.RELATION, svi, agent)) {
  				// we do create the group member relations, cause they are
  				// different
  				if (!Hardwired.contains(agent, svi.getVerbs(), Hardwired.VR_MEMBER_OF_GROUP)) {
  					continue;
  				}
  			}
  			renarrateVi(agent, svi, mapping);
  		}
  		return retval;
  	}
  
  	/**
  	 * Renarrates a specific in-memory VI svi in the current scene in the focus.
  	 * 
  	 * Focus instances corresponding to the shadow instances will be created on
  	 * demand and added to the mapping
  	 * 
  	 * @param agent
  	 * @param svi
  	 *            - in-memory VI we are re-narrating.
  	 * @param mapping
  	 *            - the mapping of the instances and VIs between the shadow
  	 *            storyline of svi and the current scene
  	 * @return
  	 */
  	public static List<VerbInstance> renarrateVi(Agent agent, VerbInstance svi, slrMapping mapping) {
  		List<VerbInstance> retval = new ArrayList<>();
  		// check whether we have all the instances
  		for (ViPart vip : ViStructureHelper.getAllowedInstanceParts(svi.getViType())) {
  			Instance inst = (Instance) svi.getPart(vip);
  			// check whether we have the regular instance, and if not, create it
  			if (!inst.isScene()) {
  				if (!mapping.getS2fInstanceMap().containsKey(inst)) {
  					// create the instance
  					List<VerbInstance> vis = renarrateInstance(agent, inst, mapping);
  					retval.addAll(vis);
  				}
  			}
  			// This is the case when we first encounter the reference to this
  			// scene as a direct
  			// part of the VI
  			if (inst.isScene()) {
  				if (!mapping.getS2fSceneMap().containsKey(inst)) {
  					List<VerbInstance> vis = renarrateScene(agent, inst, mapping);
  					retval.addAll(vis);
  				}
  			}
  		}
  		// at this moment, we are supposed to have the instances
  		VerbInstance fvi = createFocusPair(agent, svi, mapping);
  		if (fvi != null) {
  			retval.add(fvi);
  			agent.getLoop().proceedOneForcedStep(fvi, 1.0);
  		}
  		return retval;
  	}
  
  	/**
  	 * Creates a focus instance corresponding to a shadow instance si, and
  	 * update the mapping. The new instance will have all the concepts of the
  	 * shadow instance.
  	 * 
  	 * The creation of the focus instance will happen using a create-instance VI
  	 * which puts all the attributes
  	 * 
  	 * @param agent
  	 * @param si
  	 *            - the shadow instance we are reproducing in the current scene
  	 * @param mapping
  	 *            - the mapping of the instances and VIs between the shadow
  	 *            storyline of svi and the current scene
  	 * @return
  	 */
  	public static List<VerbInstance> renarrateInstance(Agent agent, Instance si, slrMapping mapping) {
  		List<VerbInstance> retval = new ArrayList<>();
  		VerbOverlay verbs = VerbOverlay.createVO(agent, Hardwired.VM_CREATE_INSTANCE);
  		VerbInstance viTemplate = VerbInstance.createViTemplate(agent, ViType.S_ADJ, verbs);
  		Instance scene = mapping.getS2fSceneMap().get(si.getScene());
  		// if the scene is a different one, call it
  		if (scene == null) {
  			List<VerbInstance> vis = renarrateScene(agent, si.getScene(), mapping);
  			retval.addAll(vis);
  			scene = mapping.getS2fSceneMap().get(si.getScene());
  		}
  		viTemplate.setSubject(scene);
  		ConceptOverlay co = new ConceptOverlay(agent);
  		co.addOverlay(si.getConcepts());
  		viTemplate.setAdjective(co);
  		// now the template is complete, let us execute it
  		agent.getLoop().proceedOneForcedStep(viTemplate, 1.0);
  		retval.add(viTemplate);
  		Instance fi = viTemplate.getCreatedInstance();
  		mapping.putInstanceMap(fi, si);
  		return retval;
  	}
  
  	/**
  	 * Creates a focus scene corresponding to the shadow scene sscene
  	 * 
  	 * FIXME: what about labels???
  	 * 
  	 * @param agent
  	 * @param sscene
  	 * @param mapping
  	 * @return
  	 */
  	public static List<VerbInstance> renarrateScene(Agent agent, Instance sscene, slrMapping mapping) {
  		List<VerbInstance> retval = new ArrayList<>();
  		// create the scene
  		String label = sscene.getConcepts().getLabels().get(0);
  		String newlabel = "#renarrated_" + Formatter.fmt(agent.getTime()) + "_" + label.substring(1);
  		VerbOverlay verbs = VerbOverlay.createVO(agent, Hardwired.VM_CREATE_INSTANCE);
  		VerbInstance viTemplate = VerbInstance.createViTemplate(agent, ViType.S_ADJ, verbs);
  		Instance scene = agent.getFocus().getCurrentScene();
  		viTemplate.setSubject(scene);
  		ConceptOverlay co = new ConceptOverlay(agent);
  		co.addOverlay(sscene.getConcepts()); // this should include "scene"
  		// FIXME: This creates a null pointer exception in
  		// at
  		// org.xapagy.ui.prettygraphviz.GraphVizHelper.formatIdentifier(GraphVizHelper.java:138)
  		// at
  		// org.xapagy.ui.prettygraphviz.GvFormatter.openNode(GvFormatter.java:165)
  		co.addFullLabel(newlabel, agent);
  		// co.addFullLabel("#renarrate", agent);
  		viTemplate.setAdjective(co);
  		// now the template is complete, let us execute it
  		agent.getLoop().proceedOneForcedStep(viTemplate, 1.0);
  		retval.add(viTemplate);
  		Instance fscene = viTemplate.getCreatedInstance();
  		mapping.putSceneMap(fscene, sscene);
  		return retval;
  	}
  
  	/**
  	 * First experiment for a renarration stuff. What it does at this moment, is
  	 * that it creates all the instances in the current scene, then returns the
  	 * action VIs
  	 * 
  	 * @param agent
  	 *            - the agent
  	 * @param narrative
  	 *            - the narrative, which is a collection of VIs selected from
  	 *            the original story line
  	 * @param sline
  	 *            - the original story line, now likely in the AM and likely in
  	 *            the shadows
  	 * @param f2sInstanceMap
  	 * @param ec
  	 * @return
  	 */
  	public static List<VerbInstance> createRenarrateInstancesFirst(Agent agent, List<VerbInstance> narrative,
  			StoryLine sline) {
  		List<VerbInstance> retval = new ArrayList<>();
  		slrMapping mapping = new slrMapping(agent);
  		// collect all the instances in the narrative
  		Set<Instance> instances = new HashSet<>();
  		for (VerbInstance svi : narrative) {
  			for (ViPart vip : ViStructureHelper.getAllowedInstanceParts(svi.getViType())) {
  				Instance inst = (Instance) svi.getPart(vip);
  				if (!inst.isScene()) {
  					instances.add(inst);
  				}
  			}
  		}
  		// now create all those instances and fill in the f2s and s2f instance
  		// maps
  		// assume that all these are going to be in the current scene
  		for (Instance inst : instances) {
  			VerbOverlay verbs = VerbOverlay.createVO(agent, Hardwired.VM_CREATE_INSTANCE);
  			VerbInstance viTemplate = VerbInstance.createViTemplate(agent, ViType.S_ADJ, verbs);
  			viTemplate.setSubject(agent.getFocus().getCurrentScene());
  			ConceptOverlay co = new ConceptOverlay(agent);
  			co.addOverlay(inst.getConcepts());
  			viTemplate.setAdjective(co);
  			// now the template is complete, let us execute it
  			agent.getLoop().proceedOneForcedStep(viTemplate, 1.0);
  			Instance fi = viTemplate.getCreatedInstance();
  			mapping.putInstanceMap(fi, inst);
  		}
  
  		// now create the narrative
  		for (VerbInstance svi : narrative) {
  			VerbInstance fvi = createFocusPair(agent, svi, mapping);
  			if (fvi != null) {
  				retval.add(fvi);
  				agent.getLoop().proceedOneForcedStep(fvi, 1.0);
  			}
  			// maybe if it is null break???
  		}
  		return retval;
  	}
  
  	/**
  	 * Selects VIs from a story line for re-narration. Returns a list of the
  	 * selected original VIs
  	 * 
  	 * @param agent
  	 * @param stl
  	 *            - the story line we want to renarrate
  	 * @param kind
  	 *            - the filtering we want to apply for the renarration: "all",
  	 *            "0", "1", "2" or "3"
  	 * @return
  	 */
  	public static List<VerbInstance> selectForRenarration(Agent agent, StoryLine sline, String kind) {
  		List<VerbInstance> vis = sline.getVis();
  		List<VerbInstance> retval = new ArrayList<>();
  		switch (kind) {
  		case "all": {
  			for (VerbInstance vi : vis) {
  				retval.add(vi);
  			}
  			return retval;
  		}
  		case "0": {
  			for (VerbInstance vi : vis) {
  				if (vi.getSummarizationLevel() == 0)
  					retval.add(vi);
  			}
  			return retval;
  		}
  		case "1": {
  			for (VerbInstance vi : vis) {
  				if (vi.getSummarizationLevel() == 1)
  					retval.add(vi);
  			}
  			return retval;
  		}
  		case "2": {
  			for (VerbInstance vi : vis) {
  				if (vi.getSummarizationLevel() == 2)
  					retval.add(vi);
  			}
  			return retval;
  		}
  		case "3": {
  			for (VerbInstance vi : vis) {
  				if (vi.getSummarizationLevel() >= 3)
  					retval.add(vi);
  			}
  			return retval;
  		}
  
  		}
  		return retval;
  	}
  
  	/**
  	 * Returns the story lines associated with the last VI processed
  	 * 
  	 * @param agent
  	 * @return
  	 */
  	public static StoryLine getCurrentStoryLine(Agent agent) {
  		VerbInstance lastVi = agent.getLastVerbInstance();
  		List<VerbInstance> vis = new ArrayList<>();
  		vis.add(lastVi);
  		List<StoryLine> stls = StoryLineReasoning.createStoryLines(agent, vis);
  		StoryLine stl = stls.get(0); // normally, it cannot be more than one
  		return stl;
  	}
  
  	/**
  	 * Returns the story lines from the shadows which map to the specified
  	 * in-focus story line. The resulting story lines are paired with a metric
  	 * that shows their strength with regards to the current story line.
  	 * 
  	 * The metric, as currently implemented is the sum of the saliences of the
  	 * best mapping from the shadow back to the focus. This means that the long matches have 
  	 * a advantage. On the other hand, shadow storylines that do not cover the whole current
  	 * are not penalized.
  	 * 
  	 * @param agent
  	 * @param fline
  	 *            - the in-focus story line whose shadows we are looking at
  	 * @param ec
  	 *            - the energy color based on which we are making the matching,
  	 *            normally SHV_GENERIC
  	 * @return
  	 */
  	public static List<SimpleEntry<StoryLine, Double>> createShadowStoryLines(Agent agent, StoryLine fline, String ec) {
  		Shadows sh = agent.getShadows();
  		//
  		// Extract all the story lines from the shadows
  		//
  		List<VerbInstance> vis = new ArrayList<>();
  		for (VerbInstance vi : agent.getFocus().getViListAllEnergies()) {
  			vis.addAll(sh.getMembers(vi, ec));
  		}
  		List<StoryLine> stlsShadows = StoryLineReasoning.createStoryLines(agent, vis);
  		//
  		// for all story lines, calculate a metric that is the sum of the
  		// saliences of the best
  		// mapping from the shadow back to the focus
  		//
  		List<SimpleEntry<StoryLine, Double>> entries = new ArrayList<>();
  		for (StoryLine stl : stlsShadows) {
  			double metric = 0;
  			for (VerbInstance vi : stl.getVis()) {
  				ViSet viset = sh.getReverseShadow(vi, ec);
  				List<SimpleEntry<VerbInstance, Double>> list = viset.getDecreasingStrengthList();
  				if (!list.isEmpty()) {
  					metric += list.get(0).getValue();
  				}
  			}
  			SimpleEntry<StoryLine, Double> entry = new SimpleEntry<>(stl, metric);
  			entries.add(entry);
  		}
  		// return the story line with the best metric
  		Collections.sort(entries, new SimpleEntryComparator<StoryLine>());
  		Collections.reverse(entries);
  		return entries;
  	}
  
  	/**
  	 * Returns the strongest shadow story line (based on which we are going to
  	 * do a prediction normally
  	 * 
  	 * @param agent
  	 * @param fline
  	 *            - the in-focus story line whose shadows we are normally
  	 *            looking at
  	 * @param ec
  	 * @return
  	 */
  	public static StoryLine getStrongestShadowStoryLine(Agent agent, StoryLine fline) {
  		List<SimpleEntry<StoryLine, Double>> entries = createShadowStoryLines(agent, fline, EnergyColors.SHV_GENERIC);
  		return entries.get(0).getKey();
  	}
  
  	/**
  	 * Considers two story lines, one in the focus fstl and one in the shadow.
  	 * For each instance in the story first story line, returns a sorted list of
  	 * possible mappings to instances of the second storyline (based on the
  	 * shadows). If it cannot find a mapping, this list will be empty.
  	 * 
  	 * There are several challenges with this approach.
  	 * 
  	 * <ul>
  	 * <li>Expired components in longer interconnected components will not
  	 * retain their mappings.
  	 * <li>The strongest mappings might not be unique...
  	 * </ul>
  	 * 
  	 * @param agent
  	 * @param fline
  	 *            - a storyline (normally, the one that is in the focus)
  	 * @param sline
  	 *            - a storyline (normally, one that is in the shadows)
  	 * @param ec
  	 *            - the energy color based on which the mapping is done -
  	 *            normally SHI_GENERIC
  	 * @return
  	 */
  	public static Map<Instance, List<SimpleEntry<Instance, Double>>> getInstanceMappingPossibilities(Agent agent,
  			StoryLine fline, StoryLine sline, String ec) {
  		Shadows sh = agent.getShadows();
  		Map<Instance, List<SimpleEntry<Instance, Double>>> retval = new HashMap<>();
  		for (Instance scene : fline.getScenes()) {
  			for (Instance fi : scene.getSceneMembers()) {
  				List<SimpleEntry<Instance, Double>> mappings = new ArrayList<>();
  				retval.put(fi, mappings);
  				List<Instance> members = sh.getMembers(fi, ec);
  