/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * HostSettingPanel.java
 *
 * Created on 2010/03/09, 17:47:01
 */
package open.dolphin.client.settings;

import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import open.dolphin.project.DolphinPrincipal;
import open.dolphin.project.GlobalVariables;
import open.dolphin.project.GlobalSettings;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import javax.swing.JPanel;

import open.dolphin.client.AutoRomanListener;
import open.dolphin.client.RegexConstrainedDocument;
import open.dolphin.project.GlobalConstants;
import open.dolphin.utils.Adapter;
import open.dolphin.utils.UserDirectoryInitializer;
import org.jdesktop.application.Action;
import org.jdesktop.application.ApplicationContext;

/**
 *
 * @author oda
 */
public class HostSettingPanel extends javax.swing.JPanel implements IAbstractSettingPanel {

    private ProjectSettingDialog context;
    private PropertyChangeSupport boundSupport;
    /**
     *
     */
    protected State state = State.NONE_STATE;
    private boolean loginState;
    private String title;
    private String icon;
    private String id;
    private static final String DEFAULT_FACILITY_OID = "1.3.6.1.4.1.9414.10.1";
    private String ipAddressPattern = "[A-Za-z0-9.\\-_]*";
    private static final String ID = "hostSetting";
    private static final String TITLE = "サーバ";
    private static final String ICON = "server.png";
    // JBoss Server PORT
    private int hostPort = 1099;
    /** 画面用のモデル */
    private ServerModel model;
    private StateMgr stateMgr;
    private Adapter<Boolean, Boolean> adapter;

    /** Creates new form HostSettingPanel */
    public HostSettingPanel() {
        boundSupport = new PropertyChangeSupport(this);
        initComponents();

        setId(ID);
        setTitle(TITLE);
        setIcon(ICON);
    }

    /** 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() {

        sip = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        dbAddressField = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        dbPasswordField = new javax.swing.JPasswordField();
        jPanel1 = new javax.swing.JPanel();
        sslState = new javax.swing.JRadioButton();
        fetchButton = new javax.swing.JButton();
        uip = new javax.swing.JPanel();
        jLabel3 = new javax.swing.JLabel();
        userIdField = new javax.swing.JTextField();

        setPreferredSize(new java.awt.Dimension(500, 305));

        sip.setBorder(javax.swing.BorderFactory.createTitledBorder("サーバ情報"));
        sip.setName("sip"); // NOI18N
        sip.setPreferredSize(new java.awt.Dimension(500, 199));

        jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
        jLabel1.setName("jLabel1"); // NOI18N

        dbAddressField.setName("dbAddressField"); // NOI18N
        dbAddressField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                dbAddressFieldActionPerformed(evt);
            }
        });
        dbAddressField.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                HostSettingPanel.this.propertyChange(evt);
            }
        });

        jLabel2.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
        jLabel2.setName("jLabel2"); // NOI18N

        dbPasswordField.setName("dbPasswordField"); // NOI18N
        dbPasswordField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                dbPasswordFieldActionPerformed(evt);
            }
        });
        dbPasswordField.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                HostSettingPanel.this.propertyChange(evt);
            }
        });

        jPanel1.setName("jPanel1"); // NOI18N
        jPanel1.setLayout(new java.awt.GridLayout(1, 0));

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance().getContext().getActionMap(HostSettingPanel.class, this);
        sslState.setAction(actionMap.get("enableKeyStoreFetch")); // NOI18N
        sslState.setText("SSLを使用");
        sslState.setName("sslState"); // NOI18N
        sslState.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                sslStateActionPerformed(evt);
            }
        });
        sslState.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                sslStatePropertyChange(evt);
            }
        });

        fetchButton.setAction(actionMap.get("fetchKeyStore")); // NOI18N
        fetchButton.setFont(new java.awt.Font("VL ゴシック", 0, 12));
        fetchButton.setText("...");
        fetchButton.setName("fetchButton"); // NOI18N

        javax.swing.GroupLayout sipLayout = new javax.swing.GroupLayout(sip);
        sip.setLayout(sipLayout);
        sipLayout.setHorizontalGroup(
            sipLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(sipLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(sipLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(sipLayout.createSequentialGroup()
                        .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 159, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(sipLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(sipLayout.createSequentialGroup()
                                .addComponent(sslState, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(fetchButton, javax.swing.GroupLayout.PREFERRED_SIZE, 64, javax.swing.GroupLayout.PREFERRED_SIZE))
                            .addComponent(dbPasswordField, javax.swing.GroupLayout.DEFAULT_SIZE, 165, Short.MAX_VALUE)))
                    .addGroup(sipLayout.createSequentialGroup()
                        .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 159, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(dbAddressField, javax.swing.GroupLayout.DEFAULT_SIZE, 165, Short.MAX_VALUE))
                    .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap())
        );
        sipLayout.setVerticalGroup(
            sipLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(sipLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(sipLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(dbAddressField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(sipLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel2)
                    .addComponent(dbPasswordField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(sipLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(sipLayout.createSequentialGroup()
                        .addComponent(fetchButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addContainerGap(25, Short.MAX_VALUE))
                    .addGroup(sipLayout.createSequentialGroup()
                        .addComponent(sslState)
                        .addContainerGap())))
        );

        uip.setBorder(javax.swing.BorderFactory.createTitledBorder("ユーザ情報"));
        uip.setName("uip"); // NOI18N
        uip.setPreferredSize(new java.awt.Dimension(500, 79));

        jLabel3.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
        jLabel3.setText("ユーザID:");
        jLabel3.setName("jLabel3"); // NOI18N

        userIdField.setColumns(10);
        userIdField.setName("userIdField"); // NOI18N
        userIdField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                userIdFieldActionPerformed(evt);
            }
        });
        userIdField.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                HostSettingPanel.this.propertyChange(evt);
            }
        });

        javax.swing.GroupLayout uipLayout = new javax.swing.GroupLayout(uip);
        uip.setLayout(uipLayout);
        uipLayout.setHorizontalGroup(
            uipLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(uipLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 158, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(userIdField, javax.swing.GroupLayout.PREFERRED_SIZE, 108, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(70, Short.MAX_VALUE))
        );
        uipLayout.setVerticalGroup(
            uipLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(uipLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(uipLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel3)
                    .addComponent(userIdField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                    .addComponent(uip, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 372, Short.MAX_VALUE)
                    .addComponent(sip, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 372, Short.MAX_VALUE))
                .addContainerGap(128, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(sip, javax.swing.GroupLayout.PREFERRED_SIZE, 169, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(uip, javax.swing.GroupLayout.PREFERRED_SIZE, 79, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(63, 63, 63))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void dbAddressFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dbAddressFieldActionPerformed
    }//GEN-LAST:event_dbAddressFieldActionPerformed

    private void userIdFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_userIdFieldActionPerformed
        change();
    }//GEN-LAST:event_userIdFieldActionPerformed

    private void dbPasswordFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dbPasswordFieldActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_dbPasswordFieldActionPerformed

    private void sslStateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sslStateActionPerformed
        change();
    }//GEN-LAST:event_sslStateActionPerformed

    private void sslStatePropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_sslStatePropertyChange
        enableKeyStoreFetch();
    }//GEN-LAST:event_sslStatePropertyChange

    private void propertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_propertyChange
        change();
    }//GEN-LAST:event_propertyChange

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JTextField dbAddressField;
    private javax.swing.JPasswordField dbPasswordField;
    private javax.swing.JButton fetchButton;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel sip;
    private javax.swing.JRadioButton sslState;
    private javax.swing.JPanel uip;
    private javax.swing.JTextField userIdField;
    // End of variables declaration//GEN-END:variables

    @Override
    public void onChenge(Adapter<Boolean, Boolean> adapter) {
        this.adapter = adapter;
    }

    private void change() {
        if (adapter != null) {
            try {
                adapter.onResult(true);
            } catch (Exception ex) {
            }
        }
    }

    // サーバ設定画面を開始する。
    @Override
    public void start() {
        model = new ServerModel();
        model.populate();
        initCustomComponents();
        connect();
        bindModelToView();
    }

    // GUI コンポーネントを初期化する。
    private void initCustomComponents() {

        if (GlobalSettings.isTrial()) {
            jLabel1.setText("DBアドレス:編集不可");
            jLabel2.setText("DBパスワード:編集不可");
        } else {
            jLabel1.setText("DBアドレス:");
            jLabel2.setText("DBパスワード:");
        }

        // パターン制約を加える
        RegexConstrainedDocument hostDoc = new RegexConstrainedDocument(ipAddressPattern);

        RegexConstrainedDocument dbDoc = new RegexConstrainedDocument(ipAddressPattern);
        dbAddressField.setDocument(dbDoc);

        if (GlobalSettings.isTrial()) {
            dbAddressField.setText("dolphin.good-day.co.jp");// 体験版利用の場合はホストを編集できないようにする
            dbAddressField.setVisible(false);
            model.setDbPassword("onas+tro");
            dbPasswordField.setVisible(false);
        }
    }

    // コンポーネントのリスナ接続を行う。
    private void connect() {

        stateMgr = new StateMgr();

        DocumentListener dl = new DocumentListener() {

            @Override
            public void insertUpdate(DocumentEvent e) {
                stateMgr.checkState();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                stateMgr.checkState();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                stateMgr.checkState();
            }
        };

        dbAddressField.getDocument().addDocumentListener(dl);
        userIdField.getDocument().addDocumentListener(dl);

        // IME OFF FocusAdapter

            dbAddressField.addFocusListener(AutoRomanListener.getInstance());
            userIdField.addFocusListener(AutoRomanListener.getInstance());
        
        // ログインしている状態の場合、この設定はできないようにする
        if (isLoginState()) {
            userIdField.setEnabled(false);
            dbAddressField.setEnabled(false);
        }
    }

    // Model 値を表示する。
    private void bindModelToView() {

        String val = model.getUserId(); // userId設定する
        val = val != null ? val : "";
        userIdField.setText(val);

        GlobalVariables.UserType userType = model.getUserType(); // UserType で分岐する

        switch (userType) {

            case FACILITY_USER:
                val = val != null ? val : "";

                val = model.getDbAddress();
                val = val != null ? val : "";
                dbAddressField.setText(val);

                sslState.setSelected(model.getDbSSLState());

                if (model.getPort() != 0) {
                    hostPort = model.getPort();
                }
                break;
        }
    }

    // Viewの値をモデルへ設定する。
    private void bindViewToModel() {
        String facilityId = DEFAULT_FACILITY_OID;      // 施設IDとユーザIDを保存する
        String userId = userIdField.getText().trim();
        String dbAddress = dbAddressField.getText().trim();
        char[] pass = dbPasswordField.getPassword();
        String dbPassword = new String(pass);
        for (int i = 0; i < pass.length; i++) {
            pass[i] = 0;
        }
        ;
        pass = null;
        dbPassword = dbPassword.trim();
        model.setFacilityId(facilityId);
        model.setUserId(userId);
        model.setDbAddress(dbAddress);
        if (!dbPassword.equals("")) {
            model.setDbPassword(dbPassword);
            dbPassword = null;
        }
        model.setDbSSLState(sslState.isSelected());
        model.setUserType(GlobalVariables.UserType.FACILITY_USER);
        model.setPort(hostPort);
    }

    // 設定値を保存する。
    @Override
    public void save() {
        bindViewToModel();
        model.restore();
    }

    @Override
    public String getId() {
        return id;
    }

    @Override
    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String getTitle() {
        return title;
    }

    @Override
    public void setTitle(String title) {
        this.title = title;
    }

    @Override
    public String getIcon() {
        return icon;
    }

    @Override
    public void setIcon(String icon) {
        this.icon = icon;
    }

    @Override
    public ProjectSettingDialog getContext() {
        return context;
    }

    @Override
    public void setContext(ProjectSettingDialog context) {
        this.context = context;
        this.addPropertyChangeListener(STATE_PROP, context);
        this.setLogInState(context.getLoginState());
    }

    @Override
    public boolean isLoginState() {
        return loginState;
    }

    @Override
    public void setLogInState(boolean login) {
        loginState = login;
    }

    @Override
    public JPanel getPanel() {
        return this;
    }

    @Override
    public void addPropertyChangeListener(String prop, PropertyChangeListener l) {
        boundSupport.addPropertyChangeListener(prop, l);
    }

    @Override
    public void removePropertyChangeListener(String prop, PropertyChangeListener l) {
        boundSupport.removePropertyChangeListener(prop, l);
    }

    /**
     * @param state The state to set.
     */
    @Override
    public void setState(State state) {
        this.state = state;
        boundSupport.firePropertyChange(STATE_PROP, null, this.state);
    }

    /**
     * @return Returns the state.
     */
    @Override
    public State getState() {
        return state;
    }

    // サーバ画面設定用のモデルクラス。
    class ServerModel {

        private GlobalVariables.UserType userType;
        private String dbAddress;
        private String dbPassword;
        private boolean dbSSLState;
        private int port;
        private String facilityId;
        private String userId;

        public ServerModel() {
        }

        /**
         * ProjectStub からポピュレイトする。
         */
        public void populate() {
            setUserId(GlobalVariables.getUserId());   // userId設定する
            setFacilityId(GlobalVariables.getFacilityId());  // 施設IDを設定する
            setUserType(GlobalVariables.getUserType()); // UserTypeを設定する
            setDbAddress(GlobalVariables.getDbAddress()); // DBAddressを設定する
            setDbPassword(GlobalVariables.getDbPasswordWithoutHash()); // DBPasswordを設定する
            setDbSSLState(GlobalVariables.getDbSSLState()); // DBのSSL仕様有無を設定する
            setPort(GlobalVariables.getHostPort());// Portを設定する
        }

        /**
         * ProjectStubへリストアする。
         */
        public void restore() {
            GlobalVariables.setFacilityId(getFacilityId());  // 施設IDとユーザIDを保存する
            GlobalVariables.setUserId(getUserId());
            DolphinPrincipal principal = new DolphinPrincipal(); // Principleを保存する
            principal.setFacilityId(getFacilityId());
            principal.setUserId(getUserId());
            GlobalVariables.setDolphinPrincipal(principal);
            GlobalVariables.setUserType(getUserType()); // メンバータイプを保存する
            GlobalVariables.setDbAddress(getDbAddress());
            GlobalVariables.setDbPassword(getDbPassword());
            GlobalVariables.setDbSSLState(getDbSSLState());
            GlobalVariables.setHostPort(getPort());  // Portを設定を保存する
        }

        public GlobalVariables.UserType getUserType() {
            return userType;
        }

        public void setUserType(GlobalVariables.UserType userType) {
            this.userType = userType;
        }

        public String getDbAddress() {
            return dbAddress;
        }

        public void setDbAddress(String dbAddress) {
            this.dbAddress = dbAddress;
        }

        public String getDbPassword() {
            return dbPassword;
        }

        public void setDbPassword(String dbPassword) {
            this.dbPassword = dbPassword;
        }

        public boolean getDbSSLState() {
            return this.dbSSLState;
        }

        public void setDbSSLState(boolean state) {
            this.dbSSLState = state;
        }

        public int getPort() {
            return port;
        }

        public void setPort(int port) {
            this.port = port;
        }

        public String getFacilityId() {
            return facilityId;
        }

        public void setFacilityId(String facilityId) {
            this.facilityId = facilityId;
        }

        public String getUserId() {
            return userId;
        }

        public void setUserId(String userId) {
            this.userId = userId;
        }
    }

    /**
     * Mediator 的 StateMgr クラス。
     */
    class StateMgr {

        public void checkState() {

            State newState = isValid()
                    ? State.VALID_STATE
                    : State.INVALID_STATE;
            if (newState != state) {
                setState(newState);
            }
        }

        private boolean isValid() {

            boolean isNotUserIdEmpty = !userIdField.getText().trim().equals("");
            boolean isNotDbAddressEmpty = !dbAddressField.getText().trim().equals("");

            return isNotUserIdEmpty && isNotDbAddressEmpty;
        }
    }

    @Action
    public void fetchKeyStore() {
        ApplicationContext appContext = GlobalConstants.getApplicationContext();
        File userPath = appContext.getLocalStorage().getDirectory();
        File trustStorePath = new File(userPath, "security/dolphin.trustStore");
        UserDirectoryInitializer.fetchTrustStore(trustStorePath);

        change();
    }

    @Action
    public void enableKeyStoreFetch() {
        fetchButton.setEnabled(sslState.isSelected());
    }
}
