code: 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.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 STPTranslator {
  
  	/**
  	 * 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 SteinerInstance 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 (!s.contains("33d32945")) {
  			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;
  		SteinerInstance g;
  		if (m.matches()) {
  			isDirected = m.group(1).equals("arcs");
  			if (isDirected) {
  				DirectedGraph dg = new DirectedGraph();
  				g = new SteinerDirectedInstance(dg);
  				letter = 'a';
  			} else {
  				UndirectedGraph ug = new UndirectedGraph();
  				g = new SteinerUndirectedInstance(ug);
  				letter = 'e';
  			}
  			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+)");
  		int cost;
  		Integer n1, n2;
  		while (!s.equals("end")) {
  			m = p.matcher(s);
  			if (m.matches()) {
  				n1 = Integer.valueOf(m.group(1));
  				n2 = Integer.valueOf(m.group(2));
  				cost = Integer.valueOf(m.group(3));
  				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();
  		}
  		return g;
  	}
  
  	/**
  	 * 
  	 * Return the {@link SteinerDirectedInstance} conresponding to the .stp file
  	 * in input. If the file describes a graph containing 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 SteinerDirectedInstance translateDirectedFile(String nomFic)
  			throws STPTranslationException {
  		SteinerInstance g = translateFile(nomFic);
  		if (g == null || g instanceof SteinerUndirectedInstance)
  			return null;
  		else
  			return (SteinerDirectedInstance) g;
  	}
  
  	/**
  	 * 
  	 * Return the {@link SteinerUndirectedInstance} conresponding to the .stp
  	 * file in input. If the file describes a graph containing directed arcs,
  	 * then this method returns null.
  	 * 
  	 * @param nomFic
  	 *            path of the file describing the instance we want to build.
  	 * @return
  	 * @throws STPTranslationException
  	 */
  	public static SteinerUndirectedInstance translateUndirectedFile(
  			String nomFic) throws STPTranslationException {
  		SteinerInstance g = translateFile(nomFic);
  		if (g == null || g instanceof SteinerDirectedInstance)
  			return null;
  		else
  			return (SteinerUndirectedInstance) g;
  	}
  
  	/**
  	 * Translate the Steiner instance g into a .stp file, which path is nomFic.
  	 * 
  	 * @param g
  	 * @param nomFic
  	 */
  	public static void translateSteinerGraph(SteinerInstance g, String nomFic) {
  		translateSteinerGraph(g, nomFic, "");
  	}
  
  	/**
  	 * Translate the Steiner instance g into a .stp file, which path is nomFic.
  	 * Associate the instance to the name given in parameter in the file.
  	 * 
  	 * @param g
  	 * @param nomFic
  	 */
  	public static void translateSteinerGraph(SteinerInstance g, String nomFic,
  			String name) {
  		boolean isDirected = g instanceof SteinerDirectedInstance;
  		FileManager f = new FileManager();
  		f.openErase(nomFic);
  
  		f.writeln("33d32945 STP File, STP Format Version 1.0");
  		f.writeln();
  		f.writeln("SECTION Comment");
  		f.writeln("Name    \"" + name + "\"");
  		f.writeln("Creator \"Dimitri Watel\"");
  		f.writeln("Remark  \"\"");
  		f.writeln("END");
  		f.writeln();
  		f.writeln("SECTION Graph");
  		f.writeln("Nodes " + g.getGraph().getNumberOfVertices());
  		f.writeln((isDirected ? "Arcs" : "Edges") + " "
  				+ g.getGraph().getNumberOfEdges());
  		Iterator<Arc> it = g.getGraph().getEdgesIterator();
  		Arc a;
  		while (it.hasNext()) {
  			a = it.next();
  			f.writeln((isDirected ? 'A' : 'E') + " " + a.getInput() + " "
  					+ a.getOutput() + " " + g.getCost(a));
  		}
  		f.writeln("END");
  		f.writeln();
  		f.writeln("SECTION Terminals");
  		f.writeln("Terminals " + g.getNumberOfRequiredVertices());
  		if (isDirected) {
  			f.writeln("Root " + ((SteinerDirectedInstance) g).getRoot());
  		}
  		Iterator<Integer> it2 = g.getRequiredVerticesIterator();
  		Integer n;
  		while (it2.hasNext()) {
  			n = it2.next();
  			f.writeln("T " + n);
  		}
  		f.writeln("END");
  		f.writeln();
  		f.writeln("EOF");
  
  		f.closeWrite();
  	}
  }