/*
 * Encog Artificial Intelligence Framework v2.x
 * Java Examples
 * http://www.heatonresearch.com/encog/
 * http://code.google.com/p/encog-java/
 * 
 * Copyright 2008-2009, Heaton Research Inc., and individual contributors.
 * See the copyright.txt in the distribution for a full listing of 
 * individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

//package org.encog.examples.neural.xorresilient;

//import org.encog.neural.activation.ActivationSigmoid;
package fr.univ_lehavre.iwocs.m2.vortex.tourbillon;
import org.encog.engine.network.activation.ActivationSigmoid;
import org.encog.ml.data.MLData;
import org.encog.ml.data.MLDataPair;
import org.encog.neural.data.NeuralData;
import org.encog.neural.data.NeuralDataPair;
import org.encog.neural.data.NeuralDataSet;
import org.encog.neural.data.basic.BasicNeuralDataSet;
import org.encog.neural.networks.BasicNetwork;
import org.encog.neural.networks.layers.BasicLayer;
import org.encog.neural.networks.training.Train;
import org.encog.neural.networks.training.propagation.back.Backpropagation;
import org.encog.neural.networks.training.propagation.resilient.ResilientPropagation;
import org.encog.util.logging.EncogLogging;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;

/**
 * XOR: This example is essentially the "Hello World" of neural network
 * programming.  This example shows how to construct an Encog neural
 * network to predict the output from the XOR operator.  This example
 * uses resilient propagation (RPROP) to train the neural network.
 * RPROP is the best general purpose supervised training method provided by
 * Encog.
 * 
 * For the XOR example with RPROP I use 4 hidden neurons.  XOR can get by on just
 * 2, but often the random numbers generated for the weights are not enough for
 * RPROP to actually find a solution.  RPROP can have issues on really small
 * neural networks, but 4 neurons seems to work just fine.
 */

// Lust
// Vanity
// Gluttony
// Wrath
// Greed
// -> Envy
// -> Sloth
public class bullesAnalyseur {
	//tableau de booleen true--> point utilisé; false point non utilisé.
	
	//permet de savoir le nombre de points
	ArrayList<Double[]> vectorCoord;
	boolean [] flag;
	public bullesAnalyseur() {
		//BasicMLData =
		Scanner sc=null;
		Scanner scWin=null;
		Scanner scFail=null;
		
		ArrayList<Double[]> vectors = new ArrayList<Double[]>();
		ArrayList<Integer[]> vectorsWin = new ArrayList<Integer[]>();
		ArrayList<Integer[]> vectorsFail = new ArrayList<Integer[]>();
		
		for(int i=0; i<50; i++){
			DecimalFormat myFormatter = new DecimalFormat("000");
			String output = myFormatter.format(i);
			try{
				sc 		= new Scanner(new File("NORMA_50HZ_DT1-8_000"+output+".txt"));
				scWin 	= new Scanner(new File("NORMA_50HZ_DT1-8_000"+output+"_tra.txt"));
				scFail 	= new Scanner(new File("fail.txt"));
			}catch(Exception e){
				e.printStackTrace();
			}
			//Lecture des trajectoires
			while(sc.hasNext()){
				Double[] values = new Double[3];
				//values[0] = formalize(sc.next());
				//values[1] = formalize(sc.next());
				//values[2] = formalize(sc.next());
	
				values[0] = new Double(sc.next());
				values[1] = new Double(sc.next());
				values[2] = new Double(sc.next());
				sc.next();
				sc.next();
				vectors.add(values.clone());
			}
			
			//Lecture des trajectoires validÈes
		
			
			while(scWin.hasNext()){
				Integer[] values = new Integer[6];
				values[0] = new Integer(scWin.next());
				values[1] = new Integer(scWin.next());
				values[2] = new Integer(scWin.next());
				values[3] = new Integer(scWin.next());
				values[4] = new Integer(scWin.next());
				values[5] = ((int)Math.random())*10+90;
				vectorsWin.add(values.clone());
			}
		}
		
		//Lecture des trajectoires incorrectes
		while(scFail.hasNext()){
			Integer[] values = new Integer[6];
			values[0] = new Integer(scFail.next());
			values[1] = new Integer(scFail.next());
			values[2] = new Integer(scFail.next());
			values[3] = new Integer(scFail.next());
			values[4] = new Integer(scFail.next());
			values[5] = ((int)Math.random())*10;
			vectorsFail.add(values.clone());
		}
		
		ArrayList<Integer[]> trajectoires = new ArrayList<Integer[]>();
		for (Integer[] traj : vectorsWin){
			trajectoires.add(traj);
		}
		for (Integer[] traj : vectorsFail){
			trajectoires.add(traj);
		}
		Integer[][] trajectoiresTab = new Integer[trajectoires.size()][6];
		Iterator<Integer[]> trajIterator = trajectoires.iterator();
		int cpt=0;
		while (trajIterator.hasNext()) {
			trajectoiresTab[cpt++]=trajIterator.next();
		}
		// Ici, on a un tableau de trajectoires avec les 5 points et leur notes ; plus qu'‡ convertir
		// les 5 points en 15 coordonnÈes.
		
		//trajectoiresTab 	: [p1][p2][p3][p4][p5][note]
		//vectors 			: [x1][x2][x3]
		
		ArrayList<Double[]> trajectoiresNotees = new ArrayList<Double[]>();
		for(int i=0; i<trajectoiresTab.length; i++){
			Double[] trajectoireNotee = new Double[15];
			for(int j=0; j<5; j++){
				for(int k=0; k<3; k++){
					trajectoireNotee[j+5*k]=vectors.get(trajectoiresTab[i][j])[k];
				}
			}
			trajectoiresNotees.add(trajectoireNotee);
		}
		
		// Transformation de l'arraylist en tableau
		Iterator<Double[]> trajIterator2 = trajectoiresNotees.iterator();
		XOR_INPUT = new double[trajectoiresNotees.size()][15];
		cpt=0;
		while (trajIterator2.hasNext()) {
			XOR_INPUT[cpt++]=convert(trajIterator2.next());
		}
		
		//todo
		
		
		double[][] notes = new double[trajectoiresNotees.size()][1];
		for(int i=0; i<trajectoiresTab.length; i++){
			notes[i][0]=((double)trajectoiresTab[i][5])/100;
			
		}
		
		
		
		
		BasicNetwork network=new BasicNetwork();
		network.addLayer(new BasicLayer(new ActivationSigmoid(),false,15));
		network.addLayer(new BasicLayer(new ActivationSigmoid(),false,4));
		network.addLayer(new BasicLayer(new ActivationSigmoid(),false,4));
		network.addLayer(new BasicLayer(new ActivationSigmoid(),false,1));
		network.getStructure().finalizeStructure();
		network.reset();

		NeuralDataSet trainingSet = new BasicNeuralDataSet(XOR_INPUT, notes);
		
		// train the neural network
		final Train train = new ResilientPropagation(network, trainingSet);
		//final Train train = new Backpropagation(network, trainingSet, 0.7, 0.8); 
		
		int epoch = 1;

		do {
			train.iteration();
			System.out
					.println("Epoch #" + epoch + " Error:" + train.getError());
			epoch++;
		} while(train.getError() > 0.01);
		//test du data
		for(MLDataPair pair: trainingSet ) { 
			   final MLData output1 = network.compute(pair.getInput()); 
			   System.out.println(pair.getInput().getData(0) + "," + pair.getInput().getData(1) +","+pair.getInput().getData(2) +"," + pair.getInput().getData(3)+"," + pair.getInput().getData(4) 
			     + ", actual=" + output1.getData(0) + ",ideal=" + pair.getIdeal().getData(0)); 
			  }
		sc.close();
		scWin.close();
		scFail.close();
		/*
		 * 450.875,951.5,1452.636,164.185,635.412, actual=0.10850145503492697,ideal=0.0
				450.875,365.364,306.412,179.5,1980.933, actual=0.8892863428315112,ideal=0.9
				1913.0,228.0,450.875,1278.429,1435.615, actual=0.8892863428315112,ideal=0.9
	
		 * */}
	public void initFlag(ArrayList<Double[]> vectorCoord) {
		for (int i=0;i<vectorCoord.size();i++) {
			flag[i]=false;
		}
	}
	public static double XOR_INPUT[][] = { { 0.0, 0.0 }, { 1.0, 0.0 },
			{ 0.0, 1.0 }, { 1.0, 1.0 } };

	public static double XOR_IDEAL[][] = { { 0.0 }, { 1.0 }, { 1.0 }, { 0.0 } };

	public static double formalize(String s){
		String sBase = s.substring(0, 9);
		Double sDouble = new Double(sBase);
		sDouble*=Math.pow(10,(new Double(s.substring(10))));
		//System.out.println(sDouble);
		return sDouble;
	}
	
	public static double[] convert(Double[] converting){
		double[] res = new double[converting.length];
		for(int i=0; i<converting.length; i++){
			res[i] = (double)converting[i];
		}
		return res;
	}
	
	public int getSizeCoord() {
		
		return this.vectorCoord.size();
	}
	public void setSizeCoord(ArrayList<Double[]> vectorCoord) {
		this.vectorCoord=vectorCoord;
	}
	
	//note la trajectoire;
	public double notation(NeuralDataSet trajOk, BasicNetwork network) {
		for(MLDataPair pair: trajOk ) { 
			   final MLData outputNote = network.compute(pair.getInput()); 
			   System.out.println(pair.getInput().getData(0) + "," + pair.getInput().getData(1) 
			     + ", actual=" + outputNote.getData(0)); 
			   
			  }
		double note=0.0;
		
		return note;
	}
	//trie le tableau de trajectoire
	//meilleur note en premier jusqu'à la plus mauvaise
	public void sort() {
		
	}
	//compare deux trajectoire contenant des points identiques 
	//et retient la mieux noté 
	//supprimme la plus mauvaisepublic class LivreComparator
    
	
    //public int compare(traj1 et traj2) si deux points sont identique on retourne false {
    	public boolean compare(int[] traj1, int[] traj2) {
			
    		for (int i=0;i<=5;i++)
        		for (int j=0;j<=5;j++)
        			if (traj1[i]==traj2[j]) {
        				return false;
        			}
    		return true;
    		
    
    }

	
	public void setFlagBulles(int ligne) {
		//boolean [] flag=new int[lengthcoord];
		this.flag[ligne]=true;
	}
	//retourne si un point est déjà utilisé
	//dans une trajectoire
	public boolean getFlagBulles(int ligne) {
		return this.flag[ligne];
		
	}
	
	//fourni des voisins
	public int[] voisin(int ligne){
		int[] neigh=new int[5];
		for(int i=0;i<=5;i++) {
			int delta=(int)(Math.random()*100);
			int voisin = ligne+delta;
			if(!this.getFlagBulles(voisin)) {
				neigh[i]=voisin;
			}else {
				voisin=voisin+delta;
			}
		}
	return neigh;
	}
	public static void main(final String args[]) {
		
		bullesAnalyseur ba = new bullesAnalyseur();
	}
}

