/**
 * Copyright 2010 Neuroph Project http://neuroph.sourceforge.net
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.neuroph.util;

import java.util.Enumeration;
import org.neuroph.core.Neuron;
import org.neuroph.core.input.InputFunction;
import org.neuroph.core.input.WeightedSum;
import org.neuroph.core.transfer.Linear;
import org.neuroph.core.transfer.TransferFunction;

/**
 * Represents properties of a neuron.
 * @author Zoran Sevarac <sevarac@gmail.com>
 */
public class NeuronProperties extends Properties {
	private static final long serialVersionUID = 2L;

	public NeuronProperties() {
                initKeys();
                this.setProperty("inputFunction", WeightedSum.class);
		this.setProperty("transferFunction", Linear.class);
		this.setProperty("neuronType", Neuron.class);
	}
        
	public NeuronProperties(Class <? extends Neuron> neuronClass) {
                initKeys();
                this.setProperty("inputFunction", WeightedSum.class);
		this.setProperty("transferFunction", Linear.class);
		this.setProperty("neuronType", neuronClass);
	}        

	public NeuronProperties(Class <? extends Neuron> neuronClass, Class <? extends TransferFunction> transferFunctionClass) {
                initKeys();
                this.setProperty("inputFunction", WeightedSum.class);
		this.setProperty("transferFunction", transferFunctionClass);
		this.setProperty("neuronType", neuronClass);
	}        

	public NeuronProperties(Class <? extends Neuron> neuronClass,
                                Class <? extends InputFunction> inputFunctionClass,
                                Class <? extends TransferFunction> transferFunctionClass) {
                initKeys();
                this.setProperty("inputFunction", inputFunctionClass);
		this.setProperty("transferFunction", transferFunctionClass);
		this.setProperty("neuronType", neuronClass);
	}
        
        
	public NeuronProperties(Class <? extends Neuron> neuronClass, TransferFunctionType transferFunctionType) {
                initKeys();
//		this.setProperty("weightsFunction", WeightedInput.class);
//		this.setProperty("summingFunction", Sum.class);
                this.setProperty("inputFunction", WeightedSum.class);
		this.setProperty("transferFunction", transferFunctionType.getTypeClass());
		this.setProperty("neuronType", neuronClass);
	}




	public NeuronProperties(TransferFunctionType transferFunctionType, boolean useBias) {
                initKeys();
//		this.setProperty("weightsFunction", WeightedInput.class);
//		this.setProperty("summingFunction", Sum.class);
                this.setProperty("inputFunction", WeightedSum.class);
		this.setProperty("transferFunction", transferFunctionType.getTypeClass());
                this.setProperty("useBias", useBias);
		this.setProperty("neuronType", Neuron.class);
	}


        // uraditi override za setProperty tako da za enum type uzima odgovarajuce klase

        private void initKeys() {
            createKeys("weightsFunction", "summingFunction", "inputFunction", "transferFunction", "neuronType", "useBias"); // use bias prebaciti u NeuralNetworkProperties
        }
        
	public Class getInputFunction() {
            Object val = this.get("inputFunction");
            if (!val.equals("")) return (Class)val;
            return null;
	}

	public Class getTransferFunction() {
		return (Class)this.get("transferFunction");
	}

	public Class getNeuronType() {
		return (Class)this.get("neuronType");
	}


	public Properties getTransferFunctionProperties() {
		Properties tfProperties = new Properties();
		Enumeration<?> en = this.keys();
		while (en.hasMoreElements()) {
			String name = en.nextElement().toString();
			if (name.contains("transferFunction")) {
				tfProperties.setProperty(name, this.get(name));
			}
		}
		return tfProperties;
	}

        @Override
	public final void setProperty(String key, Object value) {
//                if (!this.containsKey(key))
//                    throw new RuntimeException("Unknown property key: "+key);

                if (value instanceof TransferFunctionType) value = ((TransferFunctionType)value).getTypeClass();
          //      if (value instanceof InputFunctionType) value = ((InputFunctionType)value).getTypeClass();

		this.put(key, value);
	}

}