/*******************************************************************************
 * This file is part of TERMINAL RECALL
 * Copyright (c) 2015 Chuck Ritola
 * Part of the jTRFP.org project
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *     chuck - initial API and implementation
 ******************************************************************************/

package org.jtrfp.trcl.core;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Features {
    // Key represents target-class
    private static final Map<Object,Map<Class<? extends Feature>,Feature>> targetMap = new HashMap<Object,Map<Class<? extends Feature>,Feature>>();
    private static final HashMap<Class<?>,Collection<FeatureFactory>> featureFactoriesByTargetClass          = new HashMap<Class<?>,Collection<FeatureFactory>>();
    private static final HashMap<Class<?>,FeatureFactory> featureFactoriesByFeature = new HashMap<Class<?>,FeatureFactory>();

    
    public Features(){
	this(Collections.EMPTY_LIST);
    }
    
    @Autowired(required=false)
    public Features(Collection<FeatureFactory> features){
	for(FeatureFactory ff:features)
	    registerFeature(ff);
    }

    private static void registerFeature(FeatureFactory<?> factory){
	System.out.println("Registering feature factory: "+factory.getClass().getName());
	Collection<FeatureFactory> factoryCollection = getFactoryCollection(factory.getTargetClass());
	factoryCollection.add(factory);
	featureFactoriesByFeature.put(factory.getFeatureClass(),factory);
    }
    
    private static Collection<FeatureFactory> getFactoryCollection(Class targetClass){
	Collection<FeatureFactory> result = featureFactoriesByTargetClass.get(targetClass);
	if(result==null)
	    featureFactoriesByTargetClass.put(targetClass, result = new ArrayList<FeatureFactory>());
	return result;
    }
    
    public static void init(Object obj){
	for(FeatureFactory ff:getFactoryCollection(obj.getClass()))
	    get(obj,ff.getFeatureClass());
    }//end init(...)
    
    private static Map<Class<? extends Feature>,Feature> getFeatureMap(Object targ){
	Map<Class<? extends Feature>,Feature> result = targetMap.get(targ);
	if(result==null)
	    targetMap.put(targ, result = new HashMap<Class<? extends Feature>,Feature>());
	assert result!=null;
	return result;
    }//end getFeatureMap()
    
    private static Feature getFeature(Map<Class<? extends Feature>,Feature> map, Class<? extends Feature> featureClass, Object target){
	Feature result = map.get(featureClass);
	if(result==null){
	    final FeatureFactory ff = featureFactoriesByFeature.get(featureClass);
	    assert ff!=null;
	    map.put(featureClass, result = ff.newInstance(target));
	    result.apply(target);
	    }
	return result;
    }//end getFeature()

    public static Feature get(Object target, Class<? extends Feature> featureClass){
     final Map<Class<? extends Feature>,Feature> fMap = getFeatureMap(target);
     return getFeature(fMap,featureClass,target);
    }//end get(...)
}//end Features

@@ -2319,16 +2319,155 @@
 t obj)%7B%0A
+%09//Traverse the type hierarchy%0A%09Class tClass = obj.getClass();%0A%09while(tClass!=Object.class)%7B%0A%09    for(Class iFace:tClass.getInterfaces())%0A%09
 %09for(Fea
@@ -2506,25 +2506,17 @@
 ion(
-obj.getClass()
+iFace
 ))%0A
+%09
 %09   
@@ -2547,16 +2547,77 @@
 ass());%0A
+%09    tClass=tClass.getSuperclass();%0A%09%7D//end while(hierarchy)%0A
     %7D//e
@@ -3404,31 +3404,45 @@
 blic static 
+%3CT extends 
 Feature
+%3E T
  get(Object 
@@ -3455,33 +3455,17 @@
 , Class%3C
-? extends Feature
+T
 %3E featur
@@ -3564,16 +3564,19 @@
  return 
+(T)
 getFeatu

Add superclass/interface target support to Features.