import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;

/**
 * A class that represents GUIs for inserting, modifying, deleting
 * and selecting CDs from a CD collection.
 * @author Derek Bridge
 */
public class CDGUI
   extends JFrame
   implements ICDGUI
{
/* =======================================================================
       CONSTRUCTORS
   =======================================================================
*/

   /**
    * Allocates a new CD GUI object for a specified collection of
    * CDs.
    *
    * @param theParent the component that launched this GUI
    * @param theCDCollection the collection of CDs.
    */
   public CDGUI(ICDGUI theParent, CDCollection theCDCollection)
   {  super("CD-Direkt CDs");
      parentComp = theParent;
      cdCollection = theCDCollection;
      JPanel searchPanel = createSearchPanel();
      JPanel cdPanel = createCDPanel();
      JPanel returnPanel = createReturnPanel();
      Container contentPane = getContentPane();
      contentPane.setLayout(new BorderLayout());
      contentPane.add(searchPanel, BorderLayout.WEST);
      contentPane.add(cdPanel, BorderLayout.EAST);
      contentPane.add(returnPanel, BorderLayout.SOUTH);
      setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
      pack();
   }

/* =======================================================================
       PUBLIC INTERFACE
   =======================================================================
*/

/* --Setters----------------------------------------------------------- */

   /**
    * Displays the current CD's details (if any) on the CD panel.
    */
   public void displayCurrentCD()
   {  if (currentCD == null)
      {  idNumTF.setText("");
         artistTF.setText("");
         titleTF.setText("");
         priceTF.setText("");
         tracksList.setListData(new Vector());
      }
      else
      {  idNumTF.setText(currentCD.getIdNum());
         artistTF.setText(currentCD.getArtist());
         titleTF.setText(currentCD.getTitle());
         priceTF.setText("" + currentCD.getPrice());
         tracksList.setListData(currentCD.getTracks());
      }
   }

   /**
    * Disables this GUI when the user goes to some other GUI.
    */
   public void disableGUI()
   {  newBtn.setEnabled(false);
      insertBtn.setEnabled(false);
      cancelBtn.setEnabled(false);
      modifyBtn.setEnabled(false);
      deleteBtn.setEnabled(false);
      cdList.setEnabled(false);
      artistTF.setEnabled(false);
      titleTF.setEnabled(false);
      priceTF.setEnabled(false);
      tracksList.setEnabled(false);
      deleteTrackBtn.setEnabled(false);
      newTrackTF.setEnabled(false);
      saveTrackBtn.setEnabled(false);
      returnBtn.setEnabled(false);
   }

   /**
    * Enable this GUI when the user returns from some other GUI.
    */
   public void enableGUI()
   {  setGUIForCDViewing();
      returnBtn.setEnabled(true);
   }

   /**
    * If one GUI sends you to another GUI and that GUI wants to
    * supply a result, it does so using this setter. But CD GUIs
    * do nothing with any such result.
    *
    * @param anObj the result being supplied.
    */
   public void setResult(Object anObj)
   {
   }


/* =======================================================================
       HELPER METHODS
   =======================================================================
*/

   /**
    * Lays out a panel containing a list of current CDs, and
    * offers search options.
    */
   private JPanel createSearchPanel()
   {  viewedCDs = cdCollection.findAll();
      cdList = new JList(viewedCDs);
      cdList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
      JScrollPane scrollPane = new JScrollPane(cdList);
      JLabel idNumLbl = new JLabel("CD number:");
      searchIdNumTF = new JTextField("", ID_TF_COLS);
      JLabel artistLbl = new JLabel("Artist:");
      searchArtistTF = new JTextField("", ARTIST_TF_COLS);
      JLabel titleLbl = new JLabel("Title:");
      searchTitleTF = new JTextField("", TITLE_TF_COLS);
      searchBtn = new JButton(SEARCH);
      fullBtn = new JButton(FULL);

      cdList.addListSelectionListener(new ListSelectionListener()
      {  public void valueChanged(ListSelectionEvent lse)
         {  if (lse.getValueIsAdjusting()) // mouse wasn't yet at rest
            {  // do nothing
            }
            if (cdList.isSelectionEmpty()) // somehow, no selection was made
            {  // do nothing
            }
            else
            {  int index = cdList.getSelectedIndex(); 
               currentCD = (CD) viewedCDs.elementAt(index);
               setGUIForCDViewing();
            }
          }
      });

      searchBtn.addActionListener(new ActionListener()
      {  public void actionPerformed(ActionEvent ae)
         {  String idNum = searchIdNumTF.getText().trim();
            String artist = searchArtistTF.getText().trim();
            String title = searchTitleTF.getText().trim();
            if (! idNum.equals("") && artist.equals("") && title.equals(""))
            {  viewedCDs = cdCollection.findById(idNum);
               cdList.setListData(viewedCDs);
               cdList.setSelectedIndex(-1);
            }
            else if (idNum.equals("") && ! artist.equals("") && 
               title.equals(""))
            {  viewedCDs = cdCollection.findByArtist(artist);
               cdList.setListData(viewedCDs);
               cdList.setSelectedIndex(-1);
            }
            else if (idNum.equals("") && artist.equals("") && 
               ! title.equals(""))
            {  viewedCDs = cdCollection.findByTitle(title);
               cdList.setListData(viewedCDs);
               cdList.setSelectedIndex(-1);
            }
            else
            {  JOptionPane.showMessageDialog(null,
                  "To search, you must supply either a CD " +
                  "identification number or an artist or a title.",
                  "Error in search values",
                  JOptionPane.ERROR_MESSAGE);
            }
         }
      });

      fullBtnLstnr = new ActionListener()
      {  public void actionPerformed(ActionEvent ae)
         {  searchIdNumTF.setText("");
            searchArtistTF.setText("");
            searchTitleTF.setText("");
            viewedCDs = cdCollection.findAll();
            cdList.setListData(viewedCDs);
            cdList.setSelectedIndex(-1);
         }
      };
      fullBtn.addActionListener(fullBtnLstnr);

      JPanel p = new JPanel();
      GridBagLayout gbl = new GridBagLayout();
      GridBagConstraints gbc = new GridBagConstraints();
      p.setLayout(gbl);
      gbc.insets = new Insets(5, 5, 5, 0); 
      gbc.fill = GridBagConstraints.NONE;
      gbc.anchor = GridBagConstraints.CENTER;
      GuiUtility.addComp(scrollPane, p, gbl, gbc, 0, 0, 
         1, GridBagConstraints.REMAINDER, 0, 0);
      gbc.fill = GridBagConstraints.HORIZONTAL; 
      gbc.anchor = GridBagConstraints.WEST;
      GuiUtility.addComp(idNumLbl, p, gbl, gbc, 1, 0, 1, 1, 0, 0);
      GuiUtility.addComp(Box.createHorizontalStrut(10), p, gbl, gbc, 
         1, 1, 1, 1, 0, 0);
      GuiUtility.addComp(searchIdNumTF, p, gbl, gbc, 1, 2, 1, 1, 0, 0);
      GuiUtility.addComp(artistLbl, p, gbl, gbc, 2, 0, 1, 1, 0, 0);
      GuiUtility.addComp(Box.createHorizontalStrut(10), p, gbl, gbc, 
         2, 1, 1, 1, 0, 0);
      GuiUtility.addComp(searchArtistTF, p, gbl, gbc, 2, 2, 1, 1, 0, 0);
      GuiUtility.addComp(titleLbl, p, gbl, gbc, 3, 0, 1, 1, 0, 0);
      GuiUtility.addComp(Box.createHorizontalStrut(10), p, gbl, gbc, 
         3, 1, 1, 1, 0, 0);
      GuiUtility.addComp(searchTitleTF, p, gbl, gbc, 3, 2, 1, 1, 0, 0);
      gbc.fill = GridBagConstraints.NONE;
      gbc.anchor = GridBagConstraints.CENTER;
      GuiUtility.addComp(searchBtn, p, gbl, gbc, 4, 0,
         1, GridBagConstraints.REMAINDER, 0, 0);
      GuiUtility.addComp(fullBtn, p, gbl, gbc, 5, 0,
         1, GridBagConstraints.REMAINDER, 0, 0);
      return p;
   }

   /**
    * Lays out a panel containing a selected CD's details, and
    * offers update options.
    */
   private JPanel createCDPanel()
   {  JLabel idNumLbl = new JLabel("CD number:");
      idNumTF = new JTextField("", ID_TF_COLS);
      idNumTF.setEnabled(false);
      JLabel artistLbl = new JLabel("Artist:");
      artistTF = new JTextField("", ARTIST_TF_COLS);
      JLabel titleLbl = new JLabel("Title:");
      titleTF = new JTextField("", TITLE_TF_COLS);
      JLabel priceLbl = new JLabel("Price:");
      priceTF = new JTextField("", PRICE_TF_COLS);
      newBtn = new JButton(NEW);
      insertBtn = new JButton(INSERT);
      cancelBtn = new JButton(CANCEL);
      modifyBtn = new JButton(MODIFY);
      deleteBtn = new JButton(DELETE);
      JLabel tracksLbl = new JLabel("Tracks:");
      tracksList = new JList(new Vector());
      tracksList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
      JScrollPane scrollPane = new JScrollPane(tracksList);
      deleteTrackBtn = new JButton(DELETE_TRACK);
      newTrackTF = new JTextField("", TRACK_TF_COLS);
      saveTrackBtn = new JButton(SAVE_TRACK);
      setGUIForNoCDSelected();

      newBtn.addActionListener(new ActionListener()
      {  public void actionPerformed(ActionEvent ae)
         {  setGUIForCDEntry();
         }
      });

      insertBtn.addActionListener(new ActionListener()
      {  public void actionPerformed(ActionEvent ae)
         {  String artist = artistTF.getText().trim();
            String title = titleTF.getText().trim();
            int price = 0;
            try
            {  price = Integer.parseInt(priceTF.getText().trim());
            }
            catch (NumberFormatException nfe)
            {  price = 0;
            }
            if (artist.equals("") || title.equals("") ||
                price <= 0)
            {  JOptionPane.showMessageDialog(null,
                  "You must supply an artist and title, and a price " +
                  "that is greater than zero.", "Incomplete new CD data",
                  JOptionPane.ERROR_MESSAGE);
            }
            else
            {  currentCD = 
                  new CD(artist, title, price);
               cdCollection.add(currentCD);
               setGUIForCDViewing();
               fullBtnLstnr.actionPerformed(new ActionEvent(
                  fullBtn, ActionEvent.ACTION_PERFORMED, FULL));
            }
         }
      });

      cancelBtn.addActionListener(new ActionListener()
      {  public void actionPerformed(ActionEvent ae)
         {  setGUIForNoCDSelected();
         }
      });

      modifyBtn.addActionListener(new ActionListener()
      {  public void actionPerformed(ActionEvent ae)
         {  String artist = artistTF.getText().trim();
            String title = titleTF.getText().trim();
            int price = 0;
            try
            {  price = Integer.parseInt(priceTF.getText().trim());
            }
            catch (NumberFormatException nfe)
            {  price = 0;
            }
            if (artist.equals("") || title.equals("") ||
                price <= 0)
            {  JOptionPane.showMessageDialog(null,
                  "The artist and title cannot be blank and the price must " +
                  "be greater than zero.", "Incorrect changes to data",
                  JOptionPane.ERROR_MESSAGE);
            }
            else
            {  currentCD.setArtist(artist);
               currentCD.setTitle(title);
               currentCD.setPrice(price);
               setGUIForCDViewing();
               fullBtnLstnr.actionPerformed(new ActionEvent(
                  fullBtn, ActionEvent.ACTION_PERFORMED, FULL));
            }
         }
      });     

      deleteBtn.addActionListener(new ActionListener()
      {  public void actionPerformed(ActionEvent ae)
         {  int confirm = JOptionPane.showConfirmDialog(null,
               "This will permanently delete this CD. Are you sure?",
               "Confirm or cancel deletion",
               JOptionPane.YES_NO_OPTION);
            if (confirm == JOptionPane.YES_OPTION)
            {  cdCollection.remove(currentCD);
               setGUIForNoCDSelected();
               fullBtnLstnr.actionPerformed(new ActionEvent(
                  fullBtn, ActionEvent.ACTION_PERFORMED, FULL));
            }
         }
      }); 

      deleteTrackBtn.addActionListener(new ActionListener()
      {  public void actionPerformed(ActionEvent ae)
         {  int index = tracksList.getSelectedIndex();
            if (index == -1)
            {  JOptionPane.showMessageDialog(null,
                  "Select a track from the list above before clicking " +
                  "on the Delete Track button.",
                  "No track selected",
                  JOptionPane.ERROR_MESSAGE);
            }
            else
            {  int confirm = JOptionPane.showConfirmDialog(null,
               "This will permanently delete this track. Are you sure?",
               "Confirm or cancel deletion",
               JOptionPane.YES_NO_OPTION);
               if (confirm == JOptionPane.YES_OPTION)
               {  currentCD.getTracks().removeElementAt(index);
                  setGUIForCDViewing();
               }
            }
         }
      });

      saveTrackBtn.addActionListener(new ActionListener()
      {  public void actionPerformed(ActionEvent ae)
         {  String newTrack = newTrackTF.getText().trim();
            if (newTrack.equals(""))
            {  JOptionPane.showMessageDialog(null,
                  "Type a non-blank track name before clicking " +
                  "on the Save Track button.",
                  "No track entered",
                  JOptionPane.ERROR_MESSAGE);
            }
            else
            {  currentCD.addTrack(newTrack);
               setGUIForCDViewing();
            }
         }
      });

      JPanel p = new JPanel();
      GridBagLayout gbl = new GridBagLayout();
      GridBagConstraints gbc = new GridBagConstraints();
      p.setLayout(gbl);
      gbc.insets = new Insets(5, 5, 5, 0); 
      gbc.fill = GridBagConstraints.HORIZONTAL; 
      gbc.anchor = GridBagConstraints.WEST;
      GuiUtility.addComp(idNumLbl, p, gbl, gbc, 0, 0, 1, 1, 0, 0);
      GuiUtility.addComp(Box.createHorizontalStrut(10), p, gbl, gbc, 
         0, 1, 1, 1, 0, 0);
      GuiUtility.addComp(idNumTF, p, gbl, gbc, 
         0, 2, 1, GridBagConstraints.REMAINDER, 0, 0);
      GuiUtility.addComp(artistLbl, p, gbl, gbc, 1, 0, 1, 1, 0, 0);
      GuiUtility.addComp(Box.createHorizontalStrut(10), p, gbl, gbc, 
         1, 1, 1, 1, 0, 0);
      GuiUtility.addComp(artistTF, p, gbl, gbc, 
         1, 2, 1, GridBagConstraints.REMAINDER, 0, 0);
      GuiUtility.addComp(titleLbl, p, gbl, gbc, 2, 0, 1, 1, 0, 0);
      GuiUtility.addComp(Box.createHorizontalStrut(10), p, gbl, gbc, 
         2, 1, 1, 1, 0, 0);
      GuiUtility.addComp(titleTF, p, gbl, gbc, 
         2, 2, 1, GridBagConstraints.REMAINDER, 0, 0);
      GuiUtility.addComp(priceLbl, p, gbl, gbc, 3, 0, 1, 1, 0, 0);
      GuiUtility.addComp(Box.createHorizontalStrut(10), p, gbl, gbc, 
         3, 1, 1, 1, 0, 0);
      GuiUtility.addComp(priceTF, p, gbl, gbc, 
         3, 2, 1, GridBagConstraints.REMAINDER, 0, 0);
      gbc.fill = GridBagConstraints.NONE;
      gbc.anchor = GridBagConstraints.CENTER;
      JPanel btnPnl1 = new JPanel();
      btnPnl1.setLayout(new BoxLayout(btnPnl1, BoxLayout.X_AXIS));
      btnPnl1.add(newBtn);
      btnPnl1.add(insertBtn);
      btnPnl1.add(cancelBtn);
      JPanel btnPnl2 = new JPanel();
      btnPnl2.setLayout(new BoxLayout(btnPnl2, BoxLayout.X_AXIS));
      btnPnl2.add(modifyBtn);
      btnPnl2.add(deleteBtn);
      GuiUtility.addComp(btnPnl1, p, gbl, gbc, 4, 0,
         1, GridBagConstraints.REMAINDER, 0, 0);
      GuiUtility.addComp(btnPnl2, p, gbl, gbc, 5, 0,
         1, GridBagConstraints.REMAINDER, 0, 0);
      gbc.fill = GridBagConstraints.HORIZONTAL;
      gbc.anchor = GridBagConstraints.NORTHWEST;
      GuiUtility.addComp(tracksLbl, p, gbl, gbc, 6, 0, 1, 1, 0, 0);
      GuiUtility.addComp(Box.createHorizontalStrut(10), p, gbl, gbc, 
         6, 1, 1, 1, 0, 0);
      GuiUtility.addComp(scrollPane, p, gbl, gbc, 
         6, 2, 1, GridBagConstraints.REMAINDER, 0, 0);
      gbc.fill = GridBagConstraints.NONE;
      gbc.anchor = GridBagConstraints.CENTER;
      JPanel btnPnl3 = new JPanel();
      btnPnl3.setLayout(new BoxLayout(btnPnl3, BoxLayout.X_AXIS));
      btnPnl3.add(deleteTrackBtn);
      GuiUtility.addComp(btnPnl3, p, gbl, gbc, 7, 0,
         1, GridBagConstraints.REMAINDER, 0, 0);
      JPanel btnPnl4 = new JPanel();
      GridBagLayout gblP = new GridBagLayout();
      GridBagConstraints gbcP = new GridBagConstraints();
      gbcP.fill = GridBagConstraints.NONE;
      gbcP.anchor = GridBagConstraints.WEST;
      GuiUtility.addComp(newTrackTF, btnPnl4, gblP, gbcP,
         0, 0, 1, 1, 0, 0);
      GuiUtility.addComp(Box.createHorizontalStrut(10), btnPnl4, gblP, gbcP, 
         0, 1, 1, 1, 0, 0);
      GuiUtility.addComp(saveTrackBtn, btnPnl4, gblP, gbcP, 
         0, 2, 1, GridBagConstraints.REMAINDER, 0, 0);
      GuiUtility.addComp(btnPnl4, p, gbl, gbc, 8, 0,
         1, GridBagConstraints.REMAINDER, 0, 0);
      return p;
   }

   /**
    * Creates the button that takes the user back to the parent
    * component, i.e. the frame from which s/he came before viewing
    * this frame.
    */
   private JPanel createReturnPanel()
   {  returnBtn = new JButton(ICDGUI.RETURN);
      returnBtn.addActionListener(new ActionListener()
      {  public void actionPerformed(ActionEvent ae)
         {  setVisible(false);
            parentComp.enableGUI();
            parentComp.setResult(currentCD);
            dispose();
         }
      });
      JPanel p = new JPanel();
      p.add(returnBtn);
      return p;
   }

   /**
    * Disables/enables parts of the GUI for when the user has no
    * CD selected.
    */
   private void setGUIForNoCDSelected()
   {  newBtn.setEnabled(true);
      insertBtn.setEnabled(false);
      cancelBtn.setEnabled(false);
      modifyBtn.setEnabled(false);
      deleteBtn.setEnabled(false);
      cdList.setEnabled(true);
      currentCD = null;
      displayCurrentCD();
      artistTF.setEnabled(false);
      titleTF.setEnabled(false);
      priceTF.setEnabled(false);
      tracksList.setEnabled(false);
      deleteTrackBtn.setEnabled(false);
      newTrackTF.setText("");
      newTrackTF.setEnabled(false);
      saveTrackBtn.setEnabled(false);
   }

   /**
    * Disables/enables parts of the GUI for when the user is viewing
    * a CD.
    */
   private void setGUIForCDViewing()
   {  newBtn.setEnabled(true);
      insertBtn.setEnabled(false);
      cancelBtn.setEnabled(false);
      modifyBtn.setEnabled(true);
      deleteBtn.setEnabled(true);
      cdList.setEnabled(true);
      displayCurrentCD();
      artistTF.setEnabled(true);
      titleTF.setEnabled(true);
      priceTF.setEnabled(true);
      tracksList.setEnabled(true);
      deleteTrackBtn.setEnabled(true);
      newTrackTF.setText("");
      newTrackTF.setEnabled(true);
      saveTrackBtn.setEnabled(true);
   }

   /**
    * Disables/enables parts of the GUI for when the user is entering
    * a new CD.
    */
   private void setGUIForCDEntry()
   {  newBtn.setEnabled(false);
      insertBtn.setEnabled(true);
      cancelBtn.setEnabled(true);
      modifyBtn.setEnabled(false);
      deleteBtn.setEnabled(false);
      cdList.setEnabled(false);
      currentCD = null;
      displayCurrentCD();
      artistTF.setEnabled(true);
      titleTF.setEnabled(true);
      priceTF.setEnabled(true);
      tracksList.setEnabled(false);
      deleteTrackBtn.setEnabled(false);
      newTrackTF.setText("");
      newTrackTF.setEnabled(false);
      saveTrackBtn.setEnabled(false);
   }

/* =======================================================================
       INSTANCE VARIABLES & CLASS VARIABLES
   =======================================================================
*/
   private ICDGUI parentComp;
   private CDCollection cdCollection;

   private CD currentCD;
   private Vector viewedCDs;

   private JList cdList;
   private JTextField searchIdNumTF;
   private JTextField searchArtistTF;
   private JTextField searchTitleTF;
   private JButton searchBtn;
   private JButton fullBtn;
   private ActionListener fullBtnLstnr;

   private JTextField idNumTF;
   private JTextField artistTF;
   private JTextField titleTF;
   private JTextField priceTF;
   private JButton newBtn;
   private JButton insertBtn;
   private JButton cancelBtn;
   private JButton modifyBtn;
   private JButton deleteBtn;
   private JList tracksList;
   private JButton deleteTrackBtn;
   private JTextField newTrackTF;
   private JButton saveTrackBtn;

   private JButton returnBtn;

   private static final int ID_TF_COLS = 6;
   private static final int ARTIST_TF_COLS = 30;
   private static final int TITLE_TF_COLS = 30;
   private static final int PRICE_TF_COLS = 6;
   private static final int TRACK_TF_COLS = 30;

   private static final String SEARCH = "SEARCH";
   private static final String FULL = "See Full List";
   private static final String NEW = "NEW CD";
   private static final String INSERT = "INSERT";
   private static final String CANCEL = "CANCEL";
   private static final String MODIFY = "Save Changes";
   private static final String DELETE = "DELETE";
   private static final String DELETE_TRACK = "Delete Track";
   private static final String SAVE_TRACK = "Save New Track";
}
