/*
 * Copyright
 *   2009 axYus - www.axyus.com
 *   2009 C.Marchand - christophe.marchand@axyus.com
 *
 * This file is part of XEMELIOS.
 *
 * XEMELIOS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * XEMELIOS 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with XEMELIOS; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package fr.gouv.finances.dgfip.xemelios.auth.impl.std.db.ui;

import fr.gouv.finances.dgfip.xemelios.data.impl.pool.PoolManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Properties;
import java.util.TreeSet;
import java.util.Vector;
import javax.swing.table.AbstractTableModel;

/**
 *
 * @author chm
 */
public class DlgConfigAuthentication extends javax.swing.JDialog {
    private static Vector<Engine> engines;
    private static final long serialVersionUID = 4100970141481513500L;
    private boolean returnStatus = false;
    private Engine currentEngine = null;
    private PropsTableModel model = null;
    static {
        engines = new Vector<Engine>();
        engines.add(new Engine(
                "fr.gouv.finances.dgfip.xemelios.auth.impl.basic.OldBasicAuthEngineImpl",
                "Ancienne authentification basique",
                "Ancienne authentification basique, pour compatibilité avec les versions antérieures à la V4.\nElle définit un utilisateur avec tous les droits, et un utilisateur en lecture seule.\nSeul l'utilisateur avec tous les droits peut réaliser des imports.\nLes utilisateurs sont uniquement identifés par un mot de passe.",
                new Properties()));
        engines.add(new Engine(
                "fr.gouv.finances.dgfip.xemelios.auth.impl.basic.BasicAuthEngineImpl",
                "Authentification basique",
                "Authentification basique.\nElle définit un utilisateur avec tous les droits, et un utilisateur en lecture seule.\nSeul l'utilisateur avec tous les droits peut réaliser des imports.\nLes utilisateurs sont uniquement identifés par un mot de passe.",
                new Properties()));
        Properties aphmProps = new Properties();
        try {
            String sTmp = getParameterValue("auth.ldap.baseUrl");
            aphmProps.put("auth.ldap.baseUrl",sTmp!=null?sTmp:"");
            sTmp = getParameterValue("auth.ldap.adminLogin");
            aphmProps.put("auth.ldap.adminLogin",sTmp!=null?sTmp:"");
            sTmp = getParameterValue("auth.ldap.adminPassword");
            aphmProps.put("auth.ldap.adminPassword",sTmp!=null?sTmp:"");
            sTmp = getParameterValue("auth.ldap.searchPath");
            aphmProps.put("auth.ldap.searchPath",sTmp!=null?sTmp:"");
            sTmp = getParameterValue("auth.ldap.searchField");
            aphmProps.put("auth.ldap.searchField",sTmp!=null?sTmp:"");
        } catch(Exception ex) {
            ex.printStackTrace();
        }
        engines.add(new Engine(
                "fr.gouv.finances.cp.xemelios.auth.ldapAphm.LdapAuthEngineImpl",
                "Authentification pour l'APHM",
                "Authentification spécifique à l'APHM.\nIl vérifie le mot de passe de l'utilisateur dans l'annuaire LDAP de l'APHM, et les droits des utilisateurs dans la base de donnée.",
                aphmProps));
        engines.add(new Engine(
                "fr.gouv.finances.dgfip.xemelios.auth.impl.std.db.StdDbAuthEngineImpl",
                "Authentification standard",
                "Authentifdication standard, s'appuyant entièrement sur la base de donnée.\nElle permet de gérer des profils d'utilisateurs, de limiter les accès à certains types de documents et certaines collectivités.\n",
                new Properties()));
        Properties dgcpProps = new Properties();
        try {
            String sTmp = getParameterValue("auth.ldap.service.provider");
            dgcpProps.put("auth.ldap.service.provider",sTmp!=null?sTmp:"");
            sTmp = getParameterValue("auth.ldap.server.url");
            dgcpProps.put("auth.ldap.server.url",sTmp!=null?sTmp:"");
            sTmp = getParameterValue("auth.ldap.userDn");
            dgcpProps.put("auth.ldap.userDn",sTmp!=null?sTmp:"");
        } catch(Exception ex) {
            ex.printStackTrace();
        }
        engines.add(new Engine(
                "fr.gouv.finances.cp.xemelios.auth.dgcp.DgcpAuthEngine",
                "Authentification DGCP",
                "Authentification spécifique au réseau du trésor",
                dgcpProps));
        Properties ldapProps = new Properties();
        try {
            String sTmp = getParameterValue("auth.ldap.baseUrl");
            ldapProps.put("auth.ldap.baseUrl",sTmp!=null?sTmp:"");
            sTmp = getParameterValue("auth.ldap.userDN");
            ldapProps.put("auth.ldap.userDN",sTmp!=null?sTmp:"");
            sTmp = getParameterValue("auth.ldap.readAccessDN");
            ldapProps.put("auth.ldap.readAccessDN",sTmp!=null?sTmp:"");
            sTmp = getParameterValue("auth.ldap.writeAccessDN");
            ldapProps.put("auth.ldap.writeAccessDN",sTmp!=null?sTmp:"");
        } catch(Exception ex) {
            ex.printStackTrace();
        }
        engines.add(new Engine(
                "fr.gouv.finances.cp.xemelios.auth.ldap.LdapAuthEngineImpl",
                "Authentification LDAP",
                "Authentification entièrement basée sur un annuaire LDAP.\nLe mot de passe et les droits des utilisateurs sont gérés par l'annuaire LDAP.",
                ldapProps));

    }

    /** Creates new form DlgConfigAuthentication
     * @param parent
     * @param modal
     * @param initialAuthenticationEngine
     */
    public DlgConfigAuthentication(java.awt.Frame parent, boolean modal, String initialAuthenticationEngine) {
        super(parent, modal);
        Engine initialEngine = null;
        for(Engine eng:engines) {
            if(eng.getClassName().compareTo(initialAuthenticationEngine)==0) {
                initialEngine=eng;
                break;
            }
        }
        if(initialEngine==null) initialEngine = engines.get(0);
        model = new PropsTableModel(currentEngine!=null ? currentEngine.getProps() : new Properties());
        initComponents();
        cbxEngine.setSelectedItem(initialEngine);
        setLocationRelativeTo(parent);
    }
    public boolean run() {
        returnStatus = false;
        setVisible(true);
        return returnStatus;
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();
        jScrollPane2 = new javax.swing.JScrollPane();
        tblProperties = new javax.swing.JTable();
        cbxEngine = new javax.swing.JComboBox(engines);
        jLabel2 = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        txtDesc = new javax.swing.JTextArea();
        jLabel3 = new javax.swing.JLabel();
        pbOk = new javax.swing.JButton();
        pbCancel = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("Paramétrage de l'authentification");

        jLabel1.setText("Moteur d'authentification");

        tblProperties.setModel(model);
        jScrollPane2.setViewportView(tblProperties);

        cbxEngine.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cbxEngineActionPerformed(evt);
            }
        });

        jLabel2.setText("Description");

        txtDesc.setColumns(20);
        txtDesc.setEditable(false);
        txtDesc.setLineWrap(true);
        txtDesc.setRows(5);
        txtDesc.setWrapStyleWord(true);
        jScrollPane1.setViewportView(txtDesc);

        jLabel3.setText("Propriétés complémentaires");

        pbOk.setText("Ok");
        pbOk.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                pbOkActionPerformed(evt);
            }
        });

        pbCancel.setText("Annuler");
        pbCancel.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                pbCancelActionPerformed(evt);
            }
        });

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, jScrollPane2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 429, Short.MAX_VALUE)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 429, Short.MAX_VALUE)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, layout.createSequentialGroup()
                        .add(jLabel1)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(cbxEngine, 0, 259, Short.MAX_VALUE))
                    .add(org.jdesktop.layout.GroupLayout.LEADING, jLabel2)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, jLabel3)
                    .add(layout.createSequentialGroup()
                        .add(pbCancel)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(pbOk)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(jLabel1)
                    .add(cbxEngine, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jLabel2)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jScrollPane1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 117, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jLabel3)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jScrollPane2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 135, Short.MAX_VALUE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(pbOk)
                    .add(pbCancel))
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void pbOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pbOkActionPerformed
        saveData();
        setVisible(false);
    }//GEN-LAST:event_pbOkActionPerformed

    private void pbCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pbCancelActionPerformed
        setVisible(false);
    }//GEN-LAST:event_pbCancelActionPerformed

    private void cbxEngineActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbxEngineActionPerformed
        currentEngine = (Engine)cbxEngine.getSelectedItem();
        txtDesc.setEnabled(currentEngine!=null);
        tblProperties.setEnabled(currentEngine!=null);
        if(currentEngine!=null) {
            txtDesc.setText(currentEngine.getDescription());
            model.setProps(currentEngine.getProps());
        }
    }//GEN-LAST:event_cbxEngineActionPerformed

    protected void saveData() {
        try {
            setParameterValue("authEngineClassName", currentEngine.getClassName());
            for(Object key:currentEngine.getProps().keySet()) {
                setParameterValue((String)key,currentEngine.getProps().getProperty((String)key));
            }
            returnStatus = true;
        } catch(Exception ex) {
            ex.printStackTrace();
            returnStatus = false;
        }
        
    }
    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                DlgConfigAuthentication dialog = new DlgConfigAuthentication(new javax.swing.JFrame(), true,null);
                dialog.addWindowListener(new java.awt.event.WindowAdapter() {
                    @Override
                    public void windowClosing(java.awt.event.WindowEvent e) {
                        System.exit(0);
                    }
                });
                dialog.setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JComboBox cbxEngine;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JButton pbCancel;
    private javax.swing.JButton pbOk;
    private javax.swing.JTable tblProperties;
    private javax.swing.JTextArea txtDesc;
    // End of variables declaration//GEN-END:variables

    private static class Engine implements Comparable {
        private String className;
        private String libelle;
        private String description;
        private Properties props;

        public Engine(String className, String libelle, String description, Properties props) {
            super();
            this.className=className;
            this.libelle=libelle;
            this.description=description;
            this.props=props;
        }

        public String getClassName() {
            return className;
        }

        public void setClassName(String className) {
            this.className = className;
        }

        public String getDescription() {
            return description;
        }

        public void setDescription(String description) {
            this.description = description;
        }

        public String getLibelle() {
            return libelle;
        }

        public void setLibelle(String libelle) {
            this.libelle = libelle;
        }

        public Properties getProps() {
            return props;
        }

        public void setProps(Properties props) {
            this.props = props;
        }
        @Override
        public String toString() {
            return libelle;
        }

        public int compareTo(Object o) {
            return className.compareTo(((Engine)o).getClassName());
        }
    }
    private static class PropsTableModel extends AbstractTableModel {
        public static final long serialVersionUID = 0L;
        private Properties props;
        TreeSet<String> keys;
        
        public PropsTableModel(Properties props) {
            super();
            init(props);
        }
        private void init(Properties props) {
            this.props = props;
            keys = new TreeSet<String>();
            for(Object key:props.keySet()) {
                keys.add((String)key);
            }
            fireTableDataChanged();
        }
        public void setProps(Properties props) {
            init(props);
        }

        public int getRowCount() {
            return props.size();
        }

        public int getColumnCount() {
            return 2;
        }

        public Object getValueAt(int rowIndex, int columnIndex) {
            switch(columnIndex) {
                case 0: return keyAt(rowIndex);
                default: return props.getProperty(keyAt(rowIndex));
            }
        }
        private String keyAt(int rowIndex) {
            Iterator<String> it = keys.iterator();
            for(int i=0;i<keys.size();i++) {
                String s = it.next();
                if(i==rowIndex) return  s;
            }
            return null;
        }

        @Override
        public String getColumnName(int column) {
            if(column==0) return "Propriété";
            else return "Valeur";
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            return String.class;
        }

        @Override
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return columnIndex==1;
        }

        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            props.setProperty(keyAt(rowIndex), (String)aValue);
        }


    }
    public static String getParameterValue(final String paramName) {
        Connection con = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        String ret = null;
        try {
            con = PoolManager.getInstance().getConnection();
            ps = con.prepareStatement("SELECT PARAM_VALUE FROM PARAMETERS WHERE PARAM_NAME=?");
            ps.setString(1, paramName);
            rs = ps.executeQuery();
            if (rs.next()) {
                ret = rs.getString(1);
            }
        } catch (SQLException sqlEx) {
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                } catch (Throwable t) {
                }
            }
            if (ps != null) {
                try {
                    ps.close();
                } catch (Throwable t) {
                }
            }
            if (con != null) {
                PoolManager.getInstance().releaseConnection(con);
            }
        }
        return ret;
    }
    public static void setParameterValue(final String paramName, final String paramValue) {
        Connection con = null;
        PreparedStatement ps = null;
        try {
            con = PoolManager.getInstance().getConnection();
            String ret = getParameterValue(paramName);
            if (ret == null) {
                ps = con.prepareStatement("INSERT INTO PARAMETERS (PARAM_VALUE, PARAM_NAME) VALUES (?, ?)");
            } else {
                ps = con.prepareStatement("UPDATE PARAMETERS SET PARAM_VALUE=? WHERE PARAM_NAME=?");
            }
            ps.setString(1, paramValue);
            ps.setString(2, paramName);
            ps.executeUpdate();
        } catch (SQLException sqlEx) {
        } finally {
            if (ps != null) {
                try {
                    ps.close();
                } catch (Throwable t) {
                }
            }
            if (con != null) {
                PoolManager.getInstance().releaseConnection(con);
            }
        }
    }

}
