package fr.whyt.parser;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import fr.whyt.craft.Node;
import fr.whyt.craft.Tree;
import fr.whyt.item.Item;
/**
* R�cup�re chaque recette pr�sente dans la base de donn�es
* et cr�e un objet appropri� le repr�sentant.<br>
* <br>
* @author WhyT
*
*/
public class RecipeDBReader implements DBReader, DBConnect {
/**
* Cr�e les recettes � partir de la base de donn�es.<br>
* La solution retenue pour cr�er les arbres de recettes s'ex�cute en deux passes :<br>
* <ul>
* <li>Lecture.</li>
* <li>Ecriture.</li>
* </ul>
* <h4>Lecture</h4>
* La phase 1, de lecture, lis int�gralement de haut en bas, de gauche � droite,
* la base de donn�es, et cr�e pour chaque recette (ligne commen�ant par "..")
* une sous-recette (sous-arbre) unique (ajout�e dans une {@link HashSet}<{@link Node}>),
* compos�e de ses ingr�dients.<br>
* Un ingr�dient est identifi� par une indentation (\t) en d�but de ligne.
* Un ingr�dient sans recette dans la base de donn�es correspond � un mat�riau primaire
* dans la recette (une feuille dans le sous-arbre).<br>
* Le HashSet contient alors toutes les recettes (et sous-recettes) de la base de donn�es.
* <h4>Ecriture</h4>
* La phase 2, d'�criture, r�utilise le HashSet des sous-recettes pour cr�er la recette compl�te
* d'un {@link Item} � partir de sa recette racine et des sous-recettes de ses ingr�dients.<br>
* Cette deuxi�me phase intervient seulement lorsque l'utilisateur demande explicitement
* une recette, ceci afin de limiter la lecture de la base de donn�es et afin d'acc�l�rer
* la cr�ation des recettes.<br>
* Cela impose le calcul des quantit�s h�rit�es d'une recette � la cr�ation et modification
* de cette derni�re.<br>
* <br>
* @param items le Set (unique) des items de la base de donn�es
* @return une Set contenant les recettes et sous-recettes (arbres et sous-arbres) de la base de donn�es
*/
public static Map<Integer, Tree> extractRecipe () {
if(!recipe.exists() || !recipe.canRead()) {
return null;
}
try {
BufferedReader br = new BufferedReader(new FileReader(recipe));
Pattern p = Pattern.compile(recipeRegExp);
Node root = null; // Node temporaire stockant la derni�re recette lue (ingr�dient racine).
for (String line; (line = br.readLine()) != null; ) {
Matcher m = p.matcher(line);
if(!m.matches()) continue; // ligne non valide
String recipe = m.group("recipe");
if(recipe == null || recipe.isEmpty()) continue; // pas de recettes : vide ou commentaire seul
String indent = m.group("indent");
String name = m.group("name");
String quantity = m.group("quantity");
if(indent.length() > 0 && root != null) { // ingr�dient et recette pr�-lue
Item tmp = findItem(name); // cherche l'Item dans la map suivant son nom
if(tmp == null) continue;
root.addSon(new Node(
Integer.parseInt(quantity!=null && !quantity.isEmpty() ? quantity : "1"),
tmp,
1)); // on cherche l'item correspondant au nom et on l'ajoute avec sa quantit� au tableau)
} else { // recette
if(root != null && !recipes.containsKey(root.hashCode())) { // on ajoute la derni�re recette lue � la Map
recipes.put(root.hashCode(), new Tree(root.clone()));
}
// on r�initialise notre recette root avec la nouvelle lue
Item tmp = findItem(name); // cherche l'Item dans la map suivant son nom
if(tmp == null) continue;
root = new Node(
Integer.parseInt(quantity!=null && !quantity.isEmpty() ? quantity : "1"),
tmp,
0); // on cherche l'item correspondant au nom et on cr�er le Node � partir de cet Item
}
}
if(root != null && !recipes.containsKey(root.hashCode())) { // on ajoute la derni�re recette de la base de donn�es � la Map
recipes.put(root.hashCode(), new Tree(root.clone()));
}
br.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return recipes;
}
private static Item findItem(String name) {
Iterator<Item> it = items.values().iterator();
while(it.hasNext()) {
Item item = it.next();
if(item.getName().toLowerCase().equals(name.toLowerCase())) return item;
}
return null;
}
}