import java.util.*;
import java.awt.*;
import java.awt.event.*;
import mesutils.*;

public class TestGraphiqueCommande extends Frame {
  final static int AJOUT = 0; // Pour la fenêtre Dialog
  final static int MODIF = 1;

  Commande commande;
  LigneFactureDialog lfDialog;
  TextField num = new TextField(10),
            client = new TextField(20),
            totalCommande = new TextField(10);
  List lignesFacture = new List(10);
  Button bNouvelle = new Button("Nouvelle facture"),
    bAjouter = new Button("Ajouter"),
    bSupprimer = new Button("Supprimer"),
    bModifier = new Button("Modifier");

  public TestGraphiqueCommande() {
    // Frame f = new Frame("Gestion d'une facture");
    WindowListener l = new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        System.exit(0) ;
      }
    };
    addWindowListener(l) ;
    setLayout(new BorderLayout());
    Panel panelHaut = new Panel(),// numéro de commande et nom du client
      panelCentre = new Panel(),  // Lignes de la commande
      panelDroit = new Panel(),   // 3 boutons pour modifs de la commande
      panelBas = new Panel();     // Total facture et bouton "Nouvelle commande"
    
    panelHaut.add(new Label("Numéro facture"));
    num.setEditable(false);
    panelHaut.add(num);
    panelHaut.add(new Label("Client"));
    panelHaut.add(client);
    add(panelHaut, BorderLayout.NORTH);
    // Panel du Centre (mis au centre car s'étend au maximum)
    // Il est nécessaire d'y mettre un BorderLayout
    // pour positionner correctement les composants
    // l'un en dessous de l'autre
    BorderLayout bl = new BorderLayout();
    panelCentre.setLayout(bl);
    panelCentre.add(new Label("Lignes Factures"),BorderLayout.NORTH);
    panelCentre.add(lignesFacture, BorderLayout.CENTER);
    add(panelCentre, BorderLayout.CENTER);
    // Panel panelBoutons = new Panel(); // En bas du panelCentre
    panelBas.add(new Label("Total Commande :"));
    panelBas.add(totalCommande);
    panelBas.add(bNouvelle);
    add(panelBas, BorderLayout.SOUTH);
    // panelCentre.add(panelBoutons, BorderLayout.SOUTH);
    // Panel de droite
    // pour mettre les boutons l'un en dessous de l'autre
    GridLayout gl = new GridLayout(3,1);
    gl.setVgap(2);
    panelDroit.setLayout(gl);
    panelDroit.add(bAjouter);
    panelDroit.add(bSupprimer);
    panelDroit.add(bModifier);
    add(panelDroit, BorderLayout.EAST);

    // Le menu
    MenuBar menuBar = new MenuBar();
    Menu menu = new Menu("Fichier");
    MenuItem miImprimer =
      new MenuItem("Imprimer",
                   new MenuShortcut(KeyEvent.VK_I));
    MenuItem miQuitter =
      new MenuItem("Quitter",
                   new MenuShortcut(KeyEvent.VK_Q));
    menu.add(miImprimer);
    menu.addSeparator();
    menu.add(miQuitter);
    menuBar.add(menu);
    setMenuBar(menuBar);

    pack();
    setVisible(true);

    // Listeners des boutons :
    bNouvelle.addActionListener(new
                                ActionListener() {
      public void actionPerformed(ActionEvent e) {
        TestGraphiqueCommande.this.nouvelleFacture();
      }
    });
    // Pas de classe anonyme car Symantec 1.53 ne sait pas les débugger
    bAjouter.addActionListener(new ALAjouter());
    bModifier.addActionListener(new ALModifier());
    bSupprimer.addActionListener(new ALSupprimer());
    client.addActionListener(new ALClient());

    // Listeners du menu
    miQuitter.addActionListener(new ALQuitter());
    miImprimer.addActionListener(new ALImprimer());

    // Pour enregistrer le client sans taper Return
    client.addFocusListener(new FLClient());
  }

  // Classes de Listener
  class ALAjouter implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      // Ouverture fenêtre pour ajouter une ligne de facture
      if (lfDialog == null) {
        lfDialog = new LigneFactureDialog(TestGraphiqueCommande.this);
        lfDialog.pack();
      }
      lfDialog.setTypeAction(AJOUT);
      // -1 est bidon car aucune ligne à transmettre (voir ALModifier)
      lfDialog.setLigneCommande(-1);
      lfDialog.setVisible(true);
      // Blocage ici jqu'à ce que la fenêtre modale soit cachée
      LigneCommande lc = lfDialog.getLigneCommande();
      if (lc != null) // null si annulation par l'utilisateur
        commande.ajouterLigneCommande(lc);
      totalCommande.setText(Float.toString(commande.prixTotal()));
      System.out.println(commande); // Pour vérifier
      afficheCommande();
    }
  }

  class ALModifier implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      // numLigneChoisie : numéro de la ligne de la facture
      // à modifier (récupéré dans la liste)
      int numLigneChoisie = lignesFacture.getSelectedIndex();
      System.err.println(numLigneChoisie);
      if (numLigneChoisie != -1) { // une ligne a bien été choisie par l'utilisateur
        if (lfDialog == null) {
          lfDialog = new LigneFactureDialog(TestGraphiqueCommande.this);
          pack();
        }
        lfDialog.setTypeAction(MODIF);
        lfDialog.setLigneCommande(numLigneChoisie);
        lfDialog.setVisible(true);
        // Blocage ici jqu'à ce que la fenêtre modale soit cachée
        System.out.println(commande); // pour tester
        afficheCommande();
      }
      else // Pas de ligne sélectionnée par l'utilisateur
        Toolkit.getDefaultToolkit().beep();
    }
  }

  class ALSupprimer implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      int numLigneChoisie = lignesFacture.getSelectedIndex();
      if (numLigneChoisie != -1) {
        commande.enleverLigneCommande(numLigneChoisie);
        System.out.println(commande);
        afficheCommande();
      }
      else
        Toolkit.getDefaultToolkit().beep();
    }
  }

  class ALClient implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      commande.setClient(client.getText());
    }
  }

  class ALQuitter implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      System.exit(0);
    }
  }

  class ALImprimer implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      print();
    }
  }

  class FLClient extends FocusAdapter {
    public void focusLost(FocusEvent e) {
      commande.setClient(client.getText());
    }
  }

  // Pour enregistrer les préférence d'impression de l'utilisateur
  private static Properties printPrefs = new Properties();

  /** Imprimer la facture (à placer ici ou dans Commande ?) */
  void print() {
    PrintJob printJob =
      getToolkit().getPrintJob(this,
                               "Imprimer la facture",
                               printPrefs);
    // Si l'utilisateur a cliqué sur "Cancel"
    if (printJob == null) return;

    Graphics page = printJob.getGraphics();
    TestGraphiqueCommande.this.printAll(page); // pour l'instant j'imprime tout
    page.dispose();
    printJob.end();
  }

  /** Récupère la ligne de commande choisie dans la liste */
  LigneCommande getligneChoisie() {
    int indice = lignesFacture.getSelectedIndex();
    if (indice != -1)
      return commande.ligneNumero(indice);
    else
      return null;
  }

  void afficheCommande() {
    num.setText(String.valueOf(commande.getNumCommande()));
    client.setText(commande.getClient());
    afficheLignes();
    totalCommande.setText(Float.toString(commande.prixTotal()));
  }

  private void afficheLignes() {
    lignesFacture.removeAll();
    Enumeration e = commande.lignesCommande();
    while (e.hasMoreElements())
      lignesFacture.add(((LigneCommande)e.nextElement()).decritToi());
  }

  void nouvelleFacture() {
    // crée et affiche une nouvelle facture
    commande = new Commande();
    lignesFacture.removeAll();
    afficheCommande();
  }

  public static void main(String args[]) throws RefExistePasException {
        // Enregistrement d'articles
        // Création des articles
        try {
          Article s1 = new Stylo("s1", "Stylo", "Parker", 520, "Noir");
          Article s2 = new Stylo("s2", "Stylo", "Waterman", 800, "Gris");
          Article r1 = new Ramette("r1", "Ramette", "Clairefontaine", 50, 80);
          Article l1 = new Lot("l1", "s1", 100);
          Article l2 = new Lot("l2", "r1", 50);
          Article l3 = new Lot("l3", "s1", 75);
        } 
        catch (RefDoubleException e) {
          System.err.println("Référence " + e.getReference()
                              + " en double !!");
          System.exit(1);
        } 
        catch (RefExistePasException e) {
          System.err.println("Référence " + e.getReference()
                              + " n'existe pas (utilisée dans un lot)");
          System.exit(1);
        }
        // Pour vérification
        Enumeration e = Article.refArticles();
        while (e.hasMoreElements()) {
          String cle = (String)e.nextElement();
          System.out.println("CLE : --" + cle + "--"
             + ((Article)Article.getArticle(cle)).decritToi());
        }

        TestGraphiqueCommande f = new TestGraphiqueCommande();
        f.nouvelleFacture();
    }

  /** Fenêtre modale pour entrer ou modifier une
      ligne de commande */
  // Mise en classe interne de TestGraphiqueCommande
  class LigneFactureDialog extends Dialog {
    int typeAction; // AJOUT ou MODIF
    LigneCommande ligneCommande;
    TextField quantiteProduit = new TextField(10);
    Button valider = new Button("Valider");
    Button annuler = new Button("Annuler");
    // Cette liste contient les références articles + un descriptif de l'objet
    ListObjets lArticles = new ListObjets(); // une de mes classes utilitaires
    // Liste inverse pour retrouver la position d'un article dans lArticles
    // (utilisée pour sélectionner la bonne ligne au départ)
    private Hashtable listeInverseArticles = new Hashtable();

    LigneFactureDialog(Frame f) {
        super(f, "Commande d'un produit", true);
        setLayout(new FlowLayout());
        add(new Label("Quantité"));
        add(quantiteProduit);
        // On remplit la liste des articles
        Enumeration e = Article.refArticles();
        int i = 0;
        Article a;
        while (e.hasMoreElements()) {
          String cle = (String)e.nextElement();
          a = null;
          try {
          a = (Article)(Article.getArticle(cle));
          } 
          catch (RefExistePasException err) {
            System.err.println("Référence " + err.getReference() +
                               " n'existe pas !!");
            System.exit(1);
          }
          lArticles.add(a.decritToi(), a);
          listeInverseArticles.put(a, new Integer(i++));
        }
        add(new Label("Produit"));
        lArticles.setTaille(200,100); // ne marche pas !
        add(lArticles);
        add(valider);
        add(annuler);
        valider.addActionListener(new ALvalider());
        annuler.addActionListener(new ALannuler());
    }

    /* Indique si on utilise la fenêtre de dialogue pour ajouter ou 
       modifier une ligne */
    void setTypeAction(int unTypeAction) {
      switch (unTypeAction) { // juste pour réviser la syntaxe !
        case AJOUT:
        case MODIF: 
          typeAction = unTypeAction;
          break;
        default: 
          System.err.println("Mauvais type de modification");
          System.exit(1);
        }
    }


    /* L'utilisateur a validé ses modifications */
    class ALvalider implements ActionListener {
       public void actionPerformed(ActionEvent e) {
          ligneCommande.setArticle((Article)lArticles.getSelectedObjet());
          ligneCommande.setQuantite(Float.valueOf(quantiteProduit.getText()).floatValue());
          LigneFactureDialog.this.setVisible(false);
       }
    }

    class ALannuler implements ActionListener {
       public void actionPerformed(ActionEvent e) {
         ligneCommande = null;
         LigneFactureDialog.this.setVisible(false);
       }
    }

    void setLigneCommande(int numLigne) {
      if (typeAction == AJOUT) { // on ajoute une nouvelle ligne de commande
        ligneCommande = new LigneCommande();
        quantiteProduit.setText("");
        // Enlève la sélection actuelle de la liste des produits
        // (s'il  y en a une)
        lArticles.deselect(lArticles.getSelectedIndex());
      }
      else if (typeAction == MODIF) { // on modifie une ligne de commande
        System.err.println("Modif de ligne " + numLigne);
        ligneCommande =
          TestGraphiqueCommande.this.commande.ligneNumero(numLigne);
        quantiteProduit.setText(Float.toString(ligneCommande.getQuantite()));
        // Sélectionne la bonne ligne dans la liste des produits
        lArticles.select(numProduitDansListe(ligneCommande.getArticle()));
      }
      else { // Erreur sur le type
        System.err.println("Type d'action inconnu : " + typeAction);
        System.exit(1);
      }
    }

    /* Donne la position de l'article dans la liste lArticles */
    private int numProduitDansListe(Article article) {
        return ((Integer)(listeInverseArticles.get(article))).intValue();
    }

    LigneCommande getLigneCommande() {
      return ligneCommande;
    }
  }
}
