/*
 * PatientSearchView.java
 *
 * Created on 2007/11/22, 18:43
 */
package open.dolphin.client.patientsearch;

import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import java.beans.EventHandler;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.prefs.Preferences;

import javax.swing.event.ListSelectionEvent;
import javax.swing.AbstractAction;
import javax.swing.JCheckBox;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionListener;

import org.jdesktop.application.Application;
import org.jdesktop.application.ApplicationContext;
import org.jdesktop.application.Task;
import org.jdesktop.application.Task.InputBlocker;
import org.jdesktop.application.TaskMonitor;

import open.dolphin.client.AutoKanjiListener;
import open.dolphin.client.AutoRomanListener;
import open.dolphin.client.BlockGlass;
import open.dolphin.client.CalendarCardPanel;
import open.dolphin.client.Dolphin.MenuMediator;
import open.dolphin.client.GUIConst;
import open.dolphin.client.IMainComponent;
import open.dolphin.client.IMainWindow;

import open.dolphin.infomodel.AllergyModel;
import open.dolphin.infomodel.DocInfoModel;
import open.dolphin.infomodel.DocumentModel;
import open.dolphin.infomodel.KarteBean;
import open.dolphin.infomodel.ModelUtils;
import open.dolphin.infomodel.ModuleModel;
import open.dolphin.infomodel.PatientMemoModel;
import open.dolphin.infomodel.PatientModel;
import open.dolphin.infomodel.PatientVisitModel;
import open.dolphin.infomodel.SimpleDate;

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

import open.dolphin.delegater.remote.RemoteDocumentDelegater;
import open.dolphin.delegater.remote.RemotePatientDelegater;
import open.dolphin.delegater.remote.RemotePVTDelegater;

import open.dolphin.table.ObjectReflectTableModel;
import open.dolphin.table.OddEvenRowRenderer;

import open.dolphin.utils.CombinedStringParser;
import open.dolphin.utils.StringTool;

import open.dolphin.dto.PatientSearchSpec;

import open.dolphin.helper.KeyBlocker;

import open.dolphin.queries.DolphinQuery;

import open.dolphin.log.LogWriter;

/**
 * 患者検索画面　MEMO:画面
 * @author  kazushi
 */
public class PatientSearchView extends javax.swing.JPanel implements IMainComponent {

    private String name;
    private String icon;
    private IMainWindow context;
    private int number = 10000;
    private final String NAME = "患者検索";
    private final String[] COLUMN_NAMES = {"ID", "氏名", "カナ", "性別", "生年月日"};
    private final int START_NUM_ROWS = 0;
    private final String[] METHOD_NAMES = {"getPatientId", "getFullName", "getKanaName", "getGenderDesc", "getAgeBirthday"};
    private final int[] COLUMN_WIDTH = {80, 120, 120, 30, 80};
    private final String UNSUITABLE_CHAR = "検索に適さない文字が含まれています。";
    private PatientModel selectedPatient;// 選択されている患者情報
    private boolean isAgeDisplayed; // 年齢表示
    private final int AGE_COLUMN = 4; // 年齢表示カラム
    private final String[] AGE_METHOD = new String[]{"getAgeBirthday", "getBirthday"};  // 年齢生年月日メソッド
    private KeyBlocker keyBlocker;
    private int sortItemValue;
    private Application app;
    private ApplicationContext appCtx;
    private TaskMonitor taskMonitor;
    private boolean synchronize_search;

    /** 
     * Creates new form PatientSearchView
     */
    public PatientSearchView() {
        initComponents();
        jScrollPane1.getViewport().setBackground(GlobalSettings.getColors(GlobalSettings.Parts.TABLE_BACKGROUND));
        this.name = NAME;
        appCtx = GlobalConstants.getApplicationContext();
        app = appCtx.getApplication();
        taskMonitor = appCtx.getTaskMonitor();
        synchronize_search = GlobalSettings.isSynchronizePatientSearchView();
    }

    /** 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.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        table = new AddressTipsTable();
        keywordFld = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        jPanel1 = new javax.swing.JPanel();
        progressBar = new javax.swing.JProgressBar();
        cntLbl = new javax.swing.JLabel();
        jPanel2 = new javax.swing.JPanel();
        dateLbl = new javax.swing.JLabel();
        jLabel1 = new javax.swing.JLabel();
        sortItem = new javax.swing.JComboBox();
        autoIme = new javax.swing.JCheckBox();
        historySearchButton = new javax.swing.JButton();
        memoSearchButton = new javax.swing.JButton();
        allergySearchButton = new javax.swing.JButton();
        karteSearchButton = new javax.swing.JButton();

        table.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null}
            },
            new String [] {
                "Title 1", "Title 2", "Title 3", "Title 4"
            }
        ));
        jScrollPane1.setViewportView(table);

        keywordFld.setToolTipText("ID等の一部、患者氏名、右クリックで来院日を入力してください."); // NOI18N

        jPanel1.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT, 5, 0));

        progressBar.setMaximumSize(new java.awt.Dimension(100, 14));
        progressBar.setMinimumSize(new java.awt.Dimension(100, 14));
        progressBar.setPreferredSize(new java.awt.Dimension(100, 14));
        jPanel1.add(progressBar);

        cntLbl.setFont(new java.awt.Font("Lucida Grande", 0, 10));
        cntLbl.setText("0 件");
        jPanel1.add(cntLbl);

        jPanel2.setBorder(new javax.swing.border.SoftBevelBorder(javax.swing.border.BevelBorder.RAISED));
        jPanel2.setMaximumSize(new java.awt.Dimension(2, 12));
        jPanel2.setMinimumSize(new java.awt.Dimension(2, 12));
        jPanel2.setPreferredSize(new java.awt.Dimension(2, 12));

        org.jdesktop.layout.GroupLayout jPanel2Layout = new org.jdesktop.layout.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(0, 0, Short.MAX_VALUE)
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(0, 6, Short.MAX_VALUE)
        );

        jPanel1.add(jPanel2);

        dateLbl.setFont(new java.awt.Font("Lucida Grande", 0, 10));
        dateLbl.setText("2007-11-26(日)");
        jPanel1.add(dateLbl);

        jLabel1.setText("ソート:");

        sortItem.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "患者ID", "カナ" }));

        autoIme.setText("自動IME");

        historySearchButton.setFont(new java.awt.Font("MS UI Gothic", 0, 10));
        historySearchButton.setText("履歴");
        historySearchButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                historySearchButtonActionPerformed(evt);
            }
        });

        memoSearchButton.setFont(new java.awt.Font("MS UI Gothic", 0, 10));
        memoSearchButton.setText("メモ");
        memoSearchButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                memoSearchButtonActionPerformed(evt);
            }
        });

        allergySearchButton.setFont(new java.awt.Font("MS UI Gothic", 0, 10));
        allergySearchButton.setText("アレルギー");
        allergySearchButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                allergySearchButtonActionPerformed(evt);
            }
        });

        karteSearchButton.setFont(new java.awt.Font("MS UI Gothic", 0, 10)); // NOI18N
        karteSearchButton.setText("カルテ内容");
        karteSearchButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                karteSearchButtonActionPerformed(evt);
            }
        });

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, jPanel1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 706, Short.MAX_VALUE)
                    .add(layout.createSequentialGroup()
                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                            .add(jLabel2)
                            .add(org.jdesktop.layout.GroupLayout.LEADING, layout.createSequentialGroup()
                                .add(jLabel1)
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                .add(sortItem, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 70, Short.MAX_VALUE)
                        .add(keywordFld, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 164, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(autoIme)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(historySearchButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 69, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(memoSearchButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 65, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(allergySearchButton)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(karteSearchButton)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(jLabel2)
                    .add(sortItem, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(jLabel1)
                    .add(karteSearchButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 22, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(allergySearchButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 22, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(memoSearchButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 22, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(historySearchButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 22, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(autoIme)
                    .add(keywordFld, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .add(7, 7, 7)
                .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 284, Short.MAX_VALUE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED)
                .add(jPanel1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 20, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

    private void historySearchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_historySearchButtonActionPerformed
        if (!keywordFld.getText().isEmpty()) {
            if (synchronize_search) {
                app = GlobalConstants.getApplicationContext().getApplication();
                TitleSearchTask task = new TitleSearchTask(app);
                appCtx.getTaskService().execute(task);
            } else {
                SynchronizeTitleSearchTask task = new SynchronizeTitleSearchTask(app);
                task.execute();
            }
        }
    }//GEN-LAST:event_historySearchButtonActionPerformed

    private void memoSearchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_memoSearchButtonActionPerformed
        if (!keywordFld.getText().isEmpty()) {
            if (synchronize_search) {
                app = GlobalConstants.getApplicationContext().getApplication();
                MemoSearchTask task = new MemoSearchTask(app);
                appCtx.getTaskService().execute(task);
            } else {
                SynchronizeMemoSearchTask task = new SynchronizeMemoSearchTask(app);
                task.execute();
            }
        }
    }//GEN-LAST:event_memoSearchButtonActionPerformed

    private void allergySearchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_allergySearchButtonActionPerformed
        if (!keywordFld.getText().isEmpty()) {
            if (synchronize_search) {
                app = GlobalConstants.getApplicationContext().getApplication();
                AllergySearchTask task = new AllergySearchTask(app);
                appCtx.getTaskService().execute(task);
            } else {
                SynchronizeAllergySearchTask task = new SynchronizeAllergySearchTask(app);
                task.execute();
            }
        }
    }//GEN-LAST:event_allergySearchButtonActionPerformed

    private void karteSearchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_karteSearchButtonActionPerformed
        if (!keywordFld.getText().isEmpty()) {
            if (synchronize_search) {
                app = GlobalConstants.getApplicationContext().getApplication();
                KarteSearchTask task = new KarteSearchTask(app);
                appCtx.getTaskService().execute(task);
            } else {
                SynchronizeKarteSearchTask task = new SynchronizeKarteSearchTask(app);
                task.execute();
            }
        }
    }//GEN-LAST:event_karteSearchButtonActionPerformed
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton allergySearchButton;
    private javax.swing.JCheckBox autoIme;
    private javax.swing.JLabel cntLbl;
    private javax.swing.JLabel dateLbl;
    private javax.swing.JButton historySearchButton;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JButton karteSearchButton;
    private javax.swing.JTextField keywordFld;
    private javax.swing.JButton memoSearchButton;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JComboBox sortItem;
    private javax.swing.JTable table;
    // End of variables declaration//GEN-END:variables

    /**
     *
     *
     */
    private int getSelectedRow(JTable table) {
        int result = table.getSelectedRow();
        if (result >= 0 && result < table.getRowCount()) {
            result = table.convertRowIndexToModel(result);
        }
        return result;
    }

    /**
     *
     *
     */
    @Override
    public void start() {
        initCustomComponents();
        connect();
        enter();
    }

    /**
     *
     *
     */
    @Override
    public void enter() {
        controlMenu();
    }

    /**
     *
     *
     */
    @Override
    public void stop() {
    }

    /**
     *
     * @return
     */
    public PatientModel getSelectedPatinet() {
        return selectedPatient;
    }

    /**
     *
     * @param model
     */
    public void setSelectedPatinet(PatientModel model) {
        selectedPatient = model;
        controlMenu();
    }

    /**
     * 年齢表示をオンオフする。
     */
    public void switchAgeDisplay() {
        isAgeDisplayed = !isAgeDisplayed;
        Preferences preferences = Preferences.userNodeForPackage(this.getClass());
        preferences.putBoolean("ageDisplay", isAgeDisplayed);

        if (table != null) {
            ObjectReflectTableModel<PatientModel> tModel = (ObjectReflectTableModel<PatientModel>) table.getModel();
            String method = isAgeDisplayed ? AGE_METHOD[0] : AGE_METHOD[1];
            tModel.setMethodName(method, AGE_COLUMN);
        }
    }

    /**
     * メニューを制御する
     */
    private void controlMenu() {
        boolean enabled = canOpen(getSelectedPatinet());
        getContext().enabledAction(GUIConst.ACTION_OPEN_KARTE, enabled);
    }

    /**
     * カルテを開くことが可能かどうかを返す。
     * @return 開くことが可能な時 true
     */
    private boolean canOpen(PatientModel patient) {
        if (patient == null) {
            return false;
        }
        if (isKarteOpened(patient)) {
            return false;
        }
        return true;
    }

    /**
     * カルテがオープンされているかどうかを返す。
     * @return オープンされている時 true
     */
    private boolean isKarteOpened(PatientModel patient) {
        return context.isKarteOpened(patient.getId());
    }

    /**
     *
     *
     */
    @Override
    public boolean dispatchMainCommand(open.dolphin.helper.IMainCommandAccepter.MainCommand command) {
        switch (command) {
            case openKarte:
                return openKarte();
            default:
        }
        return false;
    }

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

        //
        // 年齢表示をしないなんて信じられない要望!
        // コンテナの型をObjectにしてアイテムをしまくるとは信じられない実装
        //
        Preferences preferences = Preferences.userNodeForPackage(this.getClass());
        isAgeDisplayed = preferences.getBoolean("ageDisplay", true);
        if (!isAgeDisplayed) {
            METHOD_NAMES[4] = AGE_METHOD[1];
        }

        ObjectReflectTableModel<PatientModel> tableModel = new ObjectReflectTableModel<PatientModel>(COLUMN_NAMES, START_NUM_ROWS, METHOD_NAMES, null);
        table.setModel(tableModel);
        table.setAutoCreateRowSorter(true);

        // カラム幅を変更する
        for (int i = 0; i < COLUMN_WIDTH.length; i++) {
            table.getColumnModel().getColumn(i).setPreferredWidth(COLUMN_WIDTH[i]);
        }

        // レンダラを設定する
        table.setDefaultRenderer(Object.class, new OddEvenRowRenderer());

        // 日付を設定する
        String formatStr = "yyyy-M-d(EEE)";
        SimpleDateFormat sdf = new SimpleDateFormat(formatStr);
        dateLbl.setText(sdf.format(new Date()));

        // ソートアイテム
        sortItemValue = preferences.getInt("sortItem", 0);
        sortItem.setSelectedIndex(sortItemValue);

        // Auto IME Windows の時のみ
        if (!GlobalConstants.isMac()) {
            autoIme.setSelected(preferences.getBoolean("autoIme", false));
        } else {
            autoIme.setEnabled(false);
        }
    }

    /**
     * コンポーンントにリスナを登録し接続する。
     */
    private void connect() {

        EventAdapter adp = new EventAdapter(keywordFld, table);//MEMO: unused?

        // 自動IME ボタン
        autoIme.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JCheckBox check = (JCheckBox) e.getSource();
                boolean selected = check.isSelected();
                Preferences preferences = Preferences.userNodeForPackage(this.getClass());
                preferences.putBoolean("autoIme", selected);
                if (selected) {
                    keywordFld.addFocusListener(AutoKanjiListener.getInstance());
                } else {
                    keywordFld.addFocusListener(AutoRomanListener.getInstance());
                }
            }
        });

        // Sort アイテム
        sortItem.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    JComboBox cb = (JComboBox) e.getSource();
                    sortItemValue = cb.getSelectedIndex();
                    Preferences preferences = Preferences.userNodeForPackage(this.getClass());
                    preferences.putInt("sortItem", sortItemValue);
                }
            }
        });

        // カレンダによる日付検索を設定する
        PopupListener pl = new PopupListener(keywordFld);//MEMO: unused?
        // コンテキストメニューを設定する
        table.addMouseListener(new ContextListener());
        keyBlocker = new KeyBlocker(keywordFld);
    }

    /**
     *
     *
     */
    private String constractDept() {
        CombinedStringParser line = new CombinedStringParser(',');
        line.set(0, GlobalVariables.getUserModel().getDepartmentModel().getDepartmentDesc());
        line.set(1, GlobalVariables.getUserModel().getDepartmentModel().getDepartment());
        line.set(2, GlobalVariables.getUserModel().getCommonName());
        line.set(3, GlobalVariables.getUserModel().getUserId());
        line.set(4, GlobalVariables.getJMARICode());
        line.set(5, "");
        return line.toCombinedString();
    }

    /**
     * カルテを開く。
     * @param value 対象患者
     */
    private boolean openKarte() {

        if (canOpen(getSelectedPatinet())) {
            // 来院情報を生成する
            PatientVisitModel pvt = new PatientVisitModel();
            pvt.setId(0L);
            pvt.setNumber(number);
            number++;
            pvt.setPatient(getSelectedPatinet());
            // Combined
            // 受け付けを通していないのでログイン情報及び設定ファイルを使用する
            // 診療科名、診療科コード、医師名、医師コード、JMARI
            pvt.setDepartment(constractDept());
            // カルテコンテナを生成する
            getContext().openKarte(pvt, keywordFld.getText());
        }
        return true;
    }

    /**
     *
     *
     */
    private KarteBean getKarteBean(PatientModel patient) {
        PatientVisitModel pvt = new PatientVisitModel();
        pvt.setId(0L);
        pvt.setNumber(number);
        number++;
        pvt.setPatient(patient);
        pvt.setDepartment(constractDept());
        int past = GlobalVariables.getPreferences().getInt(GlobalVariables.DOC_HISTORY_PERIOD, -12);
        GregorianCalendar today = new GregorianCalendar();
        today.add(GregorianCalendar.MONTH, past);
        today.clear(Calendar.HOUR_OF_DAY);
        today.clear(Calendar.MINUTE);
        today.clear(Calendar.SECOND);
        today.clear(Calendar.MILLISECOND);
        RemoteDocumentDelegater ddl = new RemoteDocumentDelegater();
        KarteBean karteBean = ddl.getKarte(pvt.getPatient().getId(), today.getTime());
        return karteBean;
    }

    /**
     * リストで選択された患者を受付に登録する。
     */
    public synchronized void addAsPvt() {

        // 来院情報を生成する
        PatientVisitModel pvt = new PatientVisitModel();
        pvt.setId(0L);
        pvt.setNumber(number);
        number++;
        pvt.setPatient(getSelectedPatinet());

        //CombinedString
        // 受け付けを通していないので診療科はユーザ登録してあるものを使用する
        pvt.setDepartment(constractDept());

        // 来院日
        pvt.setPvtDate(ModelUtils.getDateTimeAsString(new Date()));

        app = GlobalConstants.getApplicationContext().getApplication();
        taskMonitor = GlobalConstants.getApplicationContext().getTaskMonitor();

        AddAsPvtTask task = new AddAsPvtTask(app, pvt);
        MyInputBlocker blocker = new MyInputBlocker(task, getContext().getGlassPane(), keyBlocker);
        task.setInputBlocker(blocker);

        StatusMonitor bar = new StatusMonitor(task, taskMonitor, progressBar);//MEMO: unused?
        GlobalConstants.getApplicationContext().getTaskService().execute(task);
    }

    /**
     * 検索条件を作成する。
     * @param text キーワード
     * @return
     */
    public PatientSearchSpec createSpec(String text) {

        PatientSearchSpec spec = new PatientSearchSpec();
        if (text.equals("")) {
            spec.setCode(PatientSearchSpec.ALL_SEARCH);
        } else if (text.startsWith("N ") || text.startsWith("n ")) {
            spec.setCode(PatientSearchSpec.NAME_SEARCH);
            text = text.substring(2);
            spec.setName(text);
        } else if (text.startsWith("K ") || text.startsWith("k ")) {
            spec.setCode(PatientSearchSpec.KANA_SEARCH);
            text = text.substring(2);
            spec.setName(text);
        } else if (text.startsWith("A ") || text.startsWith("a ")) {
            spec.setCode(PatientSearchSpec.ADDRESS_SEARCH);
            text = text.substring(2);
            spec.setAddress(text);
        } else if (text.startsWith("Z ") || text.startsWith("z ")) {
            spec.setCode(PatientSearchSpec.ZIPCODE_SEARCH);
            text = text.substring(2);
            spec.setZipCode(text);
        } else if (text.startsWith("T ") || text.startsWith("t ")) {
            spec.setCode(PatientSearchSpec.TELEPHONE_SEARCH);
            text = text.substring(2);
            spec.setTelephone(text);
        } else if (text.startsWith("I ") || text.startsWith("i ")) {
            spec.setCode(PatientSearchSpec.ID_SEARCH);
            text = text.substring(2);
            spec.setPatientId(text);
        } else if (text.startsWith("E ") || text.startsWith("e ")) {
            spec.setCode(PatientSearchSpec.EMAIL_SEARCH);
            text = text.substring(2);
            spec.setEmail(text);
        } else if (text.startsWith("O ") || text.startsWith("o ")) {
            spec.setCode(PatientSearchSpec.OTHERID_SEARCH);
            text = text.substring(2);
            spec.setOtherId(text);
        } else if (isDate(text)) {
            spec.setCode(PatientSearchSpec.DATE_SEARCH);
            spec.setDigit(text);
        } else if (isKana(text)) {
            spec.setCode(PatientSearchSpec.KANA_SEARCH);
            spec.setName(text);
        } else if (isNameAddress(text)) {
            spec.setCode(PatientSearchSpec.NAME_SEARCH);
            spec.setName(text);
        } else if (isTelephoneZip(text)) {
            text = text.trim();
            int i = text.length();
            if (i < 5) {
                StringBuffer sb = new StringBuffer();
                int j = 5 - i;
                for (int k = 0; k < j; ++k) {
                    sb.append(new String("0"));
                }
                sb.append(text);
                text = sb.toString();
            }

            spec.setCode(PatientSearchSpec.DIGIT_SEARCH);
            spec.setDigit(text);

        } else if (isId(text)) {
            text = text.trim();
            int i = text.length();
            if (i < 5) {
                StringBuilder sb = new StringBuilder();
                int j = 5 - i;
                for (int k = 0; k < j; ++k) {
                    sb.append(new String("0"));
                }
                sb.append(text);
                text = sb.toString();
            }

            spec.setCode(PatientSearchSpec.ID_SEARCH);
            spec.setPatientId(text);

        } else {
            spec = null;
        }

        return spec;
    }

    /**
     * 検索を実行する。
     * @param text キーワード
     */
    private void find(String text) {

        PatientSearchSpec spec = createSpec(text);

        if (spec == null) {
            String msg = UNSUITABLE_CHAR;
            JOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(this), msg, getName(), JOptionPane.WARNING_MESSAGE);
            return;
        }

        app = GlobalConstants.getApplicationContext().getApplication();
        taskMonitor = GlobalConstants.getApplicationContext().getTaskMonitor();

        FindTask task = new FindTask(app, spec);
        MyInputBlocker blocker = new MyInputBlocker(task, getContext().getGlassPane(), keyBlocker);
        task.setInputBlocker(blocker);

        StatusMonitor bar = new StatusMonitor(task, taskMonitor, progressBar);//MEMO: unused?
        appCtx.getTaskService().execute(task);
    }

    /**
     *
     *
     */
    private boolean isDate(String text) {
        boolean maybe = false;
        if (text != null) {
            try {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                sdf.parse(text);
                maybe = true;
            } catch (ParseException e) {
                LogWriter.error(getClass(), e);
            }
        }
        return maybe;
    }

    /**
     *
     *
     */
    private boolean isKana(String text) {
        boolean maybe = true;
        if (text != null) {
            for (int i = 0; i < text.length(); i++) {
                char c = text.charAt(i);
                if (!StringTool.isKatakana(c)) {
                    maybe = false;
                    break;
                }
            }
            return maybe;
        }

        return false;
    }

    /**
     *
     *
     */
    private boolean isNameAddress(String text) {
        boolean maybe = false;
        if (text != null) {
            for (int i = 0; i < text.length(); i++) {
                char c = text.charAt(i);
                if (Character.getType(c) == Character.OTHER_LETTER) {
                    maybe = true;
                    break;
                }
            }
        }
        return maybe;
    }

    /**
     *
     *
     */
    private boolean isId(String text) {
        boolean maybe = true;
        if (text != null) {
            for (int i = 0; i < text.length(); i++) {
                char c = text.charAt(i);
                int type = Character.getType(c);
                if (type == Character.UPPERCASE_LETTER
                        || type == Character.LOWERCASE_LETTER
                        || type == Character.DECIMAL_DIGIT_NUMBER) {
                    continue;
                } else {
                    maybe = false;
                    break;
                }
            }
            return maybe;
        }
        return false;
    }

    /**
     *
     *
     */
    private boolean isTelephoneZip(String text) {
        boolean maybe = true;
        if (text != null) {
            for (int i = 0; i < text.length(); i++) {
                char c = text.charAt(i);
                int type = Character.getType(c);
                if (type == Character.DECIMAL_DIGIT_NUMBER
                        || c == '-'
                        || c == '('
                        || c == ')') {
                    continue;
                } else {
                    maybe = false;
                    break;
                }
            }
            return maybe;
        }
        return false;
    }

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

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

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

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

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

    /**
     *
     *
     * @param context
     */
    @Override
    public void setContext(IMainWindow context) {
        this.context = context;
    }

    /**
     *
     *
     * @return 
     */
    @Override
    public Callable<Boolean> getStartingTask() {
        return null;
    }

    /**
     *
     *
     * @return
     */
    @Override
    public Callable<Boolean> getStoppingTask() {
        return null;
    }

    /**
     *
     * @param midiator
     */
    @Override
    public void setMenu(MenuMediator midiator) {
    }

    /**
     * 受付リストのコンテキストメニュークラス。
     */
    class ContextListener extends MouseAdapter {

        /**
         *
         * @param e
         */
        @Override
        public void mousePressed(MouseEvent e) {
            mabeShowPopup(e);
        }

        /**
         *
         * @param e
         */
        @Override
        public void mouseReleased(MouseEvent e) {
            mabeShowPopup(e);
        }

        /**
         *
         * @param e
         */
        public void mabeShowPopup(MouseEvent e) {

            if (e.isPopupTrigger()) {

                final JPopupMenu contextMenu = new JPopupMenu();
                int row = table.rowAtPoint(e.getPoint());


                Object obj = ((ObjectReflectTableModel<PatientModel>) table.getModel()).getObject(table.convertRowIndexToModel(row));

                //     Object obj = ((ObjectReflectTableModel<PatientModel>) table.getModel()).getObject(row);

                int selected = ((JTable) e.getSource()).getSelectedRow();
                if (row == selected && obj != null) {
                    contextMenu.add(new JMenuItem(
                            new AbstractAction("カルテを開く") {

                                @Override
                                public void actionPerformed(ActionEvent e) {
                                    openKarte();
                                }
                            }));
                    contextMenu.add(new JMenuItem(
                            new AbstractAction("受付登録") {

                                @Override
                                public void actionPerformed(ActionEvent e) {
                                    addAsPvt();
                                }
                            }));
                }

                JCheckBoxMenuItem item = new JCheckBoxMenuItem("年齢表示");
                contextMenu.add(item);
                item.setSelected(isAgeDisplayed);
                item.addActionListener((ActionListener) EventHandler.create(ActionListener.class, PatientSearchView.this, "switchAgeDisplay"));
                contextMenu.show(e.getComponent(), e.getX(), e.getY());
            }
        }
    }

    /**
     *
     */
    class EventAdapter implements ActionListener, ListSelectionListener, MouseListener {

        /**
         *
         * @param tf
         * @param tbl
         */
        public EventAdapter(JTextField tf, JTable tbl) {

            tf.addActionListener(this);

            tf.addFocusListener(AutoKanjiListener.getInstance());

            tbl.getSelectionModel().addListSelectionListener(this);
            tbl.addMouseListener(this);
        }

        /**
         *
         * @param e
         */
        @Override
        public void actionPerformed(ActionEvent e) {
            JTextField tf = (JTextField) e.getSource();
            String test = tf.getText().trim();
            find(test);
        }

        /**
         *
         * @param e
         */
        @Override
        public void valueChanged(ListSelectionEvent e) {
            if (e.getValueIsAdjusting() == false) {
                ObjectReflectTableModel<PatientModel> tableModel = (ObjectReflectTableModel<PatientModel>) table.getModel();
                setSelectedPatinet(tableModel.getObject(getSelectedRow(table)));
            }
        }

        /**
         *
         * @param e
         */
        @Override
        public void mouseClicked(MouseEvent e) {
            if (e.getClickCount() == 2) {
                JTable table = (JTable) e.getSource();
                ObjectReflectTableModel<PatientModel> tableModel = (ObjectReflectTableModel<PatientModel>) table.getModel();
                setSelectedPatinet(tableModel.getObject(getSelectedRow(table)));
                openKarte();
            }
        }

        /**
         *
         * @param arg0
         */
        @Override
        public void mousePressed(MouseEvent arg0) {
        }

        /**
         *
         * @param arg0
         */
        @Override
        public void mouseReleased(MouseEvent arg0) {
        }

        /**
         *
         * @param arg0
         */
        @Override
        public void mouseEntered(MouseEvent arg0) {
        }

        /**
         *
         * @param arg0
         */
        @Override
        public void mouseExited(MouseEvent arg0) {
        }
    }

    /**
     *
     */
    class AddAsPvtTask extends Task<Void, Void> {

        private PatientVisitModel pvt;

        /**
         *
         * @param app
         * @param pvt
         */
        public AddAsPvtTask(Application app, PatientVisitModel pvt) {
            super(app);
            this.pvt = pvt;
        }

        /**
         *
         * @return
         */
        @Override
        protected Void doInBackground() {
            RemotePVTDelegater pdl = new RemotePVTDelegater();
            pdl.addPvt(pvt);
            return null;
        }
    }

    /**
     *　MEMO:リスナー
     */
    class StatusMonitor implements PropertyChangeListener {

        private Task task;
        private TaskMonitor taskMonitor;
        private JProgressBar bar;

        /**
         *
         * @param task
         * @param taskMonitor
         * @param bar
         */
        public StatusMonitor(Task task, TaskMonitor taskMonitor, JProgressBar bar) {
            this.task = task;
            this.taskMonitor = taskMonitor;
            this.bar = bar;
            taskMonitor.addPropertyChangeListener(this);
        }

        /**
         *
         * @param e
         */
        @Override
        public void propertyChange(PropertyChangeEvent e) {

            String propertyName = e.getPropertyName();

            if ("started".equals(propertyName)) {
                bar.setIndeterminate(true);

            } else if ("done".equals(propertyName)) {
                bar.setIndeterminate(false);
                bar.setValue(0);
                taskMonitor.removePropertyChangeListener(this); // 重要
            }
        }
    }

    /**
     *
     */
    class FindTask extends Task<Collection, Void> {

        private PatientSearchSpec spec;

        /**
         *
         * @param app
         * @param spec
         */
        public FindTask(Application app, PatientSearchSpec spec) {
            super(app);
            this.spec = spec;
        }

        /**
         *
         * @return
         * @throws Exception
         */
        @Override
        protected List<PatientModel> doInBackground() throws Exception {
            RemotePatientDelegater pdl = new RemotePatientDelegater();
            List<PatientModel> result = pdl.getPatients(spec);
            return result;
        }

        /**
         *
         * @param result
         */
        @Override
        protected void succeeded(Collection result) {
            List<PatientModel> list = (List<PatientModel>) result;
            if (list != null && list.size() > 0) {
                switch (sortItemValue) {
                    case 0:
                        Comparator c = new Comparator<PatientModel>() {

                            @Override
                            public int compare(PatientModel p1, PatientModel p2) {
                                return p1.getPatientId().compareTo(p2.getPatientId());
                            }
                        };
                        Collections.sort(list, c);
                        break;
                    case 1:
                        Comparator c2 = new Comparator<PatientModel>() {

                            @Override
                            public int compare(PatientModel p1, PatientModel p2) {
                                String kana1 = p1.getKanaName();
                                String kana2 = p2.getKanaName();
                                if (kana1 != null && kana2 != null) {
                                    return p1.getKanaName().compareTo(p2.getKanaName());
                                } else if (kana1 != null && kana2 == null) {
                                    return -1;
                                } else if (kana1 == null && kana2 != null) {
                                    return 1;
                                } else {
                                    return 0;
                                }
                            }
                        };
                        Collections.sort(list, c2);
                        break;
                    default:
                        LogWriter.fatal(getClass(), "case default");
                }
            }

            ObjectReflectTableModel<PatientModel> tableModel = (ObjectReflectTableModel<PatientModel>) table.getModel();
            tableModel.setObjectList(list);
            int cnt = result != null ? result.size() : 0;
            String cntStr = String.valueOf(cnt);
            cntLbl.setText(cntStr + " 件");
        }

        /**
         *
         * @param cause
         */
        @Override
        protected void failed(Throwable cause) {
        }

        /**
         *
         */
        @Override
        protected void cancelled() {
        }
    }

    /**
     *
     */
    class SynchronizeTitleSearchTask {

        private PatientSearchSpec spec;
        private Cursor currentCursor;

        /**
         *
         * @param app
         */
        public SynchronizeTitleSearchTask(Application app) {
        }

        /**
         *
         */
        public void execute() {
            try {
                succeeded(doInBackground());
            } catch (Exception ex) {
                LogWriter.error(getClass(), ex);
            }
        }

        /*
        private List<DocInfoModel> getDocumentHistory() {

        DocumentSearchSpec spec = new DocumentSearchSpec();
        spec.setKarteId(getParentContext().getKarte().getId());	// カルテID
        spec.setDocType("karte");			// 文書タイプ
        spec.setFromDate(new Date());			// 抽出期間開始
        spec.setIncludeModifid(true);	// 修正履歴
        spec.setIncludeUnsend(true);		// 修正履歴
        spec.setIncludeSend(true);		// 修正履歴

        spec.setCode(DocumentSearchSpec.DOCTYPE_SEARCH);	// 検索タイプ
        spec.setAscending(true);

        RemoteDocumentDelegater delegater = new RemoteDocumentDelegater();
        List<DocInfoModel> result = (List<DocInfoModel>) delegater.getDocumentHistory(spec);
        return result;
        }
         */
        protected Collection doInBackground() throws Exception {

            currentCursor = getCursor();
            setCursor(new Cursor(Cursor.WAIT_CURSOR));

            ObjectReflectTableModel<PatientModel> tableModel = (ObjectReflectTableModel<PatientModel>) table.getModel();
            List<PatientModel> result = new ArrayList<PatientModel>();
            PatientModel patientModel;
            Map<String, List> entries;
            List<DocInfoModel> items;
            DolphinQuery query = new DolphinQuery();
            query.addWhat("keyword", keywordFld.getText());
            for (int index = 0; index < tableModel.getRowCount(); index++) {
                patientModel = tableModel.getObject(index);
                KarteBean karteBean = getKarteBean(patientModel);
                entries = karteBean.getEntries();
                items = entries.get("docInfo");

                if (items != null) {
                    boolean found = false;
                    for (DocInfoModel item : items) {
                        if (item.search(query)) {
                            found = true;
                        }
                    }
                    if (found) {
                        result.add(patientModel);
                    }
                }
            }
            return result;
        }

        /**
         *
         * @param result
         */
        protected void succeeded(Collection result) {
            List<PatientModel> list = (List<PatientModel>) result;
            if (list != null && list.size() > 0) {
                switch (sortItemValue) {
                    case 0:
                        Comparator c = new Comparator<PatientModel>() {

                            @Override
                            public int compare(PatientModel p1, PatientModel p2) {
                                return p1.getPatientId().compareTo(p2.getPatientId());
                            }
                        };
                        Collections.sort(list, c);
                        break;
                    case 1:
                        Comparator c2 = new Comparator<PatientModel>() {

                            @Override
                            public int compare(PatientModel p1, PatientModel p2) {
                                String kana1 = p1.getKanaName();
                                String kana2 = p2.getKanaName();
                                if (kana1 != null && kana2 != null) {
                                    return p1.getKanaName().compareTo(p2.getKanaName());
                                } else if (kana1 != null && kana2 == null) {
                                    return -1;
                                } else if (kana1 == null && kana2 != null) {
                                    return 1;
                                } else {
                                    return 0;
                                }
                            }
                        };
                        Collections.sort(list, c2);
                        break;
                    default:
                        LogWriter.fatal(getClass(), "case default");
                }
            }

            ObjectReflectTableModel<PatientModel> tableModel = (ObjectReflectTableModel<PatientModel>) table.getModel();
            tableModel.setObjectList(list);
            int cnt = result != null ? result.size() : 0;
            String cntStr = String.valueOf(cnt);
            cntLbl.setText(cntStr + " 件");
            setCursor(currentCursor);
        }
    }

    /**
     *
     */
    class TitleSearchTask extends Task<Collection, Void> {

        private SynchronizeTitleSearchTask task;
        private PatientSearchSpec spec;
        private Cursor currentCursor;

        public TitleSearchTask(Application app) {
            super(app);
            task = new SynchronizeTitleSearchTask(app);
        }

        /**
         *
         * @return
         * @throws Exception
         */
        @Override
        protected Collection doInBackground() throws Exception {
            return task.doInBackground();
        }

        /**
         *
         * @param result
         */
        @Override
        protected void succeeded(Collection result) {
            task.succeeded(result);
        }

        /**
         *
         * @param cause
         */
        @Override
        protected void failed(Throwable cause) {
            setCursor(currentCursor);
        }

        /**
         *
         */
        @Override
        protected void cancelled() {
            setCursor(currentCursor);
        }
    }

    /**
     *
     */
    class SynchronizeMemoSearchTask {

        private PatientSearchSpec spec;
        private Cursor currentCursor;

        public SynchronizeMemoSearchTask(Application app) {
        }

        /**
         *
         */
        public void execute() {
            try {
                succeeded(doInBackground());
            } catch (Exception ex) {
                LogWriter.error(getClass(), ex);
            }
        }

        /**
         *
         * @return
         * @throws Exception
         */
        protected Collection doInBackground() throws Exception {
            currentCursor = getCursor();
            setCursor(new Cursor(Cursor.WAIT_CURSOR));
            ObjectReflectTableModel<PatientModel> tableModel = (ObjectReflectTableModel<PatientModel>) table.getModel();
            List<PatientModel> result = new ArrayList<PatientModel>();
            PatientModel patientModel;
            Map<String, List> entries;
            List<PatientMemoModel> items;
            DolphinQuery query = new DolphinQuery();
            query.addWhat("keyword", keywordFld.getText());
            for (int index = 0; index < tableModel.getRowCount(); index++) {
                patientModel = tableModel.getObject(index);
                KarteBean karteBean = getKarteBean(patientModel);
                entries = karteBean.getEntries();
                items = entries.get("patientMemo");
                if (items != null) {
                    boolean found = false;
                    for (PatientMemoModel item : items) {
                        if (item.search(query)) {
                            found = true;
                        }
                    }
                    if (found) {
                        result.add(patientModel);
                    }
                }
            }
            return result;
        }

        /**
         *
         * @param result
         */
        protected void succeeded(Collection result) {
            List<PatientModel> list = (List<PatientModel>) result;
            if (list != null && list.size() > 0) {
                switch (sortItemValue) {
                    case 0:
                        Comparator c = new Comparator<PatientModel>() {

                            @Override
                            public int compare(PatientModel p1, PatientModel p2) {
                                return p1.getPatientId().compareTo(p2.getPatientId());
                            }
                        };
                        Collections.sort(list, c);
                        break;
                    case 1:
                        Comparator c2 = new Comparator<PatientModel>() {

                            @Override
                            public int compare(PatientModel p1, PatientModel p2) {
                                String kana1 = p1.getKanaName();
                                String kana2 = p2.getKanaName();
                                if (kana1 != null && kana2 != null) {
                                    return p1.getKanaName().compareTo(p2.getKanaName());
                                } else if (kana1 != null && kana2 == null) {
                                    return -1;
                                } else if (kana1 == null && kana2 != null) {
                                    return 1;
                                } else {
                                    return 0;
                                }
                            }
                        };
                        Collections.sort(list, c2);
                        break;
                    default:
                        LogWriter.fatal(getClass(), "case default");
                }
            }

            ObjectReflectTableModel<PatientModel> tableModel = (ObjectReflectTableModel<PatientModel>) table.getModel();
            tableModel.setObjectList(list);
            int cnt = result != null ? result.size() : 0;
            String cntStr = String.valueOf(cnt);
            cntLbl.setText(cntStr + " 件");
            setCursor(currentCursor);
        }
    }

    /**
     *
     */
    class MemoSearchTask extends Task<Collection, Void> {

        private SynchronizeMemoSearchTask task;
        private PatientSearchSpec spec;
        private Cursor currentCursor;

        /**
         *
         * @param app
         */
        public MemoSearchTask(Application app) {
            super(app);
            task = new SynchronizeMemoSearchTask(app);
        }

        /**
         *
         * @return
         * @throws Exception
         */
        @Override
        protected Collection doInBackground() throws Exception {
            return task.doInBackground();
        }

        /**
         *
         * @param result
         */
        @Override
        protected void succeeded(Collection result) {
            task.succeeded(result);
        }

        /**
         *
         * @param cause
         */
        @Override
        protected void failed(Throwable cause) {
            setCursor(currentCursor);
        }

        /**
         *
         */
        @Override
        protected void cancelled() {
            setCursor(currentCursor);
        }
    }

    /**
     *
     */
    class SynchronizeAllergySearchTask {

        //   private PatientSearchSpec spec;
        private Cursor currentCursor;

        /**
         *
         * @param app
         */
        public SynchronizeAllergySearchTask(Application app) {
        }

        /**
         *
         */
        public void execute() {
            try {
                succeeded(doInBackground());
            } catch (Exception ex) {
                LogWriter.error(getClass(), ex);
            }
        }

        /**
         *
         * @return
         * @throws Exception
         */
        protected Collection doInBackground() throws Exception {
            currentCursor = getCursor();
            setCursor(new Cursor(Cursor.WAIT_CURSOR));
            ObjectReflectTableModel<PatientModel> tableModel = (ObjectReflectTableModel<PatientModel>) table.getModel();
            List<PatientModel> result = new ArrayList<PatientModel>();
            PatientModel patientModel;
            Map<String, List> entries;
            List<AllergyModel> items;
            DolphinQuery query = new DolphinQuery();
            query.addWhat("keyword", keywordFld.getText());
            for (int index = 0; index < tableModel.getRowCount(); index++) {
                patientModel = tableModel.getObject(index);
                KarteBean karteBean = getKarteBean(patientModel);
                entries = karteBean.getEntries();
                items = entries.get("allergy");
                if (items != null) {
                    boolean found = false;
                    for (AllergyModel item : items) {
                        if (item.search(query)) {
                            found = true;
                        }
                    }
                    if (found) {
                        result.add(patientModel);
                    }
                }
            }
            return result;
        }

        /**
         *
         * @param result
         */
        protected void succeeded(Collection result) {
            List<PatientModel> list = (List<PatientModel>) result;
            if (list != null && list.size() > 0) {
                switch (sortItemValue) {
                    case 0:
                        Comparator c = new Comparator<PatientModel>() {

                            @Override
                            public int compare(PatientModel p1, PatientModel p2) {
                                return p1.getPatientId().compareTo(p2.getPatientId());
                            }
                        };
                        Collections.sort(list, c);
                        break;
                    case 1:
                        Comparator c2 = new Comparator<PatientModel>() {

                            @Override
                            public int compare(PatientModel p1, PatientModel p2) {
                                String kana1 = p1.getKanaName();
                                String kana2 = p2.getKanaName();
                                if (kana1 != null && kana2 != null) {
                                    return p1.getKanaName().compareTo(p2.getKanaName());
                                } else if (kana1 != null && kana2 == null) {
                                    return -1;
                                } else if (kana1 == null && kana2 != null) {
                                    return 1;
                                } else {
                                    return 0;
                                }
                            }
                        };
                        Collections.sort(list, c2);
                        break;
                    default:
                        LogWriter.fatal(getClass(), "case default");
                }
            }

            ObjectReflectTableModel<PatientModel> tableModel = (ObjectReflectTableModel<PatientModel>) table.getModel();
            tableModel.setObjectList(list);
            int cnt = result != null ? result.size() : 0;
            String cntStr = String.valueOf(cnt);
            cntLbl.setText(cntStr + " 件");
            setCursor(currentCursor);
        }
    }

    /**
     *
     */
    class AllergySearchTask extends Task<Collection, Void> {

        private SynchronizeAllergySearchTask task;
        //    private PatientSearchSpec spec;
        private Cursor currentCursor;

        /**
         *
         * @param app
         */
        public AllergySearchTask(Application app) {
            super(app);
            task = new SynchronizeAllergySearchTask(app);
        }

        /**
         *
         * @return
         * @throws Exception
         */
        @Override
        protected Collection doInBackground() throws Exception {
            return task.doInBackground();
        }

        /**
         *
         * @param result
         */
        @Override
        protected void succeeded(Collection result) {
            task.succeeded(result);
        }

        /**
         *
         * @param cause
         */
        @Override
        protected void failed(Throwable cause) {
            setCursor(currentCursor);
        }

        /**
         *
         */
        @Override
        protected void cancelled() {
            setCursor(currentCursor);
        }
    }

    /**
     *
     */
    class SynchronizeKarteSearchTask {

        //     private PatientSearchSpec spec;
        private RemoteDocumentDelegater ddl;
        private Cursor currentCursor;

        /**
         *
         * @param app
         */
        public SynchronizeKarteSearchTask(Application app) {
            ddl = new RemoteDocumentDelegater();
        }

        /**
         *
         */
        public void execute() {
            try {
                succeeded(doInBackground());
            } catch (Exception ex) {
                LogWriter.error(getClass(), ex);
            }
        }

        /**
         *
         * @return
         * @throws Exception
         */
        protected Collection doInBackground() throws Exception {
            currentCursor = getCursor();
            setCursor(new Cursor(Cursor.WAIT_CURSOR));
            ObjectReflectTableModel<PatientModel> tableModel = (ObjectReflectTableModel<PatientModel>) table.getModel();
            List<PatientModel> result = new ArrayList<PatientModel>();
            PatientModel patientModel;
            Map<String, List> entries;
            List<DocInfoModel> items;
            for (int index = 0; index < tableModel.getRowCount(); index++) {
                patientModel = tableModel.getObject(index);
                KarteBean karteBean = getKarteBean(patientModel);
                entries = karteBean.getEntries();
                items = entries.get("docInfo");
                boolean found = false;
                DolphinQuery query = new DolphinQuery();
                query.addWhat("keyword", keywordFld.getText());
                if (items != null) {
                    List<Long> docId = new ArrayList<Long>();
                    for (DocInfoModel item : items) {
                        docId.add(new Long(item.getDocPk()));
                    }
                    List<DocumentModel> documents = ddl.getDocuments(docId);
                    for (DocumentModel document : documents) {
                        Set<ModuleModel> modules = document.getModules();
                        for (ModuleModel module : modules) {
                            if (module.search(query)) {
                                found = true;
                                break;
                            }
                        }
                        if (found) {
                            break;
                        }
                    }
                    if (found) {
                        result.add(patientModel);
                    }
                }
            }
            return result;
        }

        /**
         *
         * @param result
         */
        protected void succeeded(Collection result) {
            List<PatientModel> list = (List<PatientModel>) result;
            if (list != null && list.size() > 0) {
                switch (sortItemValue) {
                    case 0:
                        Comparator c = new Comparator<PatientModel>() {

                            @Override
                            public int compare(PatientModel p1, PatientModel p2) {
                                return p1.getPatientId().compareTo(p2.getPatientId());
                            }
                        };
                        Collections.sort(list, c);
                        break;
                    case 1:
                        Comparator c2 = new Comparator<PatientModel>() {

                            @Override
                            public int compare(PatientModel p1, PatientModel p2) {
                                String kana1 = p1.getKanaName();
                                String kana2 = p2.getKanaName();
                                if (kana1 != null && kana2 != null) {
                                    return p1.getKanaName().compareTo(p2.getKanaName());
                                } else if (kana1 != null && kana2 == null) {
                                    return -1;
                                } else if (kana1 == null && kana2 != null) {
                                    return 1;
                                } else {
                                    return 0;
                                }
                            }
                        };
                        Collections.sort(list, c2);
                        break;
                    default:
                        LogWriter.fatal(getClass(), "case default");
                }
            }

            ObjectReflectTableModel<PatientModel> tableModel = (ObjectReflectTableModel<PatientModel>) table.getModel();
            tableModel.setObjectList(list);
            int cnt = result != null ? result.size() : 0;
            String cntStr = String.valueOf(cnt);
            cntLbl.setText(cntStr + " 件");
            setCursor(currentCursor);
        }
    }

    /**
     *
     */
    class KarteSearchTask extends Task<Collection, Void> {

        private SynchronizeKarteSearchTask task;
        private PatientSearchSpec spec;
        private RemoteDocumentDelegater ddl;//MEMO: unused?
        private Cursor currentCursor;

        /**
         *
         * @param app
         */
        public KarteSearchTask(Application app) {
            super(app);
            task = new SynchronizeKarteSearchTask(app);
        }

        /**
         *
         * @return
         * @throws Exception
         */
        @Override
        protected Collection doInBackground() throws Exception {
            return task.doInBackground();
        }

        /**
         *
         * @param result
         */
        @Override
        protected void succeeded(Collection result) {
            task.succeeded(result);
        }

        /**
         *
         * @param cause
         */
        @Override
        protected void failed(Throwable cause) {
            setCursor(currentCursor);
        }

        /**
         *
         */
        @Override
        protected void cancelled() {
            setCursor(currentCursor);
        }
    }

    /**
     *
     */
    class MyInputBlocker extends InputBlocker {

        private BlockGlass glassPane;
        private KeyBlocker keyBlocker;

        /**
         *
         * @param task
         * @param glassPane
         * @param keyBlocker
         */
        MyInputBlocker(Task task, BlockGlass glassPane, KeyBlocker keyBlocker) {
            super(task, Task.BlockingScope.WINDOW, glassPane);
            this.glassPane = glassPane;
            this.keyBlocker = keyBlocker;
        }

        /**
         *
         */
        @Override
        protected void block() {
            glassPane.block();
            keyBlocker.block();
        }

        /**
         *
         */
        @Override
        protected void unblock() {
            glassPane.unblock();
            keyBlocker.unblock();
        }
    }

    /**
     * テキストフィールドへ日付を入力するためのカレンダーポップアップメニュークラス。　MEMO:リスナー
     */
    class PopupListener extends MouseAdapter implements PropertyChangeListener {

        /** ポップアップメニュー */
        private JPopupMenu popup;
        /** ターゲットのテキストフィールド */
        private JTextField tf;

        /**
         *
         * @param tf
         */
        public PopupListener(JTextField tf) {
            this.tf = tf;
            tf.addMouseListener(this);
        }

        /**
         *
         * @param e
         */
        @Override
        public void mousePressed(MouseEvent e) {
            maybeShowPopup(e);
        }

        /**
         *
         * @param e
         */
        @Override
        public void mouseReleased(MouseEvent e) {
            maybeShowPopup(e);
        }

        /**
         *
         * @param e
         */
        private void maybeShowPopup(MouseEvent e) {

            if (e.isPopupTrigger()) {
                popup = new JPopupMenu();
                CalendarCardPanel cc = new CalendarCardPanel(GlobalConstants.getEventColorTable());
                cc.addPropertyChangeListener(CalendarCardPanel.PICKED_DATE, this);
                cc.setCalendarRange(new int[]{-12, 0});
                popup.insert(cc, 0);
                popup.show(e.getComponent(), e.getX(), e.getY());
            }
        }

        /**
         *
         * @param e
         */
        @Override
        public void propertyChange(PropertyChangeEvent e) {
            if (e.getPropertyName().equals(CalendarCardPanel.PICKED_DATE)) {
                SimpleDate sd = (SimpleDate) e.getNewValue();
                tf.setText(SimpleDate.simpleDateToMmldate(sd));
                popup.setVisible(false);
                popup = null;
                String test = tf.getText().trim();
                if (!test.equals("")) {
                    find(test);
                }
            }
        }
    }
}
