package open.dolphin.client;

import open.dolphin.project.GlobalConstants;
import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.print.PageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import open.dolphin.delegater.remote.RemoteSetaDelegater;
import open.dolphin.infomodel.IInfoModel;
import open.dolphin.infomodel.ModelUtils;
import open.dolphin.infomodel.PatientModel;
import open.dolphin.infomodel.LetterModel;
import open.dolphin.infomodel.TouTouLetter;
import open.dolphin.infomodel.UserModel;
import open.dolphin.project.GlobalVariables;

import open.dolphin.delegater.remote.RemoteDocumentDelegater;
import open.dolphin.dto.DocumentSearchSpec;
import open.dolphin.helper.DBTask;
import java.util.List;
import java.util.ArrayList;
import java.awt.event.MouseEvent;
import javax.swing.JPopupMenu;
import javax.swing.JMenuItem;
import javax.swing.AbstractAction;
import java.awt.event.ActionEvent;
import java.util.Collections;
import java.util.LinkedHashSet;
import javax.swing.JTabbedPane;

import javax.swing.SwingUtilities;
import open.dolphin.client.caremapdocument.CareMapDocumentPanel;
import open.dolphin.project.GlobalSettings;
import open.dolphin.dto.DiagnosisSearchSpec;
import open.dolphin.dto.ModuleSearchSpec;
import open.dolphin.infomodel.ModuleModel;
import open.dolphin.infomodel.RegisteredDiagnosisModel;
import open.dolphin.log.LogWriter;
import open.dolphin.helper.IChartCommandAccepter;
import open.dolphin.infomodel.IStampInfo;
import open.dolphin.utils.AgeCalculator;

/**
 * 紹介状　MEMO:画面
 * @author
 */
public class LetterImpl extends PrintablePanel implements IChartDocument, IChartCommandAccepter {

    private static final String TITLE = "紹介状";
    private TouTouLetter model;
    private List<RegisteredDiagnosisModel> diagnosises;//MEMO: unused?
    private LetterView view;
    private StateMgr stateMgr;
    private List<LetterModel> model_list;
    //元々はAbstractChartDocumentから継承
    private static final String[] CHART_MENUS = {
        GUIConst.ACTION_OPEN_KARTE, GUIConst.ACTION_SAVE, GUIConst.ACTION_DIRECTION, GUIConst.ACTION_DELETE, GUIConst.ACTION_PRINT, GUIConst.ACTION_MODIFY_KARTE,
        GUIConst.ACTION_ASCENDING, GUIConst.ACTION_DESCENDING, GUIConst.ACTION_SHOW_MODIFIED, GUIConst.ACTION_SHOW_UNSEND, GUIConst.ACTION_SHOW_SEND, GUIConst.ACTION_SHOW_NEWEST,
        GUIConst.ACTION_INSERT_TEXT, GUIConst.ACTION_INSERT_SCHEMA, GUIConst.ACTION_INSERT_STAMP, GUIConst.ACTION_SELECT_INSURANCE,
        GUIConst.ACTION_CUT, GUIConst.ACTION_COPY, GUIConst.ACTION_PASTE, GUIConst.ACTION_UNDO, GUIConst.ACTION_REDO
    };
    private IChart parent;
    private String title;
    private boolean dirty;
    // private Application app;
    // private ApplicationContext appCtx;
    //   private TaskMonitor taskMonitor;
    //   private TaskService taskService;
    private String[] medicationHistoryCache;

    /** Creates a new instance of LetterDocument
     * @param parent
     */
    public LetterImpl(IChart parent) {
        this.title = TITLE;
        this.parent = parent;
        initComponents();

        //   appCtx = GlobalConstants.getApplicationContext();
        //    app = appCtx.getApplication();
        //    taskMonitor = appCtx.getTaskMonitor();
        //    taskService = appCtx.getTaskService();
        //   setTitle(TITLE);
    }

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

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 400, Short.MAX_VALUE));
        layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGap(0, 300, Short.MAX_VALUE));
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables

    @Override
    public TYPE getType() {
        return TYPE.LetterImpl;
    }

    /**
     * 
     */
    private void addAutoKanjiLIstenerToEachTextArea() {

        view.getCHospital().addFocusListener(AutoKanjiListener.getInstance());
        view.getCDept().addFocusListener(AutoKanjiListener.getInstance());
        view.getCDoctor().addFocusListener(AutoKanjiListener.getInstance());
        view.getDisease().addFocusListener(AutoKanjiListener.getInstance());
        view.getPurpose().addFocusListener(AutoKanjiListener.getInstance());
        view.getPastFamily().addFocusListener(AutoKanjiListener.getInstance());
        view.getClinicalCourse().addFocusListener(AutoKanjiListener.getInstance());
        view.getMedication().addFocusListener(AutoKanjiListener.getInstance());
        view.getRemarks().addFocusListener(AutoKanjiListener.getInstance());
    }

    /**
     * 
     */
    private void addDirtyListenerToEachTextArea() {
        DocumentListener dl = new DocumentListener() {

            /**
             *
             */
            @Override
            public void insertUpdate(DocumentEvent documentEvent) {
                stateMgr.processDirtyEvent();
            }

            /**
             *
             */
            @Override
            public void removeUpdate(DocumentEvent documentEvent) {
                stateMgr.processDirtyEvent();
            }

            /**
             *
             */
            @Override
            public void changedUpdate(DocumentEvent documentEvent) {
                stateMgr.processDirtyEvent();
            }
        };
        view.getCHospital().getDocument().addDocumentListener(dl);
        view.getCDept().getDocument().addDocumentListener(dl);
        view.getCDoctor().getDocument().addDocumentListener(dl);
        view.getDisease().getDocument().addDocumentListener(dl);
        view.getPurpose().getDocument().addDocumentListener(dl);
        view.getPastFamily().getDocument().addDocumentListener(dl);
        view.getClinicalCourse().getDocument().addDocumentListener(dl);
        view.getMedication().getDocument().addDocumentListener(dl);
        view.getRemarks().getDocument().addDocumentListener(dl);
    }

    /**
     * 
     */
    private void addListenerToViewComponents() {
        view.cHospitalHistoryBtn.addMouseListener(new java.awt.event.MouseAdapter() {

            /**
             *
             */
            @Override
            public void mouseClicked(MouseEvent evt) {
                cHospitalHistoryPopup(evt);
            }
        });
        view.cDeptHistoryBtn.addMouseListener(new java.awt.event.MouseAdapter() {

            /**
             *
             */
            @Override
            public void mouseClicked(MouseEvent evt) {
                cDeptHistoryPopup(evt);
            }
        });
        view.cDoctorHistoryBtn.addMouseListener(new java.awt.event.MouseAdapter() {

            /**
             *
             */
            @Override
            public void mouseClicked(MouseEvent evt) {
                cDoctorHistoryPopup(evt);
            }
        });
        view.diagnosisHistoryBtn.addMouseListener(new java.awt.event.MouseAdapter() {

            /**
             *
             */
            @Override
            public void mouseClicked(MouseEvent evt) {
                diagnosisHistoryPopup(evt);
            }
        });
        view.purposeHistoryBtn.addMouseListener(new java.awt.event.MouseAdapter() {

            /**
             *
             */
            @Override
            public void mouseClicked(MouseEvent evt) {
                purposeHistoryPopup(evt);
            }
        });
        view.pastFamilyHistoryBtn.addMouseListener(new java.awt.event.MouseAdapter() {

            /**
             *
             */
            @Override
            public void mouseClicked(MouseEvent evt) {
                pastFamilyHistoryPopup(evt);
            }
        });
        view.clinicalCourseHistoryBtn.addMouseListener(new java.awt.event.MouseAdapter() {

            /**
             *
             */
            @Override
            public void mouseClicked(MouseEvent evt) {
                clinicalCourseHistoryPopup(evt);
            }
        });
        view.medicationHistoryBtn.addMouseListener(new java.awt.event.MouseAdapter() {

            /**
             *
             */
            @Override
            public void mouseClicked(MouseEvent evt) {
                medicationHistoryPopup(evt);
            }
        });
        view.remarkHistoryBtn.addMouseListener(new java.awt.event.MouseAdapter() {

            /**
             *
             */
            @Override
            public void mouseClicked(MouseEvent evt) {
                remarksHistoryPopup(evt);
            }
        });
    }

    /**
     * 
     * @return
     */
    private DocumentSearchSpec createLetterSearchSpec() {
        DocumentSearchSpec spec = new DocumentSearchSpec();
        spec.setKarteId(getParentContext().getKarte().getId()); // カルテID
        spec.setDocType(IInfoModel.DOCTYPE_LETTER); // 文書タイプ
        spec.setFromDate((new java.util.GregorianCalendar()).getTime()); // 抽出期間開始
        spec.setIncludeModifid(true); // 修正履歴
        spec.setCode(DocumentSearchSpec.DOCTYPE_SEARCH); // 検索タイプ
        spec.setAscending(true);
        return spec;
    }

    /**
     * MEMO:Invakeを使用
     * @param setMethodName
     * @param candidates
     * @return
     */
    private JPopupMenu createPopupMenu(final String setMethodName, String[] candidates) {

        JPopupMenu popMenu = new JPopupMenu();

        for (int i = 0; i < candidates.length; i++) {
            //LogWriter.debug(getClass(), candidates.get(i));
            if (candidates[i] == null || candidates[i].trim().equals("")) {
                continue;
            }
            JMenuItem item = new JMenuItem(new AbstractAction(candidates[i]) {

                @Override
                public void actionPerformed(ActionEvent e) {
                    String actionCommand = e.getActionCommand();
                    try {
                        view.getClass().getMethod(setMethodName, new Class[]{String.class}).invoke(view, new Object[]{new String(actionCommand)});
                    } catch (Exception ex) {
                        LogWriter.error(getClass(), ex);
                    }
                }
            });
            popMenu.add(item);
        }
        return popMenu;
    }

    /**
     * MEMO:Invakeを使用
     * @param getMethodName
     * @return
     */
    private String[] getCandidateList(final String getMethodName) {

        List<String> candidates = new ArrayList<String>(1);
        String caption;

        for (LetterModel letter : model_list) {
            try {
                caption = (String) ((TouTouLetter) letter).getClass().getMethod(getMethodName).invoke(letter, (Object[]) null);
                if (caption == null) {
                    continue;
                }
                candidates.add(caption);
            } catch (Exception ex) {
                LogWriter.error(getClass(), ex);
            }
        }

        candidates = new ArrayList(new LinkedHashSet(candidates));
        Collections.reverse(candidates);
        return candidates.toArray(new String[0]);
    }

    /**
     * 
     * @param patient
     */
    private void setupModel(PatientModel patient) {

        model = new TouTouLetter();

        Date today = new Date();
        model.setConfirmed(today);

        model.setPatientName(patient.getFullName());
        model.setPatientGender(patient.getGenderDesc());
        model.setPatientBirthday(patient.getBirthday());
        model.setPatientAge(AgeCalculator.getAge(patient.getBirthday()));
        //        this.model.setPatientAddress(patient.getAddress().getAddress());

        UserModel user = GlobalVariables.getUserModel();
        model.setClientHospital(user.getFacility().getFacilityName());
        model.setClientName(user.getCommonName());
        model.setClientAddress(user.getFacility().getAddress());
        model.setClientTelephone(user.getFacility().getTelephone());
        model.setClientFax(null);
    }

    /**
     * 
     * @param tf
     * @param value
     */
    private void setModelValue(JTextField tf, String value) {
        if (value != null) {
            tf.setText(value);
        }
    }

    /**
     * 
     * @param tf
     * @return
     */
    private String getFieldValue(JTextField tf) {
        String ret = tf.getText().trim();
        if (!ret.equals("")) {
            return ret;
        }
        return null;
    }

    /**
     * 
     * @param ta
     * @return
     */
    private String getAreaValue(JTextArea ta) {
        String ret = ta.getText().trim();
        if (!ret.equals("")) {
            return ret;
        }
        return null;
    }

    /**
     * 
     * @param date
     * @return
     */
    private String getDateAsString(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年M月d日");
        return sdf.format(date);
    }

    /**
     * 
     * @param mmlDate
     * @return
     */
    private String getDateString(String mmlDate) {
        Date d = ModelUtils.getDateAsObject(mmlDate);
        return getDateAsString(d);
    }

    /**
     * 
     */
    private void displayModel() {

        String dateStr = getDateAsString(model.getConfirmed());
        view.getConfirmed().setText(dateStr);

        String birthdayStr = getDateString(model.getPatientBirthday());

        setModelValue(view.getPatientName(), model.getPatientName());
        setModelValue(view.getPatientGender(), model.getPatientGender());
        setModelValue(view.getPatientBirthday(), birthdayStr);
        setModelValue(view.getPatientAge(), model.getPatientAge());
        setModelValue(view.getPatientName(), model.getPatientName());
    }

    /**
     * 
     * @param model
     */
    private void restore(TouTouLetter model) {

        Date today = new Date();

        model.setConfirmed(today);
        model.setRecorded(today);
        model.setStarted(today);

        model.setStatus(IInfoModel.STATUS_FINAL);
        model.setKarte(getParentContext().getKarte());
        model.setCreator(GlobalVariables.getUserModel());

        model.setConsultantHospital(getFieldValue(view.getCHospital()));
        model.setConsultantDept(getFieldValue(view.getCDept()));
        model.setConsultantDoctor(getFieldValue(view.getCDoctor()));

        model.setDisease(getFieldValue(view.getDisease()));
        model.setPurpose(getFieldValue(view.getPurpose()));
        model.setClinicalCourse(getAreaValue(view.getClinicalCourse()));
        model.setPastFamily(getAreaValue(view.getPastFamily()));
        model.setMedication(getAreaValue(view.getMedication()));
        model.setRemarks(getFieldValue(view.getRemarks()));
    }

    /**
     * 
     * @param command
     * @return
     */
    @Override
    public boolean dispatchChartCommand(IChartCommandAccepter.ChartCommand command) {
        switch (command) {
            case modifyKarte:
                return modifyKarte();
            case save:
                return save();
            case print:
                return print();
            default:
        }
        return false;
    }

    /**
     *
     */
    @Override
    public void start() {

        PatientModel patient = getParentContext().getPatient();

        setupModel(patient);

        view = new LetterView();
        view.setKanzyaID(patient.getPatientId());

        JScrollPane scroller = new JScrollPane(this.view);
        scroller.getViewport().setBackground(GlobalSettings.getColors(GlobalSettings.Parts.TABLE_BACKGROUND));
        scroller.getVerticalScrollBar().setUnitIncrement(GlobalSettings.karteScrollUnitIncrement());
        setLayout(new BorderLayout());
        add(scroller);

        addListenerToViewComponents();

        displayModel();

        addDirtyListenerToEachTextArea();

        addAutoKanjiLIstenerToEachTextArea();


        stateMgr = new StateMgr();

        DocInfoTask task = new DocInfoTask(getParentContext(), createLetterSearchSpec(), new RemoteDocumentDelegater());
        task.execute();
    }

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

    private boolean save() {

        restore(this.model);

        RemoteSetaDelegater ddl = new RemoteSetaDelegater();
        long result = ddl.saveOrUpdateLetter(model);
        if (!ddl.isError()) {
            model.setId(result);
        }
        stateMgr.processSavedEvent();

        getParentContext().getDocumentHistory().getDocumentHistory();
        closeEditor();
        return true;
    }

    /*
     * ウィンドウまたはタブを閉じる。新規ボタンをEnableする。
     * */
    private void closeEditor() {

        getParentContext().enabledAction(GUIConst.ACTION_NEW_DOCUMENT, true);
        getParentContext().enabledAction(GUIConst.ACTION_DIRECTION, false);

        //    getParentContext().setNewButtonEnabled(true);
        //   getParentContext().setDirectionButtonEnabled(false);
        getParentContext().closeChartDocument(title, this);
        getParentContext().getChartMediator().unsetAccepter(this);
    }

    /**
     * 
     */
    @Override
    public void enter() {

        getParentContext().getStatusPanel().setMessage("");
        getParentContext().getChartMediator().setAccepter(this);
        disableMenus();

        getParentContext().enabledAction(GUIConst.ACTION_NEW_KARTE, true);
        getParentContext().enabledAction(GUIConst.ACTION_NEW_DOCUMENT, true);
        getParentContext().enabledAction(GUIConst.ACTION_ADD_USER, GlobalVariables.isAdmin());
        if (stateMgr != null) {
            stateMgr.enter();
        }
    }

    /**
     * 
     * @return
     */
    private boolean print() {
        //command
        if (this.model == null) {
            return true;
        }

        StringBuilder sb = new StringBuilder();
        sb.append("PDFファイルを作成しますか?");

        int option = JOptionPane.showOptionDialog(
                getParentContext().getFrame(),
                sb.toString(),
                GlobalConstants.getFrameTitle("紹介状印刷"),
                JOptionPane.DEFAULT_OPTION,
                JOptionPane.INFORMATION_MESSAGE,
                null,
                new String[]{"PDF作成", "画面印刷", "取消し"},
                "PDF作成");

        if (option == 0) {
            save();
            makePDF();
        } else if (option == 1) {
            PageFormat pageFormat = getParentContext().getContext().getPageFormat();
            String name = getParentContext().getPatient().getFullName();
            PrintablePanel panel = (PrintablePanel) this.view;
            panel.printPanel(pageFormat, 1, false, name, 0);
        }
        return true;
    }

    /**
     * 
     */
    public void makePDF() {

        if (this.model == null) {
            return;
        }
        open.dolphin.client.print.PrintPDF p = new open.dolphin.client.print.PrintPDF(getParentContext().getFrame());
        p.exec(model);
    }

    /**
     * 
     * @return
     */
    @Override
    public boolean isDirty() {
        if (stateMgr != null) {
            return stateMgr.isDirtyState();
        } else {
            return dirty;
        }
    }

    /**
     * 紹介状を変更する。
     */
    private boolean modifyKarte() {
        stateMgr.processModifyKarteEvent();
        return true;
    }

    /**
     * 
     * @param b
     */
    private void setEditables(boolean b) {

        view.getConfirmed().setEditable(b);
        view.getCHospital().setEditable(b);
        view.getCDept().setEditable(b);
        view.getCDoctor().setEditable(b);
        view.getDisease().setEditable(b);
        view.getPurpose().setEditable(b);
        view.getPastFamily().setEditable(b);
        view.getClinicalCourse().setEditable(b);
        view.getMedication().setEditable(b);
        view.getRemarks().setEditable(b);
    }

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

    /**
     * 元々はAbstractChartDocumentから継承
     * @return
     */
    @Override
    public String getTitle() {
        return title;
    }

    /**
     *
     * @return
     */
    @Override
    public IChart getParentContext() {
        return parent;
    }

    /**
     *
     * @return
     */
    @Override
    public boolean prepare() {
        return true;
    }

    /**
     *
     * @param dirty
     */
    @Override
    public void setDirty(boolean dirty) {
        this.dirty = dirty;
    }

    /**
     *
     * @return
     */
    public boolean isReadOnly() {
        return getParentContext().isReadOnly();
    }

    /**
     *
     */
    public void disableMenus() {
        // このウインドウに関連する全てのメニューをdisableにする
        ChartMediator mediator = getParentContext().getChartMediator();
        mediator.disableMenus(CHART_MENUS);
    }

    /**
     * 共通の警告表示を行う。
     * @param title 
     * @param message
     */
    protected void warning(String title, String message) {
        Window parent = SwingUtilities.getWindowAncestor(this);
        JOptionPane.showMessageDialog(parent, message, GlobalConstants.getFrameTitle(title), JOptionPane.WARNING_MESSAGE);
    }

    /**
     * MEMO: unused?
     * @return
     */
    private String[] getMedications() {

        final ModuleSearchSpec spec = new ModuleSearchSpec();
        spec.setCode(ModuleSearchSpec.ENTITY_SEARCH);
        spec.setKarteId(getParentContext().getKarte().getId());
        spec.setEntity("medOrder");
        spec.setStatus("F");

        if (medicationHistoryCache == null) {

            RemoteDocumentDelegater ddl = new RemoteDocumentDelegater();
            List<ModuleModel> moduleList = ddl.getAllModuleList(spec);

            List<String> result = new ArrayList<String>();

            for (ModuleModel module : moduleList) {

                module.setModel(module.toInfoModel());

                IStampInfo info = module.getModuleInfo();
                result.add(info.getStampName());
            }

            result = new ArrayList(new LinkedHashSet(result));
            Collections.reverse(result);

            medicationHistoryCache = result.toArray(new String[0]);
        }

        return medicationHistoryCache;
    }

    /**
     * 抽象 State クラス。
     */
    protected abstract class State {

        /**
         *
         */
        public abstract void enter();
    }

    /**
     * Claen State クラス。
     */
    class EmptyState extends State {

        /**
         *
         */
        @Override
        public void enter() {
            getParentContext().enabledAction(GUIConst.ACTION_SAVE, false);
            getParentContext().enabledAction(GUIConst.ACTION_PRINT, false);
            getParentContext().enabledAction(GUIConst.ACTION_DIRECTION, false);
            getParentContext().enabledAction(GUIConst.ACTION_MODIFY_KARTE, false);
            getParentContext().enabledAction(GUIConst.ACTION_ADD_USER, GlobalVariables.isAdmin());
        }
    }

    /**
     * Dirty State クラス。
     */
    class DirtyState extends State {

        /**
         *
         */
        @Override
        public void enter() {
            getParentContext().enabledAction(GUIConst.ACTION_SAVE, true);
            getParentContext().enabledAction(GUIConst.ACTION_PRINT, true);
            getParentContext().enabledAction(GUIConst.ACTION_DIRECTION, true);
            getParentContext().enabledAction(GUIConst.ACTION_MODIFY_KARTE, false);
            getParentContext().enabledAction(GUIConst.ACTION_ADD_USER, GlobalVariables.isAdmin());
        }
    }

    /**
     * Saved State クラス。
     */
    class CleanState extends State {

        /**
         *
         */
        @Override
        public void enter() {
            setEditables(false);
            getParentContext().enabledAction(GUIConst.ACTION_SAVE, false);
            getParentContext().enabledAction(GUIConst.ACTION_PRINT, true);
            getParentContext().enabledAction(GUIConst.ACTION_DIRECTION, true);
            getParentContext().enabledAction(GUIConst.ACTION_MODIFY_KARTE, true);
            getParentContext().enabledAction(GUIConst.ACTION_ADD_USER, GlobalVariables.isAdmin());
        }
    }

    /**
     *
     */
    class StartEditingState extends State {

        /**
         *
         */
        @Override
        public void enter() {
            setEditables(true);
            getParentContext().enabledAction(GUIConst.ACTION_SAVE, false);
            getParentContext().enabledAction(GUIConst.ACTION_PRINT, true);
            getParentContext().enabledAction(GUIConst.ACTION_DIRECTION, true);
            getParentContext().enabledAction(GUIConst.ACTION_MODIFY_KARTE, false);
            getParentContext().enabledAction(GUIConst.ACTION_ADD_USER, GlobalVariables.isAdmin());
        }
    }

    /**
     * State の Context クラス。
     */
    class StateMgr {

        private EmptyState emptyState = new EmptyState();
        private DirtyState dirtyState = new DirtyState();
        private CleanState cleanState = new CleanState();
        private StartEditingState startEditingState = new StartEditingState();
        private State curState;

        /**
         *
         */
        public StateMgr() {
            curState = emptyState;
            enter();
        }

        /**
         *
         */
        public void enter() {
            curState.enter();
        }

        /**
         *
         */
        public void processDirtyEvent() {

            boolean newDirty = (getFieldValue(view.getCHospital()) != null
                    && getFieldValue(view.getDisease()) != null
                    && getFieldValue(view.getPurpose()) != null
                    && getAreaValue(view.getClinicalCourse()) != null)
                    ? true
                    : false;
            if (isDirtyState() != newDirty) {
                curState = newDirty ? dirtyState : emptyState;
                curState.enter();
            }
        }

        /**
         *
         */
        public void processSavedEvent() {
            curState = cleanState;
            curState.enter();
        }

        /**
         *
         */
        public void processModifyKarteEvent() {
            curState = startEditingState;
            curState.enter();
        }

        /**
         *
         * @return
         */
        public boolean isDirtyState() {
            return curState == dirtyState ? true : false;
        }
    }

    /**
     *
     */
    class DocInfoTask extends DBTask<List<LetterModel>> {

        private RemoteDocumentDelegater ddl;
        private DocumentSearchSpec spec;

        /**
         *
         * @param ctx
         * @param spec
         * @param ddl
         */
        public DocInfoTask(IChart ctx, DocumentSearchSpec spec, RemoteDocumentDelegater ddl) {
            super(ctx);
            this.spec = spec;
            this.ddl = ddl;
        }

        /**
         *
         * @return
         */
        @Override
        protected List<LetterModel> doInBackground() {

            List<LetterModel> result = ddl.getRecentLetterModels();

            if (!ddl.isError()) {
                return result;
            } else {
                return null;
            }
        }

        /**
         *
         * @param result
         */
        @Override
        protected void succeeded(List<LetterModel> result) {
            if (result != null) {
                model_list = result;
            }
        }
    }

    /**
     *
     * @param e
     */
    public void cHospitalHistoryPopup(MouseEvent e) {
        historyPopup("getConsultantHospital", "setCHospital", e);
    }

    /**
     *
     * @param e
     */
    public void diagnosisHistoryPopup(final MouseEvent e) {

        final DiagnosisSearchSpec spec = new DiagnosisSearchSpec();

        spec.setCode(DiagnosisSearchSpec.PATIENT_SEARCH);
        spec.setKarteId(getParentContext().getKarte().getId());
        Date past = new Date(0l);
        if (past != null) {
            spec.setFromDate(past);
        }

        final RemoteDocumentDelegater ddl = new RemoteDocumentDelegater();

        DBTask task = new DBTask<List>(getParentContext()) {

            @Override
            protected List doInBackground() throws Exception {
                return ddl.getDiagnosisList(spec);
            }

            @Override
            protected void succeeded(List list) {

                diagnosises = list;

                List<String> captions = new ArrayList<String>();
                if (!ddl.isError() && list != null) {

                    Collections.sort(list);

                    String diagnosisName = null;
                    for (Object model : list) {
                        diagnosisName = ((RegisteredDiagnosisModel) model).getDiagnosis();
                        if (diagnosisName == null) {
                            continue;
                        }
                        captions.add(diagnosisName);
                        diagnosisName = null;
                    }

                    captions = new ArrayList(new LinkedHashSet(captions));
                    String[] diagnosisNames = captions.toArray(new String[0]);
                    //String[] diagnosisNames = (String[]) (new java.util.TreeSet(java.util.Arrays.asList(captions.toArray(new String[0])))).toArray(new String[0]);

                    JPopupMenu popMenu = new JPopupMenu();
                    for (int i = 0; i < diagnosisNames.length; i++) {

                        if (diagnosisNames[i] == null || diagnosisNames[i].trim().equals("")) {
                            continue;
                        }

                        JMenuItem item = new JMenuItem(new AbstractAction(diagnosisNames[i]) {

                            @Override
                            public void actionPerformed(ActionEvent e) {
                                String s = e.getActionCommand();
                                try {
                                    String oldDisease = view.getDisease().getText().trim();
                                    if (!oldDisease.equals("")) {
                                        oldDisease += "、";
                                    }
                                    view.setDisease(oldDisease + s);
                                } catch (Exception ex) {
                                    LogWriter.error(getClass(), ex);
                                }
                            }
                        });
                        popMenu.add(item);
                    }
                    popMenu.show(e.getComponent(), e.getX(), e.getY());
                }
            }
        };

        task.execute();
    }

    /**
     *
     * @param e
     */
    public void cDeptHistoryPopup(MouseEvent e) {
        historyPopup("getConsultantDept", "setCDept", e);
    }

    /**
     *
     * @param e
     */
    public void cDoctorHistoryPopup(MouseEvent e) {
        historyPopup("getConsultantDoctor", "setCDoctor", e);
    }

    /**
     *
     * @param e
     */
    public void purposeHistoryPopup(MouseEvent e) {
        historyPopup("getPurpose", "setPurpose", e);
    }

    /**
     *
     * @param e
     */
    public void pastFamilyHistoryPopup(MouseEvent e) {
        historyPopup("getPastFamily", "setPastFamily", e);
    }

    /**
     *
     * @param e
     */
    public void clinicalCourseHistoryPopup(MouseEvent e) {
        historyPopup("getClinicalCourse", "setClinicalCourse", e);
    }

    //紹介状->紹介状->参照
    /**
     *
     * @param e
     */
    public void medicationHistoryPopup(MouseEvent e) {
        // historyPopup("getMedication", "setMedication", e);

        // FIXME: 重いうえにスクロールしない
        // String[] medications = getMedications();
        // JPopupMenu popMenu = createPopupMenu("setMedication", medications);
        // popMenu.setName("getMedicationPopupMenu");
        // popMenu.show(e.getComponent(), e.getX(), e.getY());

        // MEMO: カルテから現在の処方をコピーするための処理
        //     getParentContext().showDocument(2);


        getParentContext().showDocument(CareMapDocumentPanel.TITLE);

        // getParentContext().showDocument(DocumentBridgeImpl.TITLE);

//getParentContext().showDocument(KarteDocumentViewer.TITLE);

    }

    /**
     *
     * @param e
     */
    public void remarksHistoryPopup(MouseEvent e) {
        historyPopup("getRemarks", "setRemarks", e);
    }

    /**
     *
     * @param getMethodName
     * @param setMethodName
     * @param evnt
     */
    private void historyPopup(final String getMethodName, final String setMethodName, MouseEvent evnt) {

        String[] captions = getCandidateList(getMethodName);

        JPopupMenu popMenu = createPopupMenu(setMethodName, captions);
        popMenu.setName(getMethodName + "PopupMenu");
        popMenu.show(evnt.getComponent(), evnt.getX(), evnt.getY());
    }

    /**
     *
     * @return
     */
    public LetterView getView() {
        return view;
    }

    /**
     *
     * @return
     */
    @Override
    public List<JTabbedPane> getTabbedPanels() {
        return null;
    }

    /**
     *
     * @param o
     * @return
     */
    @Override
    public boolean update(Object o) {
        return true;
    }
}
