package controller;
import java.util.Vector;

import javax.swing.tree.DefaultMutableTreeNode;
import model.article.Article;
import model.article.Nomenclature;

/**
 * GestionArticle contient toutes les fonctions statiques pour gerer les articles de la liste dans la classe BaseDonnees
 * @see BaseDonnees#listeArticles
 * @see model.article.Article
 * @author Magic Penguins
 */
public class GestionArticle {

	/**
	 * Concatene en une chaine de caracteres les informations de tous les articles de la liste
	 * @return Une chaine de caracteres contenant les informations de tous les articles de la liste
	 */
	public static String afficherArticles(){
		Article tmpArticle;
		String infoArticle="";
		for (int i=0;i<BaseDonnees.listeArticles.size();i++){
			tmpArticle = BaseDonnees.listeArticles.get(i);
			infoArticle += "Designation : "+tmpArticle.getDesignation()+"\nReference : "+tmpArticle.getReference()+"\nDelai : "+tmpArticle.getDelai()+" euros\nStock : "+tmpArticle.getStock()+"\n";
		}
		return infoArticle;
	}

	/**
	 * Recherche et renvoie un article dans la liste a partir de sa reference
	 * @param reference
	 * Reference de l'article a rechercher
	 * @return L'article recherche, ou null si non trouve
	 */
	public static Article getArticle(String reference){
		for (int i=0;i<BaseDonnees.listeArticles.size();i++){
			if (reference.equals(BaseDonnees.listeArticles.get(i).getReference())) return BaseDonnees.listeArticles.get(i);
		}
		return null;
	}

	/**
	 * Recherche et renvoie une chaine de caracteres contenant les informations de l'article recherche a partir de sa reference
	 * @param reference
	 * Reference de l'article a rechercher
	 * @return Une chaine de caracteres contenant les informations de l'article recherche
	 */
	public static String afficherArticle(String reference){
		for(int i=0;i<BaseDonnees.listeArticles.size();i++){
			if (reference.equals((String) BaseDonnees.listeArticles.get(i).getReference())){
				Article tmpArticle = BaseDonnees.listeArticles.get(i);
				String infoArticle="";
				infoArticle += "\nDesignation : "+tmpArticle.getDesignation()+"\nReference : "+tmpArticle.getReference()+"\nDelai : "+tmpArticle.getDelai()+" euros\nStock : "+tmpArticle.getStock()+"\n";
				return infoArticle;
			}
		}
		return "\nArticle non trouve\n";
	}

	/**
	 * Recherche et renvoie une chaine de caracteres contenant les informations de l'article recherche a partir de sa position dans la liste
	 * @param pos
	 * Position de l'article a rechercher dans la liste
	 * @return Une chaine de caracteres contenant les informations de l'article recherche
	 */
	public static String afficherArticle(int pos){
		if (pos<BaseDonnees.listeArticles.size()){
			Article tmpArticle = BaseDonnees.listeArticles.get(pos);
			String infoArticle="";
			infoArticle += "\nDesignation : "+tmpArticle.getDesignation()+"\nReference : "+tmpArticle.getReference()+"\nDelai : "+tmpArticle.getDelai()+" euros\nStock : "+tmpArticle.getStock()+"\n";
			return infoArticle;
		}
		else return "\nArticle non trouve\n";
	}

	/**
	 * Cree un article a partir des informations fournies
	 * On ne peut pas avoir deux articles ayant la meme designation
	 * @param designation
	 * Designation de l'article
	 * @param delai
	 * Delai pour l'article
	 * @param stock
	 * Stock de l'article
	 * @return True si la creation a reussie, false sinon
	 */
	public static boolean creerArticle(String designation, int delai, int stock){
		for(int i=0;i<BaseDonnees.listeArticles.size();i++){
			if (designation.equals((String) BaseDonnees.listeArticles.get(i).getDesignation()))	return false;
		}
		BaseDonnees.listeArticles.add(new Article(designation,delai,stock));
		return true;
	}

	/**
	 * Supprime un article a partir de sa reference
	 * @param reference
	 * Reference de l'article
	 * @return True si la suppression a reussie, false sinon
	 */
	public static boolean supprimerArticle(String reference){
		for(int i=0;i<BaseDonnees.listeArticles.size();i++){
			if (reference.equals((String) BaseDonnees.listeArticles.get(i).getReference())){
				for (int j=0;j<BaseDonnees.listeArticles.size();j++){
					for (int k=0;k<BaseDonnees.listeArticles.get(j).getNomenclature().size();k++){
						if (BaseDonnees.listeArticles.get(j).getNomenclature().get(k).getArticle().getReference().equals(reference)) BaseDonnees.listeArticles.get(j).supprimerNomenclature(k);
					}
				}
				BaseDonnees.listeArticles.remove(i);
				return true;
			}
		}
		return false;
	}

	/**
	 * Supprime un article a partir de sa position dans la liste
	 * @param pos
	 * Position de l'article dans la liste
	 * @return True si la suppression a reussie, false sinon
	 */
	public static boolean supprimerArticle(int pos){
		if (pos<BaseDonnees.listeArticles.size()){
			for (int j=0;j<BaseDonnees.listeArticles.size();j++){
				for (int k=0;k<BaseDonnees.listeArticles.get(j).getNomenclature().size();k++){
					if (BaseDonnees.listeArticles.get(j).getNomenclature().get(k).getArticle().getReference().equals(BaseDonnees.listeArticles.get(pos).getReference())) BaseDonnees.listeArticles.get(j).supprimerNomenclature(k);
				}
			}
			BaseDonnees.listeArticles.remove(pos);
			return true;
		}
		else return false;
	}

	/**
	 * Actualise la nomenclature de l'article voulue
	 * @param article
	 * Article avec la nouvelle nomenclature actualisee
	 * @return True si l'actualisation a reussie, false sinon
	 */
	public static boolean actualiserArticleNomenclature(Article article){
		for (int i=0;i<BaseDonnees.listeArticles.size();i++){
			if (BaseDonnees.listeArticles.get(i).getReference().equals(article.getReference())) {
				BaseDonnees.listeArticles.get(i).setNomenclature(article.getNomenclature());
				return true;
			}
		}
		return false;
	}

	/**
	 * Actualise les nomenclature de la liste d'articles mis en parametre
	 * @param articles
	 * Articles avec les nouvelles nomenclatures actualisees
	 */
	public static void actualiserArticleNomenclature(Vector<Article> articles){
		for (int j=0;j<articles.size();j++){
			for (int i=0;i<BaseDonnees.listeArticles.size();i++){
				if (BaseDonnees.listeArticles.get(i).getReference().equals(articles.get(j).getReference())) {
					BaseDonnees.listeArticles.get(i).setNomenclature(articles.get(j).getNomenclature());
				}
			}
		}
	}

	/**
	 * Met a jour la liste des articles a partir des informations d'un arbre (root et ses fils)
	 * @param root
	 * Noeud a partir duquel on commencera a mettre a jour les articles
	 */
	public static void convertirListe(DefaultMutableTreeNode root){
		Vector<Nomenclature> newNomenclature = new Vector<Nomenclature>();
		for (int i=0;i<root.getChildCount();i++){
			newNomenclature.add((Nomenclature)((DefaultMutableTreeNode)root.getChildAt(i)).getUserObject());
			convertirListe((DefaultMutableTreeNode) root.getChildAt(i));
		}
		if (!newNomenclature.isEmpty()) GestionArticle.getArticle(((Nomenclature)root.getUserObject()).getArticle().getReference()).setNomenclature(newNomenclature);
	}

	/**
	 * Renvoie d'une liste de tous les fils et sous-fils d'un noeud
	 * @param root
	 * Noeud pour lequel on cherche ses fils
	 * @return Une liste des references des articles fils
	 */
	public static Vector<String> trouverNoeudsFils(DefaultMutableTreeNode root){
		return recursionNoeudsFils(root,new Vector<String>());
	}
	protected static Vector<String> recursionNoeudsFils(DefaultMutableTreeNode root,  Vector<String> liste){
		for (int i=0;i<root.getChildCount();i++){
			liste.add( ((Nomenclature)((DefaultMutableTreeNode)root.getChildAt(i)).getUserObject()).getArticle().getReference() );
			liste = recursionNoeudsFils((DefaultMutableTreeNode)root.getChildAt(i),liste);
		}
		return liste;
	}

	/**
	 * Renvoie d'une liste de tous les peres d'un noeud
	 * @param node
	 * Noeud pour lequel on cherche ses peres
	 * @return Une liste des references des articles parents
	 */
	public static Vector<String> trouverNoeudsPeres(DefaultMutableTreeNode node){
		Vector<String> liste = new Vector<String>();
		while (!node.isRoot()){
			liste.add( ((Nomenclature)((DefaultMutableTreeNode)node.getParent()).getUserObject()).getArticle().getReference() );
			node = (DefaultMutableTreeNode)node.getParent();
		}
		return liste;
	}

	/**
	 * Verification pour savoir si on peut ajouter un composant a un article comme lien de nomenclature
	 * On ne peut pas ajouter un article a lui meme
	 * On ne peut pas ajouter un composant a un article si l'article l'a deja en composant direct
	 * On ne peut pas ajouter un composant a un article si ce composant est l'un des parents de l'article
	 * On ne peut pas ajouter un composant a un article si l'un des fils ou sous fils est l'un des parents de l'article
	 * @param article
	 * Article dans lequel on veut ajouter le composant
	 * @param composant
	 * Article que l'on veut ajouter
	 * @return True si on peut effectuer l'action, false sinon
	 */
	public static boolean verifierAjout(Article article, Article composant){
		if (article.getReference().equals(composant.getReference())) return false;

		for (int i=0;i<article.getNomenclature().size();i++){
			if (article.getNomenclature().get(i).getArticle().getReference().equals(composant.getReference())) return false;
		}

		Vector<DefaultMutableTreeNode> listeArbresArticles = new Vector<DefaultMutableTreeNode>();
		for (int i=0;i<BaseDonnees.listeArticles.size();i++){
			listeArbresArticles.add(BaseDonnees.listeArticles.get(i).convertirArbre());
		}
		Vector<String> listeParents = new Vector<String>();
		for (int i=0;i<listeArbresArticles.size();i++){
			if (chercherNoeud(listeArbresArticles.get(i),article)!=null) {
				DefaultMutableTreeNode node = chercherNoeud(listeArbresArticles.get(i),article);
				Vector<String> listeParents2 = trouverNoeudsPeres(node);
				for (int j=0;j<listeParents2.size();j++){
					listeParents.add(listeParents2.get(j));
				}
			}
		}
		for (int i=0;i<listeParents.size();i++){
			if (listeParents.get(i).equals(composant.getReference())) return false;
		}

		Vector<String> listeFils = trouverNoeudsFils(composant.convertirArbre());
		for (int i=0;i<listeParents.size();i++){
			for (int j=0;j<listeFils.size();j++){
				if (listeParents.get(i).equals(listeFils.get(j))) return false;
			}
		}
		return true;
	}

	/**
	 * Cherche et renvoie le noeud d'un article dans un arbre
	 * @param root
	 * La racine de l'arbre
	 * @param article
	 * Article a rechercher
	 * @return Le noeud de l'article dans l'arbre, a partir duquel on pourra acceder aux parents et fils
	 */
	public static DefaultMutableTreeNode chercherNoeud (DefaultMutableTreeNode root, Article article){
		for (int i=0;i<root.getChildCount();i++){
			if ( ((Nomenclature)((DefaultMutableTreeNode)root.getChildAt(i)).getUserObject()).getArticle().getReference().equals(article.getReference()) ) return (DefaultMutableTreeNode) root.getChildAt(i);
			chercherNoeud ((DefaultMutableTreeNode)root.getChildAt(i),article);
		}
		return null;
	}

}
