import java.util.*;
import java.io.*;
import java.lang.reflect.*;

/** Cette classe gère une commande. Elle fournit des méthodes
    permettant d'ajouter, d'enlever, de consulter ou de lister des
    Lignes de commande. Une ligne est un couple article/quantite, ou
    un Article peut également être un Lot d'article en promotion. */

public class Commande {
  /* Liste des lignes de commande (couples article/quantite) */
  private Vector listeArticle = new Vector();
  /* le client qui a passé la commande */
  private String client;
  /* prix total de la commande */
  private float prixGlobal;

  // Constructeurs
  public Commande(String client) {
    this.client = client;
  }

  // méthodes publiques

  /** AJoute une ligne à la commande (un couple article/quantite) */
  public void addLigne(Article article_a_rajouter, int quantite) {
    listeArticle.addElement(new ArticleQuantite(article_a_rajouter, quantite));
  }

  /** Supprime une ligne de la commande */
  public void deleteLigne(int position) {
    if(listeArticle.size() >= position + 1) {
      listeArticle.removeElementAt(position);
    }
  }

  /** Permet de renvoyer une ligne de commande (un couple article/quantite) */
  public ArticleQuantite getLigne(int position) {
    if(listeArticle.size() >= position + 1) {
      return (ArticleQuantite)listeArticle.elementAt(position);
    }
    return null;
  }

  /** Affiche un ensemble de lignes décrivant chauque ligne de la
      commande (article, quantite, prix total) */

  public void decrisToi() {
    ArticleQuantite elem;
    Enumeration liste = listeArticle.elements();
    int i = 0;

    while(liste.hasMoreElements()) {
      elem = (ArticleQuantite)liste.nextElement();
      System.out.println("Commande ligne # " + i + " : " + 
			 elem.getQuantite() + " articles de type\n" + 
			 "\t- " + elem.getArticle().identifieToi() + "\n" + 
			 "\t-  Pour un prix total de : " + elem.getPrix() + 
			 "\n");
      i++;
    }
  }

  /** Renvoie le prix total de la commande, calculé à partir des lignes
     de la commande */

  public void getPrix() {
    float prixTotal = 0;
    Enumeration liste = listeArticle.elements();
    ArticleQuantite elem;

    while(liste.hasMoreElements()) {
      elem = (ArticleQuantite) liste.nextElement();
      prixTotal += elem.getPrix();
    }
    System.out.println("Prix total de la commande: " + prixTotal + " francs.\n");
  }

  public void write(String filename) {

    FileOutputStream fos=null;
    DataOutputStream dos=null;
    Enumeration liste = listeArticle.elements();
    ArticleQuantite elem;

    try {
      fos = new FileOutputStream(filename);
      dos = new DataOutputStream(fos);
    } catch (IOException e) {
      e.printStackTrace();
    }


    while(liste.hasMoreElements()) {
      elem = (ArticleQuantite) liste.nextElement();
      elem.getArticle().write(dos);
    }
  }

  public void read(String filename) throws IOException {
    FileInputStream fis; 
    DataInputStream dis = null; 
    String nomClasse =  null;
    Class classe = null;
    String ref = null;
    double prix;
    Article a = null;
    
    fis = new FileInputStream(filename);
    dis = new DataInputStream(fis);

    while ((nomClasse = dis.readUTF()) != null) {

      // Récupération de la Class à partir du nom de la classe lu
      // dans le fichier
      try {
	classe = Class.forName(nomClasse);
      } catch(ClassNotFoundException e) {
	System.out.println("Erreur, conversion de classe impossible !\n");
	e.printStackTrace();
      }

      // Récupératon des constructeurs de cette classe et les infos
      // qui les concernent (nombre et type des parametres
      Constructor[] constructeurs = classe.getDeclaredConstructors();
      System.out.println("Classe courante = " + nomClasse);
      System.out.println("Nombre de constructeurs  = " + constructeurs.length);

      // on suppose qu'il n'y a qu'un seul constructeur par article
      if(constructeurs.length != 1) {
	// Il faudrait lancer une exception a nous ici...
	System.out.println("Erreur, il y a plusieurs constructeurs\n");
	System.exit(0);
      } else {
	// On va prendre le premier constructeur et obtenir des infos sur ses
	// parametres
	Constructor c = constructeurs[0];
	Class[] paramTypes = c.getParameterTypes();
	Object[] paramConstructeurLu = new Object[paramTypes.length];
      
	System.out.println("\nNombre de parametres pour le constructeur courant = " + paramTypes.length + "\n");

	// Pour chaque parametre du constructeur on va lire la valeur 
	// correspondant à son type. Valeurs lues dans le tableau 
	// paramConstructeurLu
	for(int j = 0; j < paramTypes.length; j++) {

	  // Plusieurs manières de faire ça, avec Class.forName, etc...
	  // mais celle-ci est la plus propre pour les classes standards
	  if(paramTypes[j] == String.class) 
	    paramConstructeurLu[j] = dis.readUTF();

	  if(paramTypes[j] == double.class) 
	    paramConstructeurLu[j] = new Double(dis.readDouble());

	  if(paramTypes[j] == int.class) 
	    paramConstructeurLu[j] = new Integer(dis.readInt());
	  
	  System.out.println("Parametre lu : " + paramConstructeurLu[j] + "\n");      
	}

	// On va maintenant instancier un objet de la classe lue
	try {
	  a = (Article) c.newInstance(paramConstructeurLu);
	} catch (Exception e) {
	  System.out.println("Erreur durant la création de l'objet lu!\n");
	  e.printStackTrace();
	}

	// On l'ajoute à la commande
	addLigne(a, 1);
      }
    }
  }

}
    
