package net.woodyfolsom.msproj.ann2;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

public abstract class AbstractNeuralNetFilter implements NeuralNetFilter {
	private final FeedforwardNetwork neuralNetwork;
	private final TrainingMethod trainingMethod;
	
	private double maxError;
	private int actualTrainingEpochs = 0;
	private int maxTrainingEpochs;
	
	AbstractNeuralNetFilter(FeedforwardNetwork neuralNetwork, TrainingMethod trainingMethod, int maxTrainingEpochs, double maxError) {
		this.neuralNetwork = neuralNetwork;
		this.trainingMethod = trainingMethod;
		this.maxError = maxError;
		this.maxTrainingEpochs = maxTrainingEpochs;
	}
	
	@Override
	public NNData compute(NNDataPair input) {
		return this.neuralNetwork.compute(input);
	}
	
	public int getActualTrainingEpochs() {
		return actualTrainingEpochs;
	}
	
	@Override
	public int getInputSize() {
		return 2;
	}

	public int getMaxTrainingEpochs() {
		return maxTrainingEpochs;
	}
	
	protected FeedforwardNetwork getNeuralNetwork() {
		return neuralNetwork;
	}
	
	@Override
	public void learn(List<NNDataPair> trainingSet) {
		actualTrainingEpochs = 0;
		double error;
		neuralNetwork.initWeights();
		
		error = trainingMethod.computeError(neuralNetwork,trainingSet);
		
		if (error <= maxError) {
			System.out.println("Initial error: " + error);
			return;	
		}
		
		do {
			trainingMethod.iterate(neuralNetwork,trainingSet);
			error = trainingMethod.computeError(neuralNetwork,trainingSet);
			System.out.println("Epoch #" + actualTrainingEpochs + " Error:"
					+ error);
			actualTrainingEpochs++;
			System.out.println("MSSE after epoch " + actualTrainingEpochs + ": " + error);
		} while (error > maxError && actualTrainingEpochs < maxTrainingEpochs);
	}
	
	@Override
	public boolean load(InputStream input) {
		return neuralNetwork.load(input);
	}

	@Override
	public boolean save(OutputStream output) {
		return neuralNetwork.save(output);
	}
	
	public void setMaxError(double maxError) {
		this.maxError = maxError;
	}
	
	public void setMaxTrainingEpochs(int max) {
		this.maxTrainingEpochs = max;
	}
}