/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
package lu.tudor.santec.gecamed.patient.gui;


import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.i18n.Translatrix;
import lu.tudor.santec.settings.SettingsPlugin;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;

import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;


/**
 * <p>This class implements the Settings dialog for the configuration of the
 * Patient sub-Modules. You can enable / disable the different Modules here. It
 * implements the lu.tudor.santec.settings.SettingsPlugin Interface and is used
 * inside the framework with the SettingPanel.</p>
 * <p>All methods are implemented that are necessary to support all functions of
 * the SettingsPlugin.</p>
 * @author Andreas Jahnen
 */
public class PatientModulesPlugin extends SettingsPlugin implements ActionListener, ListSelectionListener {
    
    public static final String ENABLED_ELEMENTS = "EnabledPatientModules";
    public static final String DISABLED_ELEMENTS = "DisabledPatientModules";
    private static final String NAME = "PatientModulesPlugin";
    private static final URL CONFIG_FILE = PatientModulesPlugin.class.getResource("PatientModulesPlugin.properties");
	
	private static final long serialVersionUID = 1L;
	private JPanel          m_ModulePanel;
    private JLabel          m_CommentLabel;
    private JLabel          m_ModulesLabel;
    private JList           m_ModulesList;
    private JButton         m_EnableButton;
    private JButton         m_DisableButton;
    private JButton         m_UpButton;
    private JButton         m_DownButton;
    
    private Vector<ModuleElement> m_modules = new Vector<ModuleElement>();
	private String enabledModules = "";
	private String disabledModules = "";
    private static Logger logger = Logger.getLogger ("lu.tudor.santec.gecamed.patient.gui.PatientModulesPlugin");

    /**
     * This Methode creates a new object of the ModuleManagerPlugin.
     */
    public PatientModulesPlugin() {
        super(NAME);
        FormLayout              l_Layout;
        PanelBuilder            l_Builder;
        CellConstraints         l_Constraints;
        
        Translatrix.addBundle("lu.tudor.santec.gecamed.patient.gui.resources.Translatrix");
        
        // Create Module Managers SubPanel
        
        l_Layout      = new FormLayout("fill:120dlu:grow, 1dlu, fill:50dlu:grow, 1dlu",
                "pref, 5dlu, pref, pref, pref, pref, pref, 30dlu, 2dlu");
        
        l_Constraints = new CellConstraints();
        
        m_ModulePanel = createSubPanel(Translatrix.getTranslationString("PatientModulesPlugin.ElementManager"));
        m_ModulePanel.setLayout(l_Layout);
        
        l_Builder     = new PanelBuilder(l_Layout,m_ModulePanel);
        
        // init the components:
        
//        m_ModuleDescriptionLabel = new JLabel(" ");
        m_CommentLabel = new JLabel(Translatrix.getTranslationString("PatientModulesPlugin.Comment"));
        m_ModulesLabel = new JLabel(Translatrix.getTranslationString("PatientModulesPlugin.availableElements"));
        
        m_ModulesList = new JList();
        m_ModulesList.setCellRenderer(new ModuleFormatterJListRenderer());
        m_ModulesList.addListSelectionListener(this);
        m_ModulesList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        m_ModulesList.setSelectedIndex(0);
        
        m_EnableButton = new JButton(Translatrix.getTranslationString("PatientModulesPlugin.enable"));
        m_EnableButton.addActionListener(this);
        m_DisableButton = new JButton(Translatrix.getTranslationString("PatientModulesPlugin.disable"));
        m_DisableButton.addActionListener(this);
        m_UpButton = new JButton(GECAMedModule.getSmallIcon(GECAMedModule.UP));
        m_UpButton.addActionListener(this);
        m_DownButton = new JButton(GECAMedModule.getSmallIcon(GECAMedModule.DOWN));
        m_DownButton.addActionListener(this);
        
        l_Builder.add(m_CommentLabel,l_Constraints.xyw(1,1,3));
        l_Builder.add(m_ModulesLabel,l_Constraints.xyw(1,3,1));
        l_Builder.add(new JScrollPane(m_ModulesList),l_Constraints.xywh(1,4,1,5));
        l_Builder.add(m_EnableButton,l_Constraints.xyw(3,4,1));
        l_Builder.add(m_DisableButton,l_Constraints.xyw(3,5,1));
        l_Builder.add(m_UpButton,l_Constraints.xyw(3,6,1));
        l_Builder.add(m_DownButton,l_Constraints.xyw(3,7,1));
               
        addSubPanel(m_ModulePanel);
        
        setIcon(PatientManagerModule.getIcon(PatientManagerModule.PATIENT_MODULES));
        setLabel(Translatrix.getTranslationString("PatientModulesPlugin.ElementManager"));
        
        loadAvailableElements(CONFIG_FILE);
        setStationary(ENABLED_ELEMENTS, enabledModules);
        setStationary(DISABLED_ELEMENTS, disabledModules);
        
        
    }
    
    
    /**
     * Is called if the default settings file is specified and used.
     */
    public void revertToDefaults() {
        setValue(ENABLED_ELEMENTS,  getDefault(ENABLED_ELEMENTS));
        setValue(DISABLED_ELEMENTS,  getDefault(DISABLED_ELEMENTS));
        
        reflectSettings();
        
        super.revertToDefaults();
    }
    
//---------------------------------------------------------------------------
    
    /**
     * Updates the Settings in the settings file. This methode is called if the apply
     * or OK button is pressed.
     */
    public void updateSettings() {
        
        resetValueChanged();
        
        setValue(ENABLED_ELEMENTS,  getEnabledElements());
        setValue(DISABLED_ELEMENTS, getDisabledElements());
        
        super.updateSettings();
    }
    
    public void init(){
        
       
    }
    
//---------------------------------------------------------------------------
    
    /**
     * Updates the GUI with the values in the settings file. The methode is called,
     * if the cancel button is pressed or the dialog is created.
     */
    public void reflectSettings() {
        
//   	 create a vector with the enabled / disabled elements: m_modules
        m_modules = new Vector<ModuleElement>();

        // modules enabled in db
        Collection<String> l_enabledModules = Arrays.asList(((String)getValue(ENABLED_ELEMENTS)).split(" "));
        
        // modules enabled in file
        Collection<String> defaultEnabledModules = Arrays.asList(((String)getStationary(ENABLED_ELEMENTS)).split(" "));
        
        // modules disabled in db
//        Collection<String> l_disabledModules = Arrays.asList(((String)getValue(DISABLED_ELEMENTS)).split(" "));
        
        // modules disables in db
        Collection<String> defaultDisabledModules = Arrays.asList(((String)getStationary(DISABLED_ELEMENTS)).split(" "));

//        Collection<String> deleteables = new ArrayList<String>(); 
//        for (Iterator iter = l_enabledModules.iterator(); iter.hasNext();) {
//			String mod = (String) iter.next();
//			if (! defaultDisabledModules.contains(mod) && ! defaultDisabledModules.contains(mod))
//				deleteables.add(mod);
//		}
//        l_enabledModules.removeAll(deleteables);
//        
//        deleteables.clear();
//        for (Iterator iter = l_disabledModules.iterator(); iter.hasNext();) {
//			String mod = (String) iter.next();
//			if (! defaultDisabledModules.contains(mod) && ! defaultDisabledModules.contains(mod))
//				deleteables.add(mod);
//		}
//        l_disabledModules.removeAll(deleteables);
        
        // list of all modules in the files
        Collection<String> newModules = new ArrayList<String>();
        newModules.addAll(defaultEnabledModules);
        newModules.addAll(defaultDisabledModules);
        
        // remove the db enabled ones
        newModules.removeAll(l_enabledModules);
        
        // remove the db disabled ones
//        newModules.removeAll(l_disabledModules);
       
        
        // a) enabled:
        for (Iterator iter = l_enabledModules.iterator(); iter.hasNext();) {
			String l_module = (String) iter.next();
			if (l_module.length() > 3) {
				ModuleElement l_element = new ModuleElement(l_module, true);
	            m_modules.add(l_element);
			}
		}
        
        // b) disabled:
        for (Iterator iter = newModules.iterator(); iter.hasNext();) {
        	String l_module = (String) iter.next();
        	if (l_module.length() > 3) {
	            ModuleElement l_element = new ModuleElement(l_module, false);
	            m_modules.add(l_element);
        	}
        }
        
        m_ModulesList.setListData(m_modules);
        m_ModulesList.setSelectedIndex(0);
        
        super.reflectSettings();
    }
    
    
//---------------------------------------------------------------------------
    
    //---------------------------------------------------------------------------
    private void loadAvailableElements(URL url){
    	try {
			BufferedReader br = new BufferedReader(
					new InputStreamReader(url.openStream()));
			String line;
			while ((line = br.readLine()) != null) {
				if (!line.startsWith("#") && line.length() > 3) {
					try {
						String[] fields = line.split("=");

						if (fields[1].toLowerCase().equals("on")) {
							this.enabledModules += fields[0] + " ";
						} else {
							this.disabledModules += fields[0] + " ";
						}
					} catch (Exception e) {
						logger.log(Level.WARN, "line is no valid settingline: " + line);
					}
				}
			}
		} catch (Exception e) {
			logger.log(Level.WARN, "error parsing file ", e);
		}
    }
    
    //---------------------------------------------------------------------------
    
    /**
     * Methode to handle the ActionEvents for the Buttons on the Panel.
     * @param p_ActionEvent The ActionEvent.
     */
    public void actionPerformed(ActionEvent p_ActionEvent) {
        
        if (p_ActionEvent.getSource() == m_EnableButton) {
            // get selected Element:
            ModuleElement e = (ModuleElement) m_ModulesList.getSelectedValue();
            
            // change the value to "true":
            e.setEnabled(true);
            
            int l_currentLocation = m_ModulesList.getSelectedIndex();
            m_ModulesList.setSelectedIndex((l_currentLocation+1));
            
            m_ModulesList.repaint();
        }
        
        if (p_ActionEvent.getSource() == m_DisableButton) {
            // get selected Element:
        	ModuleElement e = (ModuleElement) m_ModulesList.getSelectedValue();
            
            // change the value to "true":
        	e.setEnabled(false);
            
            int l_currentLocation = m_ModulesList.getSelectedIndex();
            m_ModulesList.setSelectedIndex((l_currentLocation+1));
            
            m_ModulesList.repaint();
        }
        
        if (p_ActionEvent.getSource() == m_UpButton) {
            
            int l_currentLocation = m_ModulesList.getSelectedIndex();
            ModuleElement o = (ModuleElement)  m_ModulesList.getModel().getElementAt(l_currentLocation);
            
            if(o != m_modules.firstElement()){
                
                // remove element at selected location:
                m_modules.remove(o);
                
                // add it to selected location - 1:
                m_modules.add((l_currentLocation-1), o);
                m_ModulesList.setSelectedIndex((l_currentLocation-1));
                
                
                m_ModulesList.repaint();
            }
        }
        
        if (p_ActionEvent.getSource() == m_DownButton) {
            int l_currentLocation = m_ModulesList.getSelectedIndex();
            ModuleElement o = (ModuleElement)  m_ModulesList.getModel().getElementAt(l_currentLocation);
            
            if(o != m_modules.lastElement()){
                
                // remove element at selected location:
                m_modules.remove(o);
                
                // add it to selected location - 1:
                m_modules.add((l_currentLocation+1), o);
                m_ModulesList.setSelectedIndex((l_currentLocation+1));
                
                m_ModulesList.repaint();
            }
        }
        
    }
    
    /**
     * Methode that implements the ListChangeListner.valueChanged(ListSelectionEvent).
     * Used to display the list properly.
     * @param p_SelectioEvent The Selection Event.
     */
    public void valueChanged(ListSelectionEvent p_SelectioEvent){        
        try {
            // get selected element:
//        	ModuleElement e = (ModuleElement)  m_ModulesList.getSelectedValue();

        	
//            // call the getDescription static method:
//            Class c = Class.forName(e.getName());
//            
//            Method m = c.getMethod("getDescription", null);
//            Object o = m.invoke(null, null);
//            
//            // display it in the Description area:
//            m_ModuleDescriptionLabel.setText("<html>" + (String)o + "</html>");
//            m_ModuleDescriptionLabel.repaint();
        } catch (Exception ioe) {
            // this does not matter.....
        } 
    }
    
    /**
     * Returns the currently in the Selection list enabled Modules.
     * @return A space separated list of enabled modules.
     */
    public String getEnabledElements(){
        
        String l_result = "";
        
        // walk over all modules:
        int l_numberOfElements = m_ModulesList.getModel().getSize();
        
        for(int i = 0; i < l_numberOfElements; i++){
        	ModuleElement e = (ModuleElement) m_ModulesList.getModel().getElementAt(i);
            // if they are enabled, add the class names to the result
            if(e.isEnabled()){
                l_result += e.getName() + " ";
            }
        }
        
        // ok, done:
        return l_result;
    }
    
    /**
     * Returns the currently in the Selection list disabled Modules.
     * @return A space separated list of disabled modules.
     */
    public String getDisabledElements(){
        
        String l_result = "";
        
        // walk over all modules:
        int l_numberOfElements = m_ModulesList.getModel().getSize();
        
        for(int i = 0; i < l_numberOfElements; i++){
        	ModuleElement e = (ModuleElement) m_ModulesList.getModel().getElementAt(i);
            
            // if they are enabled, add the class names to the result
            if(! e.isEnabled()){
                l_result += e.getName() + " ";
            }
        }
        
        // ok, done:
        return l_result;
    }
    
    //---------------------------------------------------------------------------
    /**
     * Method is part of the Relocalizable interface. The method does everything
     * required to reflect changes of active Locale
     */
//---------------------------------------------------------------------------
    
    public void relocalize() {
       
       super.relocalize();
       
       m_CommentLabel.setText(Translatrix.getTranslationString("PatientModulesPlugin.Comment"));
       m_EnableButton.setText(Translatrix.getTranslationString("PatientModulesPlugin.enable"));
       m_DisableButton.setText(Translatrix.getTranslationString("PatientModulesPlugin.disable"));
       
       m_ModulesLabel.setText(Translatrix.getTranslationString("PatientModulesPlugin.availableElements"));
       setLabel(Translatrix.getTranslationString("PatientModulesPlugin.ElementManager"));
    }
    
    
    public class ModuleFormatterJListRenderer extends JLabel implements
			ListCellRenderer {

		private static final long serialVersionUID = 1L;

		/**
		 * builds a new DefaultComboboxRenderer
		 */
		public ModuleFormatterJListRenderer() {
			setOpaque(true);
			setHorizontalAlignment(LEFT);
			setVerticalAlignment(CENTER);
		}

            /*
             * (non-Javadoc)
             *
             * @see javax.swing.ListCellRenderer#getListCellRendererComponent(javax.swing.JList,
             *      java.lang.Object, int, boolean, boolean)
             */
public Component getListCellRendererComponent(JList list, Object value,
        int index, boolean isSelected, boolean cellHasFocus) {
    if (isSelected) {
        setBackground(list.getSelectionBackground());
        setForeground(list.getSelectionForeground());
    } else {
        setBackground(list.getBackground());
        setForeground(list.getForeground());
    }
    try {
        String l_description = ((ModuleElement)value).getName();
      
        this.setText(l_description.substring(l_description.lastIndexOf(".")+1));
     
        if(((ModuleElement)value).isEnabled()){
            this.setIcon(GECAMedModule.getSmallIcon(GECAMedModule.OK));
        } else {
            this.setIcon(GECAMedModule.getSmallIcon(GECAMedModule.CANCEL));
        }
    } catch (Exception e) {
    	logger.log(Level.WARN, "rendering patientmodule plugin failed", e);
    }
    return this;
}

}
  
    public class ModuleElement {
    	
    	private String name;
    	private boolean enabled;
    	
    	public ModuleElement(String name, boolean enabled) {
    		this.name = name;
    		this.enabled = enabled;
    	}
    	
    	public String getName() {
    		return name;
    	}
    	
    	public boolean isEnabled() {
    		return enabled;
    	}
    	
    	public void setEnabled(boolean enabled) {
    		this.enabled = enabled;
    	}
    	
    }
    
    
}

