package graphTheory.steinLib;

import graphTheory.graph.Arc;
import graphTheory.graph.DirectedGraph;
import graphTheory.graph.UndirectedGraph;
import graphTheory.instances.steiner.classic.SteinerDirectedInstance;
import graphTheory.instances.steiner.classic.SteinerInstance;
import graphTheory.instances.steiner.classic.SteinerUndirectedInstance;
import graphTheory.instances.steiner.eoliennes.EolienneInstance;
import graphTheory.utils.FileManager;

import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 
 * This class contains static method to translate .stp files into a
 * {@link SteinerInstance}, directed or not, and to translate a
 * {@link SteinerInstance} into a .stp file.
 * 
 * @author Watel Dimitri
 * 
 */
public class STPEolienneTranslator {

	/**
	 * Return the {@link SteinerDirectedInstance} or the
	 * {@link SteinerUndirectedInstance} conresponding to the .stp file in
	 * input. If the file describes a graph containing directed arcs and
	 * undirected edges, then this method returns null.
	 * 
	 * @param nomFic
	 *            path of the file describing the instance we want to build.
	 * @return
	 * @throws STPTranslationException
	 */
	public static EolienneInstance translateFile(String nomFic)
			throws STPTranslationException {
		FileManager f = new FileManager();
		f.openRead(nomFic);
		String s;
		int lineNumber = 0;
		s = f.readLine();
		lineNumber++;
		if (s == null) {
			throw new STPTranslationException(
					STPTranslationExceptionEnum.EMPTY_FILE, nomFic, lineNumber,
					null);
		}

		s = s.toLowerCase();

		// On vérifie que le fichier est au bon format

		if (false && !s.contains("33d32946")) {
			throw new STPTranslationException(
					STPTranslationExceptionEnum.BAD_FORMAT_CODE, nomFic,
					lineNumber, s);
		}

		// On saute l'espace réservé aux commentaires.
		while (!s.contains("section graph")) {
			s = f.readLine();
			lineNumber++;
			if (s == null) {
				throw new STPTranslationException(
						STPTranslationExceptionEnum.NO_SECTION_GRAPH, nomFic,
						lineNumber, s);
			}
			s = s.toLowerCase();
		}

		// On récupère le nombre de noeuds.
		s = f.readLine();
		lineNumber++;

		if (s == null) {
			throw new STPTranslationException(
					STPTranslationExceptionEnum.EMPTY_SECTION_GRAPH, nomFic,
					lineNumber, s);
		}
		s = s.toLowerCase();
		s = s.trim();
		Pattern p = Pattern.compile("nodes +(\\d+)");
		Matcher m = p.matcher(s);
		if (!m.matches())
			throw new STPTranslationException(
					STPTranslationExceptionEnum.NODE_NUMBER_BAD_FORMAT, nomFic,
					lineNumber, s);
		// On récupère le nombre d'arcs
		s = f.readLine();
		lineNumber++;
		if (s == null) {
			throw new STPTranslationException(
					STPTranslationExceptionEnum.EDGE_NUMBER_BAD_FORMAT, nomFic,
					lineNumber, s);
		}
		s = s.toLowerCase();
		s = s.trim();
		p = Pattern.compile("(edges|arcs) +(\\d+)");
		m = p.matcher(s);
		boolean isDirected;
		int noe;
		char letter;
		EolienneInstance g;
		if (m.matches()) {
			isDirected = m.group(1).equals("arcs");
			if (isDirected) {
				DirectedGraph dg = new DirectedGraph();
				g = new EolienneInstance(dg);
				letter = 'a';
			} else {
				throw new STPTranslationException(
						STPTranslationExceptionEnum.EDGE_NUMBER_BAD_FORMAT, nomFic,
						lineNumber, s);
			}
			noe = Integer.valueOf(m.group(2));
		} else {
			throw new STPTranslationException(
					STPTranslationExceptionEnum.EDGE_NUMBER_BAD_FORMAT, nomFic,
					lineNumber, s);
		}

		s = f.readLine();
		lineNumber++;
		if (s == null) {
			throw new STPTranslationException(
					STPTranslationExceptionEnum.NO_SECTION_GRAPH_CONTENT,
					nomFic, lineNumber, s);
		}
		s = s.toLowerCase();
		s = s.trim();
		while (s.equals("")) {
			s = f.readLine();
			lineNumber++;

			if (s == null) {
				throw new STPTranslationException(
						STPTranslationExceptionEnum.NO_SECTION_GRAPH_CONTENT,
						nomFic, lineNumber, s);
			}
			s = s.toLowerCase();
			s = s.trim();
		}
		p = Pattern.compile(letter + " +(\\d+) +(\\d+) +(\\d+)(?:\\.(\\d+))?");
		int cost;
		Integer n1, n2;

		Integer multiplierPower = 0;

		while (!s.equals("end")) {
			m = p.matcher(s);
			if (m.matches()) {
				n1 = Integer.valueOf(m.group(1));
				n2 = Integer.valueOf(m.group(2));

				if(m.groupCount() == 4){
					cost = Integer.valueOf(m.group(3));
				}
				else{
					int nbDigits = m.group(4).length();
					if(multiplierPower < nbDigits){
                        for(Arc a : g.getGraph().getEdges())
                            g.setCost(a, g.getCost(a) * (int)Math.pow(10, nbDigits - multiplierPower));
                        multiplierPower = nbDigits;
                    }

                    int multiplier = (int)Math.pow(10, multiplierPower);
                    int multiplier2 = (int)Math.pow(10, multiplierPower - nbDigits);

                    cost = Integer.valueOf(m.group(3)) * multiplier + Integer.valueOf(m.group(4)) * multiplier2;
				}

				if (!g.getGraph().contains(n1))
					g.getGraph().addVertice(n1);
				if (!g.getGraph().contains(n2))
					g.getGraph().addVertice(n2);

				Arc a;
				if (isDirected)
					a = g.getGraph().addDirectedEdge(n1, n2);
				else
					a = g.getGraph().addUndirectedEdge(n1, n2);
				g.setCost(a, cost);
			} else {
				throw new STPTranslationException(
						STPTranslationExceptionEnum.EDGE_DESCRIPTION_BAD_FORMAT,
						nomFic, lineNumber, s);
			}

			s = f.readLine();
			lineNumber++;
			if (s == null) {
				throw new STPTranslationException(
						STPTranslationExceptionEnum.FILE_ENDED_BEFORE_EOF_SG,
						nomFic, lineNumber, s);
			}
			s = s.toLowerCase();
			s = s.trim();
			noe--;
		}
		if (noe != 0) {
			throw new STPTranslationException(
					STPTranslationExceptionEnum.INCOHERENT_NB_EDGES, nomFic,
					lineNumber, s);
		}

		// On saute jusqu'aux terminaux
		while (!s.contains("section terminals")) {
			s = f.readLine();
			lineNumber++;
			if (s == null) {
				throw new STPTranslationException(
						STPTranslationExceptionEnum.NO_SECTION_TERM, nomFic,
						lineNumber, s);
			}
			s = s.toLowerCase();
		}

		s = f.readLine();
		lineNumber++;
		if (s == null) {
			throw new STPTranslationException(
					STPTranslationExceptionEnum.EMPTY_SECTION_TERM, nomFic,
					lineNumber, s);
		}
		s = s.toLowerCase();
		p = Pattern.compile("terminals +(\\d+)");
		m = p.matcher(s);
		int not;
		int size = g.getGraph().getNumberOfVertices();
		if (m.matches()) {
			not = Integer.valueOf(m.group(1));
			if (not > size || not <= 0) {
				throw new STPTranslationException(
						STPTranslationExceptionEnum.STRANGE_NB_TERM, nomFic,
						lineNumber, s);
			}
		} else {
			throw new STPTranslationException(
					STPTranslationExceptionEnum.TERMINALS_NUMBER_BAD_FORMAT,
					nomFic, lineNumber, s);
		}

		boolean rootSet = false;
		s = f.readLine();
		lineNumber++;
		if (s == null) {
			throw new STPTranslationException(
					STPTranslationExceptionEnum.NO_SECTION_TERM_CONTENT,
					nomFic, lineNumber, s);
		}
		s = s.toLowerCase();
		s = s.trim();
		p = Pattern.compile("(t +(\\d+))|(root +(\\d+))");
		while (!s.equals("end")) {
			m = p.matcher(s);
			if (m.matches()) {
				if (m.group(3) != null) {
					if (rootSet || !isDirected) {
						throw new STPTranslationException(
								STPTranslationExceptionEnum.TOO_MUCH_ROOT_SET,
								nomFic, lineNumber, s);
					} else {
						rootSet = true;
						((SteinerDirectedInstance) g).setRoot(Integer.valueOf(m
								.group(4)));
					}
				} else {
					n1 = Integer.valueOf(m.group(2));
					g.setRequired(n1, true);
					not--;
				}
			} else {
				throw new STPTranslationException(
						STPTranslationExceptionEnum.TERMINALS_DESC_BAD_FORMAT,
						nomFic, lineNumber, s);
			}
			s = f.readLine();
			lineNumber++;
			if (s == null) {
				throw new STPTranslationException(
						STPTranslationExceptionEnum.FILE_ENDED_BEFORE_EOF_ST,
						nomFic, lineNumber, s);
			}
			s = s.toLowerCase();

		}
		if (not != 0) {
			throw new STPTranslationException(
					STPTranslationExceptionEnum.INCOHERENT_NB_TERMS, nomFic,
					lineNumber, s);
		}

		// On saute l'espace reservé aux coordonnées
		while (!s.contains("eof")) {
			s = f.readLine();
			lineNumber++;
			if (s == null) {
				throw new STPTranslationException(
						STPTranslationExceptionEnum.FILE_ENDED_BEFORE_EOF,
						nomFic, lineNumber, s);
			}
			s = s.toLowerCase();
		}


		// TODO Ajouter dans le fichier stp ces informations
        for(Arc a : g.getGraph().getEdges()){
            g.setCapacity(a, 10);
        }
        for(Integer node : g.getGraph().getVertices()){
            g.setBranchingNodeCost(node, 1);
        }

		for(Integer node : g.getRequiredVertices())
			g.setMaximumOutputDegree(node, 1);

		g.setMaximumOutputDegree(g.getRoot(), 5);




		return g;
	}
}