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

/*
 * StampBoxFrame.java
 *
 * Created on 2010/04/12, 14:16:08
 */
package open.dolphin.client.editor.stamp;

import java.sql.SQLException;
import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.io.IOException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import open.dolphin.delegater.remote.RemoteStampDelegater;
import open.dolphin.infomodel.FacilityModel;
import open.dolphin.infomodel.IInfoModel;
import open.dolphin.infomodel.IStampTreeModel;
import open.dolphin.infomodel.ModuleModel;
import open.dolphin.infomodel.PublishedTreeModel;
import open.dolphin.infomodel.RegisteredDiagnosisModel;
import open.dolphin.infomodel.StampTreeModel;
import open.dolphin.helper.ComponentMemory;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;

import java.util.List;
import java.util.concurrent.Callable;
import java.util.prefs.Preferences;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTabbedPane;

import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.xml.transform.TransformerException;
import open.dolphin.client.AbstractStampBox;
import open.dolphin.client.AspStampBox;
import open.dolphin.client.BlockGlass;
import open.dolphin.client.DefaultStampTreeXmlBuilder;
import open.dolphin.client.IMainTool;
import open.dolphin.client.IMainWindow;
import open.dolphin.client.IStampEditorDialog;
import open.dolphin.container.Pair;
import open.dolphin.utils.FileTool;
import open.dolphin.project.GlobalVariables;
import open.dolphin.client.stamp.convert.StampConverter;
import open.dolphin.component.TabTransferHandler;
import open.dolphin.log.LogWriter;
import open.dolphin.project.GlobalConstants;
import open.dolphin.utils.FileOpenDialog;
import org.xml.sax.SAXException;

/**
 *
 * @author
 */
public class StampBoxFrame extends javax.swing.JFrame implements IMainTool {

    private static final String NAME = "スタンプ箱";
    // frameのデフォルトの大きさ及びタイトル
    private final int DEFAULT_WIDTH = 320;
    private final int DEFAULT_HEIGHT = 690;
    private final int IMPORT_TREE_OFFSET = 1;
    private AbstractStampBox userBox;    //ユーザ個人用の StampBox
    private AbstractStampBox curBox;    // 現在選択されている StampBox
    private List<Long> importedTreeList;    // インポートしている StampTree のリスト
    private EditorSetPanel editors;    // StampMaker のエディタセット
    private EditorValueListener editorValueListener;    // Editorの編集値リスナ
    private boolean editing;    // StampMaker モードのフラグ
    private Point stampBoxLoc;    // StampBox 位置
    private int stampBoxWidth;    // StampBox 幅
    private int stampBoxHeight;    // StampBox 高さ
    private BlockGlass glass;    // Block Glass Pane
    private List<IStampTreeModel> stampTreeModels;    // このスタンプボックスの StmpTreeModel
    private String name;
    private IMainWindow context;

    /** Creates new form StampBoxFrame */
    public StampBoxFrame() {
        super();
        this.name = NAME;
        importedTreeList = new ArrayList<Long>(5);
        initComponents();
    }

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

        content = new javax.swing.JPanel();
        stampBoxPanel = new javax.swing.JPanel();
        parentBox = new javax.swing.JTabbedPane();
        cmdPanel = new javax.swing.JPanel();
        toolBtn = new javax.swing.JToggleButton();
        publishBtn = new javax.swing.JButton();
        importBtn = new javax.swing.JButton();
        fileExportButton = new javax.swing.JButton();
        fileImportButton = new javax.swing.JButton();
        curBoxInfo = new javax.swing.JLabel();

        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
        });

        content.setName("content"); // NOI18N
        content.setLayout(new java.awt.BorderLayout());

        stampBoxPanel.setName("stampBoxPanel"); // NOI18N
        stampBoxPanel.setLayout(new java.awt.BorderLayout());

        parentBox.setTabPlacement(javax.swing.JTabbedPane.BOTTOM);
        parentBox.setName("parentBox"); // NOI18N
        parentBox.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                parentBoxStateChanged(evt);
            }
        });
        stampBoxPanel.add(parentBox, java.awt.BorderLayout.CENTER);

        cmdPanel.setName("cmdPanel"); // NOI18N
        cmdPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 0, 0));

        toolBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/open/dolphin/resources/images/tools_24.gif"))); // NOI18N
        toolBtn.setToolTipText("スタンプメーカを起動します");
        toolBtn.setName("toolBtn"); // NOI18N
        toolBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                toolBtnActionPerformed(evt);
            }
        });
        cmdPanel.add(toolBtn);

        publishBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/open/dolphin/resources/images/exp_24.gif"))); // NOI18N
        publishBtn.setToolTipText("\"スタンプの公開を管理をします");
        publishBtn.setName("publishBtn"); // NOI18N
        publishBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                publishBtnActionPerformed(evt);
            }
        });
        cmdPanel.add(publishBtn);

        importBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/open/dolphin/resources/images/impt_24.gif"))); // NOI18N
        importBtn.setToolTipText("スタンプのインポートを管理をします");
        importBtn.setName("importBtn"); // NOI18N
        importBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                importBtnActionPerformed(evt);
            }
        });
        cmdPanel.add(importBtn);

        fileExportButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/open/dolphin/resources/images/save_24.gif"))); // NOI18N
        fileExportButton.setToolTipText("スタンプをファイルへ書き出します");
        fileExportButton.setName("fileExportButton"); // NOI18N
        fileExportButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                fileExportButtonActionPerformed(evt);
            }
        });
        cmdPanel.add(fileExportButton);

        fileImportButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/open/dolphin/resources/images/move_24.gif"))); // NOI18N
        fileImportButton.setToolTipText("スタンプをファイルから読み込みます");
        fileImportButton.setName("fileImportButton"); // NOI18N
        fileImportButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                fileImportButtonActionPerformed(evt);
            }
        });
        cmdPanel.add(fileImportButton);

        curBoxInfo.setFont(new java.awt.Font("Dialog", 0, 10));
        curBoxInfo.setName("curBoxInfo"); // NOI18N
        cmdPanel.add(curBoxInfo);

        stampBoxPanel.add(cmdPanel, java.awt.BorderLayout.NORTH);

        content.add(stampBoxPanel, java.awt.BorderLayout.CENTER);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(content, javax.swing.GroupLayout.DEFAULT_SIZE, 363, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(content, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE)
        );

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

    private void toolBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_toolBtnActionPerformed
        if (!editing) {
            startStampMake();
            editing = true;
        } else {
            stopStampMake();
            editing = false;
        }
    }//GEN-LAST:event_toolBtnActionPerformed

    private void publishBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_publishBtnActionPerformed
        publishStamp();
    }//GEN-LAST:event_publishBtnActionPerformed

    private void importBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importBtnActionPerformed
        importStamp();
    }//GEN-LAST:event_importBtnActionPerformed

    private void fileExportButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileExportButtonActionPerformed
        Cursor currentCursor = getCursor();
        setCursor(new Cursor(Cursor.WAIT_CURSOR));
        try {
            exportStampToFile();
        } finally {
            setCursor(currentCursor);
        }
    }//GEN-LAST:event_fileExportButtonActionPerformed

    private void fileImportButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileImportButtonActionPerformed
        Cursor currentCursor = getCursor();
        setCursor(new Cursor(Cursor.WAIT_CURSOR));
        try {
            importStampFromFile();
        } finally {
            setCursor(currentCursor);
        }
    }//GEN-LAST:event_fileImportButtonActionPerformed

    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
        if (editing) {
            toolBtn.doClick();
        } else {
            setVisible(false);
        }
    }//GEN-LAST:event_formWindowClosing

    private void parentBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_parentBoxStateChanged
        boxChanged();
    }//GEN-LAST:event_parentBoxStateChanged

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

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

    @Override
    public void setContext(IMainWindow context) {
        this.context = context;
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel cmdPanel;
    private javax.swing.JPanel content;
    private javax.swing.JLabel curBoxInfo;
    private javax.swing.JButton fileExportButton;
    private javax.swing.JButton fileImportButton;
    private javax.swing.JButton importBtn;
    private javax.swing.JTabbedPane parentBox;
    private javax.swing.JButton publishBtn;
    private javax.swing.JPanel stampBoxPanel;
    private javax.swing.JToggleButton toolBtn;
    // End of variables declaration//GEN-END:variables

    /**a
     * StampTreeModel を返す。
     * @return StampTreeModelのリスト
     */
    public List<IStampTreeModel> getStampTreeModels() {
        return stampTreeModels;
    }

    /**
     * parentBox を返す。
     * @return parentBox
     */
    public JTabbedPane getParentBox() {
        return this.parentBox;
    }

    /**
     * StampTreeModel を設定する。
     * @param stampTreeModels StampTreeModelのリスト
     */
    private void setStampTreeModels(List<IStampTreeModel> stampTreeModels) {
        this.stampTreeModels = stampTreeModels;
    }

    /**
     * 現在のStampBoxを返す。
     * @return 現在選択されているStampBox
     */
    private AbstractStampBox getCurrentBox() {
        return curBox;
    }

    /**
     * 現在のStampBoxを設定する。
     * @param curBox 選択されたStampBox
     */
    private void setCurrentBox(AbstractStampBox curBox) {
        this.curBox = curBox;
    }

    /**
     * User(個人用)のStampBoxを返す。
     * @return User(個人用)のStampBox
     */
    public AbstractStampBox getUserStampBox() {
        return userBox;
    }

    /**
     * StampBox の JFrame を返す。
     * @return StampBox の JFrame
     */
    public JFrame getFrame() {
        return this;
    }

    /**
     * インポートしているStampTreeのリストを返す。
     * @return インポートしているStampTreeのリスト
     */
    public List<Long> getImportedTreeList() {
        return importedTreeList;
    }

    /**
     * Block用GlassPaneを返す。
     * @return Block用GlassPane
     */
    public BlockGlass getBlockGlass() {
        return glass;
    }

    /**
     * StampTree をデータベースまたはリソースから読み込む。
     * アプリケーションの起動時に一括してコールされる。
     * @return
     */
    @Override
    public Callable<Boolean> getStartingTask() {

        Callable<Boolean> task = new Callable<Boolean>() {

            @Override
            public Boolean call() {

                try {
                    // UserPkを取得する
                    long userPk = GlobalVariables.getUserModel().getId();

                    // データベース検索を行う
                    RemoteStampDelegater stampDel = new RemoteStampDelegater();
                    List<IStampTreeModel> treeList = stampDel.getTrees(userPk);

                    if (stampDel.isError()) {
                        return false;
                    }

                    // User用のStampTreeが存在しない新規ユーザの場合、そのTreeを生成する
                    boolean hasTree = false;
                    if (treeList != null && !treeList.isEmpty()) {
                        hasTree = true;
                    }

                    // 新規ユーザでデータベースに個人用のStampTreeが存在しなかった場合
                    //スタンプが壊れた時はhasTreeをfalseにしてログインすれば初期化される。
                    if (!hasTree) {
                        treeList.add(0, createStampTreeModel(getSeedStamp()));
                    }
                    setStampTreeModels(treeList);
                } catch (Exception e) {
                    LogWriter.fatal(getClass(), e.getMessage());
                    return false;
                }
                return true;
            }
        };
        return task;
    }

    /**
     * プログラムを開始する。
     */
    @Override
    public void start() {

        if (stampTreeModels == null) {
            //     LogWriter.fatal(getClass(), "StampTreeModel is null");
            throw new RuntimeException("Fatal error: StampTreeModel is null at start.");
        }

        // StampBoxのJFrameを生成する
        String title = GlobalConstants.getFrameTitle(getName());
        Rectangle setBounds = new Rectangle(0, 0, 1000, 690);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int defaultX = (screenSize.width - setBounds.width) / 2;
        int defaultY = (screenSize.height - setBounds.height) / 2;
        int defaultWidth = setBounds.width;
        int defaultHeight = setBounds.height;
        setBounds = new Rectangle(defaultX, defaultY, defaultWidth, defaultHeight);
        int x = (defaultX + defaultWidth) - DEFAULT_WIDTH;
        int y = defaultY;
        int width = DEFAULT_WIDTH;
        int height = DEFAULT_HEIGHT;
        setTitle(title);

        //<TODO>アイコンを適切な物に変更
        ImageIcon icon = GlobalConstants.getImageIcon("web_32.gif");
        setIconImage(icon.getImage());

        setSize(new Dimension(stampBoxWidth, stampBoxHeight));
        Dimension dim = new Dimension(350, 690);
        setMinimumSize(dim);

        glass = new BlockGlass();
        setGlassPane(glass);

        ComponentMemory cm = new ComponentMemory(this, new Point(x, y), new Dimension(width, height), this);
        cm.setToPreferenceBounds();

        for (IStampTreeModel model : stampTreeModels) {
            // 読み込んだStampTreeをTabbedPaneに格納し、さらにそれをparentBoxに追加する
            if (model != null) {
                // ユーザ個人用StampTreeの場合
                if (model.getUser().getId() == GlobalVariables.getUserModel().getId() && model instanceof StampTreeModel) {
                    userBox = new UserStampBox(this, model);
                    userBox.setTransferHandler(new TabTransferHandler());// 個人用のスタンプボックス(JTabbedPane)を生成する
                    parentBox.addTab("個人用", userBox);  // ParentBox に追加する
                } else if (model instanceof PublishedTreeModel) {
                    // インポートしているTreeの場合
                    importPublishedTree(model);
                }
            }
        }

        stampTreeModels.clear();        // StampTreeModel を clear する

        // ParentBox のTab に tooltips を設定する
        for (int i = 0; i < parentBox.getTabCount(); i++) {
            AbstractStampBox box = (AbstractStampBox) parentBox.getComponentAt(i);
            parentBox.setToolTipTextAt(i, box.getInfo());
        }

        // ParentBoxにChangeListenerを登録しスタンプメーカの制御を行う
        //     parentBox.addChangeListener(new BoxChangeListener());
        setCurrentBox(userBox);

        // ユーザBox用にChangeListenerを設定する
        userBox.addChangeListener(new TabChangeListener());

        // Frame に加える
        setContentPane(content);

        // 前回終了時のタブを選択する
        Preferences prefs = Preferences.userNodeForPackage(this.getClass());
        String name1 = this.getClass().getName();
        int index = prefs.getInt(name1 + "_parentBox", 0);
        index = (index >= 0 && index <= (parentBox.getTabCount() - 1)) ? index : 0;
        parentBox.setSelectedIndex(index);
        index = prefs.getInt(name1 + "_stampBox", 0);
        index = (index >= 0 && index <= (userBox.getTabCount() - 1)) ? index : 0;

        // ORCA タブが選択されていて ORCA に接続がない場合を避ける
        index = index == IInfoModel.TAB_INDEX_ORCA ? 0 : index;

        if (userBox.getTabCount() != 0) {
            userBox.setSelectedIndex(index);
        }

        boxChanged(); // ボタンをコントロールする
    }

    /**
     * 選択されているIndexでボタンを制御する。
     */
    private void boxChanged() {

        int index = parentBox.getSelectedIndex();
        setCurrentBox((AbstractStampBox) parentBox.getComponentAt(index));
        String info = getCurrentBox().getInfo();
        curBoxInfo.setText(info);

        if (getCurrentBox() == userBox) {
            publishBtn.setEnabled(true);
            int index2 = userBox.getSelectedIndex();
            boolean enabled = userBox.isHasEditor(index2);
            toolBtn.setEnabled(enabled);

        } else {
            toolBtn.setEnabled(false);
            publishBtn.setEnabled(false);
        }
    }

    /**
     * ImportしたStampBoxの選択可能を制御する。
     * @param enabled 選択可能な時 true
     */
    private void enabledImportBox(boolean enabled) {
        int cnt = parentBox.getTabCount();
        for (int i = 0; i < cnt; i++) {
            if ((JTabbedPane) parentBox.getComponentAt(i) != userBox) {
                parentBox.setEnabledAt(i, enabled);
            }
        }
    }

    /**
     *
     * @return
     */
    public boolean update() {
        return false;
    }

    /**
     * TabChangeListener
     * User用StampBoxのTab切り替えリスナクラス。
     */
    class TabChangeListener implements ChangeListener {

        @Override
        public void stateChanged(ChangeEvent e) {

            if (!editing) {
                // スタンプメーカ起動中でない時
                // テキストスタンプタブが選択されたらスタンプメーカボタンを disabledにする
                // ORCA セットタブの場合を処理する
                int index = userBox.getSelectedIndex();
                StampTree tree = userBox.getStampTree(index);
                tree.enter();
                boolean enabled = userBox.isHasEditor(index);
                toolBtn.setEnabled(enabled);
            } else {
                // スタンプメーカ起動中の時
                // 選択されたタブに対応するエディタを表示する
                int index = userBox.getSelectedIndex();
                StampTree tree = userBox.getStampTree(index);
                if (editors != null && (!tree.getEntity().equals(IInfoModel.ENTITY_TEXT))) {
                    editors.show(tree.getEntity());
                }
            }
        }
    }

    /**
     * ParentBox の TabChangeListenerクラス。
     */
    // class BoxChangeListener implements ChangeListener {
    //     public void stateChanged(ChangeEvent e) {
    //          boxChanged();
    //      }
    //  }
    /**
     * スタンプメーカを起動する。
     */
    private void startStampMake() {

        if (!editing) {
            // 現在の位置と大きさを保存する
            stampBoxLoc = getLocation();
            stampBoxWidth = getWidth();
            stampBoxHeight = getHeight();

            Dimension dim = new Dimension(1000, 690);
            setMinimumSize(dim);

            enabledImportBox(false); // ASP ボックスを選択不可にする

            // 現在のタブからtreeのEntityを得る
            int index = userBox.getSelectedIndex();
            StampTree tree = userBox.getStampTree(index);
            String entity = tree.getEntity();

            // エディタを生成する
            // text タブを選択不可にする
            userBox.setHasNoEditorEnabled(false);
            List<StampTree> allTrees = userBox.getAllTrees();
            editors = new EditorSetPanel();
            for (StampTree st : allTrees) {
                st.addTreeSelectionListener(editors);
            }
            editorValueListener = new EditorValueListener();
            editors.addPropertyChangeListener(IStampEditorDialog.EDITOR_VALUE_PROP, editorValueListener);
            editors.show(entity);

            content.removeAll();
            content.add(editors, BorderLayout.CENTER);
            content.add(stampBoxPanel, BorderLayout.EAST);
            stampBoxPanel.setPreferredSize(new Dimension(300, 690));
            editors.setPreferredSize(new Dimension(724, 690));
            content.setPreferredSize(new Dimension(1000, 690));
            content.revalidate();
            setVisible(false);

            // 前回終了時の位置とサイズを取得する
            Preferences prefs = Preferences.userNodeForPackage(this.getClass());
            String name1 = this.getClass().getName();
            int locX = prefs.getInt(name1 + ".stampmMaker.x", 0);
            int locY = prefs.getInt(name1 + ".stampmMaker.y", 0);
            int width = prefs.getInt(name1 + ".stampmMaker.width", 0);
            int height = prefs.getInt(name1 + ".stampmMaker.height", 0);

            if (width == 0 || height == 0) {
                // センタリングする
                pack();
                Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
                int x = (screen.width - getWidth()) / 2;
                int y = (screen.height - getHeight()) / 2;
                setLocation(x, y);
            } else {
                setLocation(locX, locY);
                setSize(width, height);
            }

            setVisible(true);
            editing = true;
            toolBtn.setToolTipText("スタンプメーカを終了します");
            publishBtn.setEnabled(false);
            importBtn.setEnabled(false);
        }
    }

    /**
     * スタンプメーカを終了する。
     */
    private void stopStampMake() {
        Dimension dim = new Dimension(350, 690);
        setMinimumSize(dim);

        if (editing) {
            // 現在の大きさと位置をPreferenceに保存ずる
            Preferences prefs = Preferences.userNodeForPackage(this.getClass());
            String name1 = this.getClass().getName();
            prefs.putInt(name1 + ".stampmMaker.x", getLocation().x);
            prefs.putInt(name1 + ".stampmMaker.y", getLocation().y);
            prefs.putInt(name1 + ".stampmMaker.width", getWidth());
            prefs.putInt(name1 + ".stampmMaker.height", getHeight());

            editors.close();
            editors.removePropertyChangeListener(IStampEditorDialog.EDITOR_VALUE_PROP, editorValueListener);
            List<StampTree> allTrees = userBox.getAllTrees();
            for (StampTree st : allTrees) {
                st.removeTreeSelectionListener(editors);
            }

            content.removeAll();
            content.add(stampBoxPanel, BorderLayout.CENTER);

            editors = null;
            editorValueListener = null;
            userBox.setHasNoEditorEnabled(true);
            content.revalidate();
            setLocation(stampBoxLoc);
            setSize(new Dimension(stampBoxWidth, stampBoxHeight));
            editing = false;
            toolBtn.setToolTipText("スタンプメーカを起動します");
            publishBtn.setEnabled(true);
            importBtn.setEnabled(true);

            enabledImportBox(true); // ASP ボックスを選択可にする
        }
    }

    /**
     * EditorValueListener
     * INFORMATION エディタで作成したスタンプをStampTreeに加える。
     */
    class EditorValueListener implements PropertyChangeListener {

        @SuppressWarnings("unchecked")
        @Override
        public void propertyChange(PropertyChangeEvent e) {
            Object obj = e.getNewValue();
            if (obj != null && obj instanceof ModuleModel) {
                ModuleModel stamp = (ModuleModel) obj;
                String entity = stamp.getModuleInfo().getEntity();
                StampTree tree = userBox.getStampTree(entity);
                try {
                    tree.addStamp(stamp, null);
                } catch (SQLException ex) {
                    LogWriter.error(getClass(), ex);
                }
                tree.saveStampTree();

            } else if (obj != null && obj instanceof ArrayList) {
                // 傷病名
                StampTree tree = getStampTree(IInfoModel.ENTITY_DIAGNOSIS);
                try {
                    tree.addDiagnosis((List<RegisteredDiagnosisModel>) obj);
                } catch (SQLException ex) {
                    LogWriter.error(getClass(), ex);
                }
            }
        }
    }

    /**
     * スタンプパブリッシャーを起動する。
     * Reflect
     */
    private void publishStamp() {
        StampPublisher publisher = new StampPublisher(this);
        publisher.start();
    }

    /**
     * スタンプインポーターを起動する。
     * Reflect
     */
    private void importStamp() {
        StampImporter importer = new StampImporter(this);
        importer.start();
    }

    /**
     *
     */
    private void exportStampToFile() {
        FileOpenDialog dialog1 = new FileOpenDialog(this, "", FileOpenDialog.SAVE, "stamp");
        FileFilter filter = new FileNameExtensionFilter("スタンプファイル", "stamp");
        dialog1.addChoosableFileFilter(filter);
        if (dialog1.open() == FileOpenDialog.APPROVE_OPTION) {
            try {
                final RemoteStampDelegater delegator = new RemoteStampDelegater();
                FileTool.stringToFile(dialog1.getPath(), StampConverter.buildStampXml(delegator, getStampTree()), "UTF-8");
                JOptionPane.showMessageDialog(null, "ファイル'" + dialog1.getPath() + "'をエクスポートしました。", "確認", JOptionPane.INFORMATION_MESSAGE);
            } catch (IOException ex) {
                //     LogWriter.error(getClass(), null, ex);
            }
        }
    }

    /**
     *
     */
    private void importStampFromFile() {

        FileOpenDialog dialog = new FileOpenDialog(this, "", FileOpenDialog.LOAD, "stamp");
        FileFilter filter = new FileNameExtensionFilter("スタンプファイル", "stamp");
        dialog.addChoosableFileFilter(filter);
        if (dialog.open() == FileOpenDialog.APPROVE_OPTION) {
            if (JOptionPane.showConfirmDialog(null, "ファイル'" + dialog.getPath() + "'をインポートします。"+ System.getProperty("line.separator") +"現在のスタンプは全て置き換えられます。よろしいですか？", "確認", JOptionPane.YES_NO_OPTION) == 0) {
                try {
                    final RemoteStampDelegater delegator = new RemoteStampDelegater();
                    importStampXml(delegator, FileTool.fileToString(dialog.getPath(), "UTF-8"));
                    JOptionPane.showMessageDialog(null, "スタンプのインポート後はOpenDolphinを再起動してください。");
                } catch (SAXException ex) {
                    JOptionPane.showMessageDialog(null, "ファイル'" + dialog.getPath() + "'はスタンプファイルではないようです。" + System.getProperty("line.separator") + ex.getMessage(), "スタンプファイルフォーマットエラー", JOptionPane.ERROR_MESSAGE);
                } catch (TransformerException ex) {
                    JOptionPane.showMessageDialog(null, "インポートしたファイルの XML のフォーマットが不正です。" + System.getProperty("line.separator") + ex.getMessage(), "スタンプファイルフォーマットエラー", JOptionPane.ERROR_MESSAGE);
                } catch (IOException ex) {
                    LogWriter.error(getClass(), ex);
                }
            }
        }
    }

    /**
     * 公開されているスタンプTreeをインポートする。
     * @param importTree インポートする公開Tree
     */
    public void importPublishedTree(IStampTreeModel importTree) {

        String st = importTree.getName();
        for (int i = 0; i < parentBox.getComponentCount(); i++) {
            String tst = parentBox.getTitleAt(i);
            if (st.equals(tst)) {
                return;
            }
        }

        AbstractStampBox aspBox = new AspStampBox(this, importTree);// Asp StampBox を生成し parentBox に加える
        parentBox.addTab(importTree.getName(), aspBox);
        importedTreeList.add(new Long(importTree.getId()));// インポートリストに追加する
    }

    /**
     * インポートしている公開Treeを削除する。
     * @param removeId 削除する公開TreeのId
     */
    public void removeImportedTree(long removeId) {
        if (importedTreeList != null) {
            for (int i = 0; i < importedTreeList.size(); i++) {
                Long id = importedTreeList.get(i);
                if (id.longValue() == removeId) {
                    parentBox.removeTabAt(i + IMPORT_TREE_OFFSET);
                    importedTreeList.remove(i);
                    break;
                }
            }
        }
    }

    /**
     * プログラムを終了する。
     */
    @Override
    public void stop() {
        setVisible(false);
        dispose();
    }

    /**
     * フレームを前面に出す。
     */
    @Override
    public void enter() {

        toFront();

    }

    /**
     * @return
     */
    @Override
    /*
     * スタンプのセーブ
     * INFORMATION スタンプをどのように保存してるか確認する場合はここ。
     */
    public Callable<Boolean> getStoppingTask() {

        Preferences prefs = Preferences.userNodeForPackage(this.getClass());
        String name1 = (StampBoxFrame.this).getClass().getName();

        // StampMeker modeで終了した場合、
        // 次回起動時に通常モードの位置と大きさで表示するため
        if (editing) {
            prefs.putInt(name1 + "_x", stampBoxLoc.x);
            prefs.putInt(name1 + "_y", stampBoxLoc.y);
            prefs.putInt(name1 + "_width", stampBoxWidth);
            prefs.putInt(name1 + "_height", stampBoxHeight);
        }

        // 終了時のタブ選択インデックスを保存する
        prefs.putInt(name1 + "_parentBox", parentBox.getSelectedIndex());
        prefs.putInt(name1 + "_stampBox", userBox.getSelectedIndex());

        // 個人用のStampTreeModelにXMLをセットする
        final IStampTreeModel treeModel = userBox.getStampTreeModel();
        String treeXml = getStampTree();
        treeModel.setTreeXml(treeXml);

        // StampTree を保存する Callable Object を生成する
        Callable<Boolean> longTask = new Callable<Boolean>() {

            @Override
            public Boolean call() {
                return saveStampTreeModel(treeModel);
            }
        };
        return longTask;
    }

    /**
     * 引数に指定したStampTreeModelをデータベースに保存する
     * @param treeModel
     * @return 成功で true, 失敗で false が返る
     */
    private Boolean saveStampTreeModel(IStampTreeModel treeModel) {

        RemoteStampDelegater stampDel = new RemoteStampDelegater();
        stampDel.putTree(treeModel);
        boolean result = !stampDel.isError();
        return new Boolean(result);
    }

    /**
     * 引数のカテゴリに対応するTreeを返す。
     * @param entity
     * @return カテゴリにマッチするStampTree
     */
    public StampTree getStampTree(String entity) {
        return getCurrentBox().getStampTree(entity);
    }

    /**
     *
     * @param entity
     * @return
     */
    public StampTree getStampTreeFromUserBox(String entity) {
        return getUserStampBox().getStampTree(entity);
    }

    /**
     * スタンプボックスに含まれる全treeを返す。
     * @return StampTreeのリスト
     */
    public List<StampTree> getAllTrees() {
        return getCurrentBox().getAllTrees();
    }

    /**
     * Currentボックスの P 関連Staptreeを返す。
     * @return StampTreeのリスト
     */
    public List<StampTree> getAllPTrees() {

        AbstractStampBox stb = (AbstractStampBox) getCurrentBox();
        return stb.getAllPTrees();
    }

    /**
     * 引数のエンティティ配下にある全てのスタンプを返す。
     * これはメニュー等で使用する。
     * @param entity Treeのエンティティ
     * @return 全てのスタンプのリスト
     */
    private StampTreeModel createStampTreeModel(String stampXml) {

        FacilityModel facility = GlobalVariables.getUserModel().getFacility();
        StampTreeModel result = new StampTreeModel();
        result.initialize(GlobalVariables.getUserModel(), "個人用", "個人用のスタンプセットです", facility.getFacilityName(), facility.getUrl(), stampXml);
        //result.initialize(Project.getUserModel(),GlobalVariables.getString("stampTree.personal.box.name"),GlobalVariables.getString("stampTree.personal.box.tooltip"),facility.getFacilityName(),facility.getUrl(),stampXml);
        return result;
    }

    private String getSeedStamp() {

        String result = "";
        try {
            InputStream seedStamp = GlobalConstants.getResourceAsStream("stamptree-seed.xml");
            result = FileTool.streamToString(seedStamp, "UTF-8");
            seedStamp.close();
        } catch (IOException ex) {
           LogWriter.error(getClass(), ex);
        }
        return result;
    }

    /*
     * INFORMATION スタンプをあらわすＸＭＬを設定する。
     */
    private void importStampXml(RemoteStampDelegater delegator, String stampSetXml)
            throws SAXException, IOException, TransformerException {

        List<Pair<Pair<String, String>, String>> stamps = StampConverter.extractStamps(stampSetXml);

        delegator.cleanStamp(GlobalVariables.getUserModel().getId());

        HashMap convertIdMap = new HashMap<String, String>();
        for (int index = 0; index < stamps.size(); index++) {
            Pair<Pair<String, String>, String> stamp = stamps.get(index);
            String newId = delegator.newStamp(stamp.key.value, stamp.value);
            if (!newId.equals(stamp.key.key)) {
                convertIdMap.put(stamp.key.key, newId);
            }
        }

        String originalTreeXml = StampConverter.extractStampTree(stampSetXml);
        String stampTreeXml = StampConverter.changeStampIds(originalTreeXml, convertIdMap);


        // 個人用のStampTreeModelにXMLをセットする
        final IStampTreeModel model = userBox.getStampTreeModel();
        model.setTreeXml(stampTreeXml);
        userBox = new UserStampBox(this, model); // 個人用のスタンプボックス(JTabbedPane)を生成する
        userBox.setTransferHandler(new TabTransferHandler());// 個人用のスタンプボックス(JTabbedPane)を生成する
        for (int index = parentBox.getTabCount() - 1; index >= 0; index--) {
            if (parentBox.getTitleAt(index).equals("個人用")) {
                parentBox.setComponentAt(index, userBox);
                userBox.addChangeListener(new TabChangeListener());
            }
        }
    }

    public String getStampTree() {

        // User Tree のみを保存する
        List<StampTree> list = (List<StampTree>) userBox.getAllTrees();
        if (list == null || list.isEmpty()) {
            return "";
        }

        // ORCA セットは除く
        for (StampTree tree : list) {
            if (tree.getTreeInfo().getEntity().equals(IInfoModel.ENTITY_ORCA)) {
                list.remove(tree);
                break;
            }
        }

        DefaultStampTreeXmlBuilder builder = new DefaultStampTreeXmlBuilder();
        StampTreeXmlDirector director = new StampTreeXmlDirector(builder);
        return director.build(list);
    }
}
