import java.util.*;
import java.awt.*;
import java.awt.event.*;
import Article.RefDoubleException;
import Article.RefExistePasException;

public class TestGraphiqueCommande extends Frame {
    Commande commande;
    LigneFactureDialog lfDialog;
    TextField num = new TextField(10);
    TextField client = new TextField(20);
    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(),
              panelGauche = new Panel(),
              panelDroit = new Panel();
        // Panel du haut
        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 de gauche (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();
        panelGauche.setLayout(bl);
        panelGauche.add(new Label("Lignes Factures"),BorderLayout.NORTH);
        panelGauche.add(lignesFacture, BorderLayout.CENTER);
        Panel panelBoutons = new Panel();
        panelBoutons.add(bNouvelle);
        panelGauche.add(panelBoutons, BorderLayout.SOUTH);
        add(panelGauche, BorderLayout.CENTER);
        // 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();
        }
        // -1 car aucune ligne à transmettre (voir ALModifier)
        lfDialog.setLigneCommande(-1);
        lfDialog.setVisible(true);
        LigneCommande lc = lfDialog.getLigneCommande();
        if (lc != null) // null si annulation par l'utilisateur
          commande.ajouterLigneCommande(lc);
        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();
          if (numLigneChoisie != -1) {
            if (lfDialog == null) {
              lfDialog = new LigneFactureDialog(TestGraphiqueCommande.this);
              pack();
            }
            lfDialog.setLigneCommande(numLigneChoisie);
            // Blocage ici jqu'à ce que la fenêtre modale soit cachée
            lfDialog.setVisible(true);
            System.out.println(commande); // pour tester
            afficheCommande();
          }
          else
            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() {
        afficheNumero();
        afficheClient();
        afficheLignes();
    }

    private void afficheNumero() {
        num.setText(String.valueOf(commande.getNumCommande()));
    }

    private void afficheClient() {
        if (commande.getClient() != "")
          client.setText(commande.getClient());
        else
          client.setText("");
    }

    private void afficheLignes() {
        lignesFacture.removeAll();
        //if (commande.lignesCommande != null) {
          Enumeration e = commande.lignesCommande.elements();
          while (e.hasMoreElements())
            ajouteLigne((LigneCommande)e.nextElement());
        //}
    }

    private void ajouteLigne(LigneCommande l) {
        lignesFacture.addItem(l.toString());
    }

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

    public static void main(String args[]) {
        // Enregistrement d'articles
        // Création des articles
        try {
          Article s1 = new Stylo("s1", "Stylo", "Parker", 520, Color.black);
          Article s2 = new Stylo("s2", "Stylo", "Waterman", 800, Color.gray);
          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);
        }

        // Pour vérification
        Enumeration e = Article.articles.keys();
        while (e.hasMoreElements()) {
          String cle = (String)e.nextElement();
          System.out.println("CLE : --" + cle + "--"
             + ((Article)(Article.articles.get(cle))).toString());
        }

        Article a1 = (Article)Article.articles.get("s1");
        Article a2 = Article.getArticle("s1");
        System.out.println(a1 + "\n" + a2);

        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 {
    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
    List lArticles = new List();
    // Liste inverse pour retrouver la position d'un article dans lArticles
    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.articles.keys();
        int i = 0;
        Article a;
        while (e.hasMoreElements()) {
          String cle = (String)e.nextElement();
          a = (Article)(Article.articles.get(cle));
          lArticles.addItem(cle + " : "
             + a.toString());
          listeInverseArticles.put(a, new Integer(i++));
        }
        add(new Label("Produit"));
        add(lArticles);
        add(valider);
        add(annuler);
        valider.addActionListener(new ALvalider());
        annuler.addActionListener(new ALannuler());
    }

    class ALvalider implements ActionListener {
       public void actionPerformed(ActionEvent e) {
          // Récupère la clé depuis la ligne sélectionnée dans la liste
          // (c'est le premier mot)
          String cle = lArticles.getSelectedItem();
          cle = cle.substring(0, cle.indexOf(' '));
          ligneCommande.setArticle(Article.getArticle(cle));
          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 (numLigne == -1) {
        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 {
        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()));
      }
    }

    /* 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;
    }
  }
}
