/*******************************************************************************
 * 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.Collection;

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

@Component
public class ControllerMapper {
    private final Collection<InputDevice> inputDevices;
    
    @Autowired
    public ControllerMapper(Collection<InputDevice> inputDevices){
	this.inputDevices = inputDevices;
    }//end constructor
    
    public Collection<InputDevice> getInputDevices(){
	return inputDevices;
    }//end getInputDevices()
    /*
    public void registerInputDevice(InputDevice toRegister){
	inputDevices.add(toRegister);
    }//end registerInputDevice
    */
    /**
     * Multiple sources may feed the same input, though their behavior is undefined if they are of different types
     * i.e. button vs trigger vs axis
     * @param controllerSource
     * @param controllerInput
     * @since Nov 12, 2015
     */
    public void mapControllerSourceToInput(ControllerSource controllerSource, ControllerInput controllerInput, double scale, double offset){
	controllerSource.addStateListener(new ControllerInputStateChangeSetter(controllerInput,scale,offset));
    }//end mapControllerSourceToInput
    
    private class ControllerInputStateChangeSetter implements StateListener{
	private final ControllerInput controllerInput;
	private final double scale;
	private final double offset;
	public ControllerInputStateChangeSetter(ControllerInput controllerInput, double scale, double offset) {
	    this.controllerInput = controllerInput;
	    this.scale           = scale;
	    this.offset          = offset;
	}

	@Override
	public void stateChanged(ControllerSource source, double value) {
		controllerInput.setState(value*scale+offset);
	}
    }//end ControllerInputStateChangeSetter
 
}//end ControllerMapper

@@ -626,16 +626,140 @@
 lection;
+%0Aimport java.util.HashMap;%0Aimport java.util.HashSet;%0Aimport java.util.Map;%0Aimport java.util.Map.Entry;%0Aimport java.util.Set;
 %0A%0Aimport
@@ -960,24 +960,301 @@
 putDevices;%0A
+    private final Set%3CMappingListener%3CControllerSource,ControllerMapping%3E%3E mappingListeners = new HashSet%3CMappingListener%3CControllerSource,ControllerMapping%3E%3E();%0A    private final Map%3CControllerSource,ControllerMapping%3E map = new HashMap%3CControllerSource,ControllerMapping%3E();%0A
     %0A    @Au
@@ -1500,145 +1500,8 @@
 s()%0A
-    /*%0A    public void registerInputDevice(InputDevice toRegister)%7B%0A%09inputDevices.add(toRegister);%0A    %7D//end registerInputDevice%0A    */%0A
     
@@ -1899,379 +1899,904 @@
 )%7B%0A%09
-controllerSource.addStateListener(new ControllerInputStateChangeSetter(controllerInput,scale,offset));%0A    %7D//end mapControllerSourceToInput%0A    %0A    private class ControllerInputStateChangeSetter implements StateListener%7B%0A%09private final ControllerInput controllerInput;%0A%09private final double scale;%0A%09private final double offset;%0A%09public ControllerInputStateChangeSetter(
+final ControllerMapping mapping = new ControllerMapping(controllerSource,controllerInput,scale,offset);%0A%09map.put(controllerSource, mapping);%0A%09controllerSource.addStateListener(mapping);%0A%09fireMappedEvent(controllerSource, mapping);%0A    %7D//end mapControllerSourceToInput%0A    %0A    public boolean unmapControllerSource(ControllerSource controllerSource)%7B%0A%09final ControllerMapping controllerMapping = map.get(controllerSource);%0A%09if(controllerMapping==null)%0A%09    return false; //Was never here to begin with%0A%09map.remove(controllerSource);%0A%09controllerSource.removeStateListener(controllerMapping);%0A%09return true;%0A    %7D%0A    %0A    private void fireMappedEvent(ControllerSource cs, ControllerMapping mapping)%7B%0A%09for(MappingListener%3CControllerSource,ControllerMapping%3E l:mappingListeners)%0A%09    l.mapped(cs, mapping);%0A    %7D// end fireMappedEvent(...)%0A    %0A%0A    public boolean addMappingListener(MappingListener%3C
 Cont
@@ -2793,39 +2793,40 @@
 tener%3CController
-Input c
+Source,C
 ontrollerInput, 
@@ -2822,338 +2822,517 @@
 ller
-Input, double scale, double offset) %7B%0A%09    this.controllerInput = controllerInput;%0A%09    this.scale           = scale
+Mapping%3E l, boolean populate) %7B%0A%09boolean result =  mappingListeners.add(l);%0A%09if(populate)%7B%0A%09    for(Entry%3CControllerSource,ControllerMapping%3E entry:map.entrySet())%7B%0A%09%09l.mapped(entry.getKey(), entry.getValue());%0A%09    %7D//end for(entries)%0A%09%7D//end if(populate)%0A%09return result
 ;%0A
-%09
     
-this.offset   
+%7D//end addMappingListener(...)%0A
     
+%0A
    
-= offset;%0A%09%7D%0A%0A%09@Override%0A%09public void stateChanged(ControllerSource source, double value) %7B%0A%09%09controllerInput.setState(value*scale+offset);%0A%09%7D%0A    %7D//end ControllerInputStateChangeSetter
+ public boolean removeMappingListener(MappingListener%3CControllerSource,ControllerMapping%3E l)%7B%0A%09boolean result = mappingListeners.remove(l);%0A%09return result;%0A    %7D//end removeMappingListener(...)
 %0A %0A%7D

Add ControllerMapper.addMappingListener()