/**
 * The contents of this file are subject to the license and copyright
 * detailed in the LICENSE and NOTICE files at the root of the source
 * tree and available online at
 *
 * http://www.dspace.org/license/
 */
/**
 * Copyright (c) 2007, Aberystwyth University
 *
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions 
 * are met:
 * 
 *  - Redistributions of source code must retain the above 
 *    copyright notice, this list of conditions and the 
 *    following disclaimer.
 *  
 *  - Redistributions in binary form must reproduce the above copyright 
 *    notice, this list of conditions and the following disclaimer in 
 *    the documentation and/or other materials provided with the 
 *    distribution.
 *    
 *  - Neither the name of the Centre for Advanced Software and 
 *    Intelligent Systems (CASIS) nor the names of its 
 *    contributors may be used to endorse or promote products derived 
 *    from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 * SUCH DAMAGE.
 */
package org.purl.sword.client;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * Dialog for users to enter details of post destinations. 
 * 
 * @author Neil Taylor
 */
public class PostDialog 
implements ActionListener, ChangeListener
{
   /**
    * label for the browse command. 
    */
   protected static final String BROWSE = "browse"; 
   
   /**
    * label for the add command. 
    */
   protected static final String ADD = "add";
   
   /**
    * label for the edit command. 
    */
   protected static final String EDIT = "edit";
   
   /**
    * label for the delete command. 
    */
   protected static final String DELETE = "delete";
   
   /**
    * label for the clear command. 
    */
   protected static final String CLEAR = "clear";
   
   /**
    * Username combo box. 
    */
   private SWORDComboBox username;
   
   /**
    * Post Location combo box. 
    */
   private SWORDComboBox postLocation;
   
   /**
    * Password field. 
    */
   private JPasswordField password;
   
   /**
    * The file combo box. 
    */
   private SWORDComboBox file;
   
   /**
    * The filetype combo box. 
    */
   private SWORDComboBox fileType;
   
   /**
    * The onBehalfOf combo box. 
    */
   private SWORDComboBox onBehalfOf;
   
   /**
    * The md5 checkbox. 
    */
   private JCheckBox useMD5;
   
   /**
    * The corruptMD5 checkbox.
    */
   private JCheckBox corruptMD5;

   /**
    * The corruptRequest checkbox.
    */
   private JCheckBox corruptRequest;

   /**
    * The useNoOp checkbox. 
    */
   private JCheckBox useNoOp;
   
   /**
    * The verbose checkbox. 
    */
   private JCheckBox useVerbose;
   
   /**
    * The format namespace combo box. 
    */
   private SWORDComboBox formatNamespace;

   /**
    * The list of post destinations. 
    */
   private JList list;
   
   /**
    * The parent frame for the dialog that is displayed.
    */
   private JFrame parentFrame = null; 
   
   /**
    * Array that lists the labels for the buttons on the panel.
    */
   private static Object[] options = {"Post File", "Cancel" };
   
   /**
    * The panel that holds the controls to show. 
    */
   private JPanel controls = null; 

   /**
    * 
    * @param parentFrame
    */
   public PostDialog(JFrame parentFrame)
   {
      this.parentFrame = parentFrame; 
      controls = createControls();
   }
   
   /**
    * Show the dialog with ok and cancel options. 
    * @return The return value from displaying JOptionPane. Either 
    *         JOptionPane.OK_OPTION or JOptionPane.CANCEL_OPTION.
    */
   public int show( )
   {
     int result =  JOptionPane.showOptionDialog(parentFrame,
        controls,
        "Post Document",
        JOptionPane.OK_CANCEL_OPTION,
        JOptionPane.PLAIN_MESSAGE,
        null,
        options,
        null);
     
     if( result == JOptionPane.OK_OPTION )
     {
        // update the combo boxes with the values 
        username.updateList();
        file.updateList();
        fileType.updateList();
        onBehalfOf.updateList();
        formatNamespace.updateList();
     }
     
     return result; 
   }
   
   /**
    * Create the controls for the main panel. 
    * 
    * @return The panel. 
    */
   protected final JPanel createControls( )
   {
	   file = new SWORDComboBox();
      JPanel filePanel = new JPanel(new BorderLayout());
      filePanel.add(file, BorderLayout.CENTER);
      JButton browse = new JButton("Browse...");
      browse.setActionCommand(BROWSE);
      browse.addActionListener(this);
      
      filePanel.add(browse, BorderLayout.SOUTH);
      
      fileType = new SWORDComboBox();
      String type = "application/zip";
      fileType.addItem(type);
      fileType.setSelectedItem(type);
      
      // controls that will be used in the second dialog
      postLocation = new SWORDComboBox();
      username = new SWORDComboBox();
      password = new JPasswordField();
      onBehalfOf = new SWORDComboBox();
      
      
      useMD5 = new JCheckBox();
      useMD5.addChangeListener(this);
      corruptMD5 = new JCheckBox();
      corruptRequest = new JCheckBox();
      useNoOp = new JCheckBox();
      useVerbose = new JCheckBox();
      formatNamespace = new SWORDComboBox();
      
      JLabel fileLabel = new JLabel("File:", JLabel.TRAILING);
      JLabel fileTypeLabel = new JLabel("File Type:", JLabel.TRAILING);
      JLabel useMD5Label = new JLabel("Use MD5:", JLabel.TRAILING);
      JLabel corruptMD5Label = new JLabel("Corrupt MD5:", JLabel.TRAILING);
      JLabel corruptRequestLabel = new JLabel("Corrupt Request:", JLabel.TRAILING);
      //JLabel corruptMD5Label = new JLabel("Corrupt MD5:", JLabel.TRAILING);
      JLabel useNoOpLabel = new JLabel("Use noOp:", JLabel.TRAILING);
      JLabel useVerboseLabel = new JLabel("Use verbose:", JLabel.TRAILING);
      JLabel formatNamespaceLabel = new JLabel("X-Packaging:", JLabel.TRAILING);
      JLabel userAgentLabel = new JLabel("User Agent:", JLabel.TRAILING);
      JLabel userAgentNameLabel = new JLabel(ClientConstants.SERVICE_NAME, JLabel.LEADING);
      
      SWORDFormPanel panel = new SWORDFormPanel(); 
      panel.addFirstRow(new JLabel("Please enter the details for the post operation"));
      
      JPanel destinations = createDestinationsPanel();
      
      panel.addRow(new JLabel("Destinations:"), destinations);
      panel.addRow(fileLabel, filePanel);
      panel.addRow(fileTypeLabel, fileType);
      panel.addRow(useMD5Label, useMD5);
      panel.addRow(corruptMD5Label, corruptMD5);
      panel.addRow(corruptRequestLabel, corruptRequest);
      panel.addRow(useNoOpLabel, useNoOp);
      panel.addRow(useVerboseLabel, useVerbose);
      panel.addRow(formatNamespaceLabel, formatNamespace);
      panel.addRow(userAgentLabel, userAgentNameLabel);
      
      return panel; 
   }

   /**
    * Create the destinations panel. This contains a list and four buttons
    * to operate on values in the list. 
    *  
    * @return The panel containing the controls. 
    */
   protected JPanel createDestinationsPanel()
   {
      DefaultListModel model = new DefaultListModel();
      list = new JList(model);
      JScrollPane jsp = new JScrollPane(list);
      
      JPanel destinations = new JPanel(new BorderLayout());
      destinations.add(jsp, BorderLayout.CENTER);
      JPanel destinationButtons = new JPanel();
      
      JButton addButton = new JButton("Add");
      addButton.setActionCommand(ADD);
      addButton.addActionListener(this);
      
      JButton editButton = new JButton("Edit");
      editButton.setActionCommand(EDIT);
      editButton.addActionListener(this);
      
      JButton deleteButton = new JButton("Delete");
      deleteButton.setActionCommand(DELETE);
      deleteButton.addActionListener(this);
      
      JButton clearButton = new JButton("Clear");
      clearButton.setActionCommand(CLEAR);
      clearButton.addActionListener(this);
      
      destinationButtons.add(addButton);
      destinationButtons.add(editButton);
      destinationButtons.add(deleteButton);
      destinationButtons.add(clearButton);
      
      destinations.add(destinationButtons, BorderLayout.SOUTH);
      
      return destinations; 
   }
   
   /**
    * Handle the button click to select a file to upload. 
    */
   public void actionPerformed(ActionEvent evt) 
   {
      String cmd = evt.getActionCommand();
      
      if( BROWSE.equals(cmd) )
      {
         JFileChooser chooser = new JFileChooser();
         chooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
         int returnVal = chooser.showOpenDialog(parentFrame);
         if(returnVal == JFileChooser.APPROVE_OPTION) {
            file.setSelectedItem(chooser.getSelectedFile().getAbsolutePath());
         }
      }
      else if( ADD.equals(cmd))
      {
         PostDestination dest = showDestinationDialog(null);
         if( dest != null ) 
         {
              ((DefaultListModel)list.getModel()).addElement(dest);
         }
      }
      else if( EDIT.equals(cmd))
      {
         PostDestination dest = (PostDestination)list.getSelectedValue(); 
         if( dest != null ) 
         {
            showDestinationDialog(dest);
            list.repaint();
         }
      }
      else if( DELETE.equals(cmd))
      {
         if( list.getSelectedIndex() != -1 )
         {
            ((DefaultListModel)list.getModel()).removeElementAt(list.getSelectedIndex());
         }
      }
      else if( CLEAR.equals(cmd))
      {
    	  ((DefaultListModel)list.getModel()).clear();
      }
   }
   
   /**
    * Show the destination dialog. This is used to enter the URL, 
    * username, password and onBehalfOf name for a destination. 
    * 
    * @param destination The post destination. If this is not null, the values
    *                    in the object are used to set the current values 
    *                    in the dialog controls.  
    * @return The post destination value. 
    */
   public PostDestination showDestinationDialog( PostDestination destination )
   {
      SWORDFormPanel panel = new SWORDFormPanel(); 
      panel.addFirstRow(new JLabel("Please enter the details for the post operation"));

      JLabel postLabel = new JLabel("Post Location:", JLabel.TRAILING);
      JLabel userLabel = new JLabel("Username:", JLabel.TRAILING);
      JLabel passwordLabel = new JLabel("Password:", JLabel.TRAILING);
      JLabel onBehalfOfLabel = new JLabel("On Behalf Of:", JLabel.TRAILING);

      panel.addRow(postLabel, postLocation);
      panel.addRow(userLabel, username);
      panel.addRow(passwordLabel, password);
      panel.addRow(onBehalfOfLabel, onBehalfOf);

      if( destination != null )
      {
         postLocation.insertItem(destination.getUrl());
         username.insertItem(destination.getUsername());
         password.setText(destination.getPassword());
         onBehalfOf.insertItem(destination.getOnBehalfOf());
      }
      else
      {
         String s = "";
         postLocation.insertItem(s);
         //postLocation.setSelectedItem(s);
         username.insertItem(s);
         username.setSelectedItem(s);
         password.setText(s);
         onBehalfOf.insertItem(s);
         onBehalfOf.setSelectedItem(s);
      }

      int result =  JOptionPane.showOptionDialog(null,
            panel,
            "Destination",
            JOptionPane.OK_CANCEL_OPTION,
            JOptionPane.PLAIN_MESSAGE,
            null,
            new String[] { "OK", "Cancel" },
            null);

      if( result == JOptionPane.OK_OPTION )
      {
         postLocation.updateList();
         username.updateList();
         onBehalfOf.updateList();
         
         if( destination == null ) 
         {
            destination = new PostDestination();   
         }
         
         destination.setUrl(postLocation.getText());
         destination.setUsername(username.getText());
         String pass = new String(password.getPassword());
         if( pass.length() > 0 )
         {
            destination.setPassword(pass);
         }
         else
         {
        	destination.setPassword(null);
         }
         
         String obo = onBehalfOf.getText();
         if( obo.length() > 0 ) 
         {
        	 destination.setOnBehalfOf(onBehalfOf.getText());
         }
         else
         {
        	 destination.setOnBehalfOf(null);
         }
         
      }

      return destination; 
   }
   
   /**
    * Get the list of Post Destinations.  
    * @return The destinations. 
    */
   public PostDestination[] getDestinations()
   {
      DefaultListModel model = (DefaultListModel)list.getModel();
      PostDestination[] destinations = new PostDestination[model.size()];
      for( int i = 0; i < model.size(); i++)
      {
         destinations[i] = (PostDestination)model.get(i);
      }
      return destinations;
   }
   
   /**
    * Get the file details.  
    * @return The value. 
    */
   public String getFile( ) 
   {
	   return file.getText();
   }
   
   /**
    * Get the filetype value. 
    * @return The value. 
    */
   public String getFileType() 
   {
	   return fileType.getText();
   }
   
   /**
    * Get the onBehalfOf value. 
    * @return The value. 
    */
   public String getOnBehalfOf()
   {
	   return onBehalfOf.getText();
   }
   
   /**
    * Get the format namespace value. 
    * @return The value. 
    */
   public String getFormatNamespace()
   {
	   return formatNamespace.getText();
   }
   
   /**
    * Determine if the MD5 checkbox is selected. 
    * 
    * @return True if the MD5 checkbox is selected. 
    */
   public boolean useMd5()
   {
	   return useMD5.isSelected();
   }
   
   /**
    * Determine if the noOp checkbox is selected. 
    * 
    * @return True if the checkbox is selected. 
    */
   public boolean useNoOp()
   {
	   return useNoOp.isSelected();
   }
   
   /**
    * Determine if the verbose checkbox is selected.
    *  
    * @return True if the checkbox is selected. 
    */
   public boolean useVerbose()
   {
	   return useVerbose.isSelected();
   }

   /**
    * Get the post location. 
    * @return The post location. 
    */
   public String getPostLocation()
   {
	   return postLocation.getText();
   }
   
   /**
    * Determine if the MD5 hash should be corrupted.
    * @return True if the corrupt MD5 checkbox is selected. The MD5 checkbox
    * must also be selected.
    */
   public boolean corruptMD5()
   {
	   return (corruptMD5.isEnabled() && corruptMD5.isSelected());
   }

   /**
    * Determine if the POST request should be corrupted.
    * @return True if the corrupt request checkbox is selected.
    */
   public boolean corruptRequest()
   {
	   return (corruptRequest.isSelected());
   }

   /**
    * Detect a state change event for the checkbox. 
    * 
    * @param evt The event. 
    */
   public void stateChanged(ChangeEvent evt) 
   {
      corruptMD5.setEnabled(useMD5.isSelected());  
   }
   
   /**
    * Add a list of user ids. 
    * 
    * @param users The user ids. 
    */
   public void addUserIds(String[] users)
   {
	   username.insertItems(users);
   }
   
   /**
    * Add a list of deposit URLs.
    *  
    * @param deposits The URLs. 
    */
   public void addDepositUrls(String[] deposits)
   {
	   postLocation.insertItems(deposits);
   }
   
   /**
    * Add a list of onBehalfOf names. 
    * 
    * @param users The names. 
    */
   public void addOnBehalfOf(String[] users)
   {
	   onBehalfOf.insertItems(users);
   }
   
   /**
    * Add the list of formatNamespace strings. 
    * 
    * @param namespaces list of strings. 
    */
   public void addFormatNamespaces(String[] namespaces)
   {
	   formatNamespace.insertItems(namespaces);
   }
   
   /**
    * Add a list of file types. 
    * 
    * @param types The file types. 
    */
   public void addFileTypes(String[] types)
   {
	   fileType.insertItems(types);
   }
   
   /**
    * Add a list of file names. 
    * @param files The list of files. 
    */
   public void addFiles(String[] files)
   {
	   file.insertItems(files);
   }
   
   /**
    * Set the deposit location. 
    * 
    * @param location The location. 
    */
   public void setDepositLocation(String location)
   {
	   postLocation.insertItem(location);
      postLocation.setSelectedItem(location);
   }
}
