package org.wikiwebserver.distribute.se.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.net.URI;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import org.wikiwebserver.distribute.interfaces.ConfigChangeListener;
import org.wikiwebserver.distribute.se.ConfigManager;
import org.wikiwebserver.distribute.se.ResourceManager;
import org.wikiwebserver.distribute.se.worker.ServerCommunicator;

public abstract class JConfigPanel extends JPanel implements ConfigChangeListener {
    
    private static final long serialVersionUID = 1L;    
	
	private static JFileChooser fileChooser;
	
	private JPanel configPanel;
	private JButton updateButton;
	private Image backgroundImage;
	
    
    public abstract void updateConfigDisplay();	
	
	public JPanel getConfigPanel() {
		return this.configPanel;
	}

	public void setConfigPanel(JPanel configPanel) {
		this.configPanel = configPanel;
	}

	public JConfigPanel() {
		setOpaque(false);

		configPanel = new JPanel();	
		BoxLayout layout = new BoxLayout(configPanel, BoxLayout.Y_AXIS);
		configPanel.add(Box.createHorizontalGlue());
		configPanel.setLayout(layout);
		configPanel.setOpaque(this.isOpaque());
        
        JPanel upperConfigPanel = new JPanel(new BorderLayout());
        upperConfigPanel.setOpaque(this.isOpaque());
        upperConfigPanel.add(configPanel, BorderLayout.NORTH);

        updateButton = new JButton("Apply");
        updateButton.setEnabled(false);
        
        JPanel updateButtonPanel = new JPanel(new BorderLayout());
        updateButtonPanel.setBorder(new EmptyBorder(3, 2, 3, 5));
        updateButtonPanel.setOpaque(this.isOpaque());
        updateButtonPanel.add(updateButton, BorderLayout.SOUTH);    
        
        JPanel lowerButtonPanel = new JPanel(new BorderLayout());
        lowerButtonPanel.setOpaque(this.isOpaque());
        lowerButtonPanel.add(updateButtonPanel, BorderLayout.EAST);   
        
        backgroundImage = ResourceManager.getImage("icons/backgroundLogo.png");
        
		setLayout(new BorderLayout());
		add(upperConfigPanel, BorderLayout.CENTER);
		add(lowerButtonPanel, BorderLayout.SOUTH);
		
		updateConfigDisplay();
		ConfigManager.addConfigChangeListener(this);
	}
	
	public void addLinkOption(String linkName, String linkDetail, final String link) {
		
		JPanel innerFieldPanel = new JPanel(new BorderLayout());
		innerFieldPanel.setBorder(new TitledBorder(linkName));
		innerFieldPanel.setOpaque(this.isOpaque());
		
		JTextPane help = new JTextPane();
        help.setOpaque(this.isOpaque());        
        help.setText(linkDetail);
        help.setEditable(false);

        JPanel helpPanel = new JPanel(new BorderLayout());
        helpPanel.setOpaque(this.isOpaque());  
        helpPanel.add(help, BorderLayout.CENTER);
        innerFieldPanel.add(helpPanel, BorderLayout.NORTH);		
		
		JLabel linkLabel = new JLabel("<html><u>" + link + "</u></html>");
		linkLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
		linkLabel.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent arg0) {
				try {
					URI uri = new URI(link);
					Desktop.getDesktop().browse(uri);
				} catch (Exception ex) {
					ex.printStackTrace();
				}
			}
			public void mouseEntered(MouseEvent arg0) {}
			public void mouseExited(MouseEvent arg0) {}
			public void mousePressed(MouseEvent arg0) {}
			public void mouseReleased(MouseEvent arg0) {}
			
		});
		
		JPanel linkLabelPanel = new JPanel();
		linkLabelPanel.setOpaque(this.isOpaque());
		linkLabelPanel.setBorder(new EmptyBorder(1, 0, 1, 0));
		linkLabelPanel.add(linkLabel);
		
		innerFieldPanel.add(linkLabelPanel, BorderLayout.WEST); 
		
        String copyText = ResourceManager.getString("copyButtonText");		
		JButton copyButton = new JButton(copyText);
        
		copyButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                StringSelection stringSelection = new StringSelection(link);
                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                clipboard.setContents( stringSelection, null );
            }
            
        });	
		
		innerFieldPanel.add(copyButton, BorderLayout.EAST);    		
		
		JPanel linkPanel = new JPanel(new BorderLayout());
		linkPanel.setOpaque(this.isOpaque());
		linkPanel.add(innerFieldPanel, BorderLayout.CENTER);
		linkPanel.setBorder(new EmptyBorder(2, 3, 3, 3));    		
		
		getConfigPanel().add(linkPanel);
	}	
	
	public void addConfigOption(String property, boolean editable, boolean optional, SimpleValidator validator) {
		getConfigPanel().add(createOptionPanel(property, editable, false, optional, validator));
	}
	
	public void addConfigFileOption(String property, boolean editable, SimpleValidator validator) {
		getConfigPanel().add(createOptionPanel(property, editable, true, false, validator));
	}	
	
	private JPanel createOptionPanel(final String property, boolean isEdiable, boolean isFile, 
	                                 final boolean isOptional, final SimpleValidator validator) {
		
        final String propertyValue = ConfigManager.getString(property);	    
	    String propertyTitle = ResourceManager.getString(property + "Title");
        String propertyDetail = ResourceManager.getString(property + "Detail");
		
		JPanel innerFieldPanel = new JPanel(new BorderLayout());
		innerFieldPanel.setBorder(new TitledBorder(propertyTitle));
		innerFieldPanel.setOpaque(this.isOpaque());
		
		JTextPane help = new JTextPane();
        help.setOpaque(this.isOpaque());		
		help.setText(propertyDetail);
		help.setEditable(false);
		
		final JCheckBox checkbox = new JCheckBox(propertyDetail);
		checkbox.setOpaque(this.isOpaque());
		checkbox.setSelected(propertyValue != null && propertyValue.length() > 0);

		JPanel helpPanel = new JPanel(new BorderLayout());
		helpPanel.setOpaque(this.isOpaque());  
		if (isOptional) {
		    helpPanel.add(checkbox, BorderLayout.CENTER);
		} else {
		    helpPanel.add(help, BorderLayout.CENTER);
		}
		innerFieldPanel.add(helpPanel, BorderLayout.NORTH);
		
		
		JTextField field = null;
		if (property.toLowerCase().contains("password")) {
		    field = new JPasswordField(propertyValue);
		}
		else {
		    field = new JTextField(propertyValue);
		}
		field.setCaretPosition(0);
		field.setEditable(!isOptional || isEdiable && checkbox.isSelected());
		
		
		if (isEdiable) {
		    final JTextField changeableField = field; 
		    changeableField.addCaretListener(new CaretListener() {
				public void caretUpdate(CaretEvent arg0) {
				    if (!isOptional || checkbox.isSelected()) {
                        if (validator.validate(changeableField.getText()) != null) {
                            changeableField.setForeground(Color.red);
                        } 
                        else changeableField.setForeground(Color.black);
    			    
    					if (hasChanged(changeableField.getText(), propertyValue)) {
    						updateButton.setEnabled(true);
    					}
				    }
				}
			});
			
	        
	        checkbox.addActionListener(new ActionListener() {
	            public void actionPerformed(ActionEvent arg0) {
	                changeableField.setEditable(checkbox.isSelected());
	                if (!checkbox.isSelected()) {
	                    changeableField.setText(null);  
	                    changeableField.setBackground(null);
	                    ConfigManager.setString(property, null);
	                }
                    updateButton.setEnabled(true);      	                
	            }
	        });   
	        
	        updateButton.addActionListener(new ActionListener() {
	            public void actionPerformed(ActionEvent arg0) {
	                if (!isOptional || checkbox.isSelected()) {
    	                String text = changeableField.getText();
    	                String error = validator.validate(text);
    	                    
    	                if (error != null) {
    	                    String title = ResourceManager.getString("badConfigurationValue");
    	                    changeableField.setBackground(new Color(255, 200, 200));
    	                    JOptionPane.showMessageDialog(changeableField, error, title, JOptionPane.ERROR_MESSAGE);
    	                }
    	                else {
    	                    changeableField.setBackground(Color.white);             
    	                    ConfigManager.setString(property, text);
    	                    updateButton.setEnabled(false);     
    	                    ServerCommunicator.checkNow();
    	                }
	                }
	            }
	        });	        
		}

		
		// Initial validation 
		if (!isOptional || checkbox.isSelected()) { 
            if (validator.validate(field.getText()) != null) {
                field.setBackground(new Color(255, 200, 200));		
            }
		}

		innerFieldPanel.add(field, BorderLayout.CENTER);
		
		// Ability to add a file browse button
		if (isFile) {
		    String browseText = ResourceManager.getString("browseButtonText");        
			JButton browseButton = new JButton(browseText);
			
			browseButton.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					if (fileChooser == null) {
						fileChooser = new JFileChooser();
						fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
					}
					
					int returnVal = fileChooser.showOpenDialog(null);

			        if (returnVal == JFileChooser.APPROVE_OPTION) {
			            File file = fileChooser.getSelectedFile();
			            ConfigManager.setString(property, file.getPath());
			            updateButton.setEnabled(true);
			        }
				}
				
			});
			
			JPanel browseButtonPanel = new JPanel(new BorderLayout());
			browseButtonPanel.setOpaque(this.isOpaque());
			browseButtonPanel.add(browseButton, BorderLayout.EAST);
			innerFieldPanel.add(browseButtonPanel, BorderLayout.EAST);			
		}		
		
		JPanel optionPanel = new JPanel(new BorderLayout());
		optionPanel.setOpaque(this.isOpaque());
		optionPanel.setBorder(new EmptyBorder(2, 3, 3, 3));		
		optionPanel.add(innerFieldPanel, BorderLayout.CENTER);
		

		
		return optionPanel;
	}

	public void configChanged() {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				
				configPanel.removeAll();
				
				ActionListener[] oldListeners = updateButton.getActionListeners();
				for (ActionListener l : oldListeners) {
					updateButton.removeActionListener(l);
				}
				
				updateConfigDisplay();
			}
		});
	}
	
	private static boolean hasChanged(Object obj1, Object obj2) {
		if (obj1 == null && obj2 != null) return true;
		if (obj1 != null && obj2 == null) return true;
		return !obj1.equals(obj2);
	}	
	
	@Override
	public void paintComponent(Graphics gfx) {
	    int x = 10;
	    int y = getHeight() - backgroundImage.getHeight(this) - 10;
	    gfx.drawImage(backgroundImage, x, y, this);
	    super.paintComponent(gfx);
	}
}

