package com.ftinc.si.assist.test.web;

import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import com.ftinc.si.assist.run.Messages;
import com.ftinc.si.assist.test.Tool;

public class XpathEditor4Element extends JDialog {
	private JTextField repTextField;
	private JTextField childTextField;
	private HashMap<String, String> m_attrMap;
	private int m_prevpos = -1;
	private String[] m_paths;

	private int m_spinpos = 0;
	private HashMap<String, Object> m_pathmap;

	private HashMap<String, String> m_result;
	private HashMap<String, String> m_repdic = null;

	//pathmap キー：xpath
	//        値：HashMap<String, String> キー="xpath"とxpathの値, "id"とid相当の値, 末端から要素までのパスと属性の組
	//        ※idがない場合もある。
	//        ※#attrMap:このダイアログで編集した結果を保持するMapが含まれていることがある。
	@SuppressWarnings("unchecked")
	public XpathEditor4Element(JFrame owner, String xrepXPath, String curPath, HashMap<String, Object> pathMap, HashMap<String, String> repMap) {
		super(owner, true); // modalにする。

		boolean b_single = false;
		String repXPath = ""; //$NON-NLS-1$
		if (xrepXPath == null) {
			b_single = true;
		} else {
			repXPath = xrepXPath;;
		}

		m_pathmap = (HashMap<String, Object>)pathMap.get(curPath);
		if (m_pathmap == null) {
			Tool.alertMSG(this, Messages.getString("XpathEditor4Element.1") + curPath + Messages.getString("XpathEditor4Element.2") + Tool.getJSONfromObject(pathMap)); //$NON-NLS-1$ //$NON-NLS-2$
		}

		setTitle("XpathEditor4Element"); //$NON-NLS-1$
		getContentPane().setLayout(null);
		setSize(new Dimension(640, 370));
		setResizable(false);

		repTextField = new JTextField();
		repTextField.setBounds(12, 33, 258, 19);
		getContentPane().add(repTextField);
		repTextField.setColumns(10);

		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setBounds(12, 86, 141, 206);
		getContentPane().add(scrollPane);

		DefaultListModel<String> layer_model = new DefaultListModel<String>();
		m_paths = curPath.split("/"); //$NON-NLS-1$
		for (int i = 0; i < m_paths.length; i++) {
			String i_dent = ""; //$NON-NLS-1$
			for (int j = 0; j < i; j++) {
				i_dent += ">"; //$NON-NLS-1$
			}
			//各階層の要素タグをListに登録。階層数は>の数で示す。
			layer_model.addElement(i_dent + " " + m_paths[i]); //$NON-NLS-1$
		}

		SpinnerNumberModel snm = new SpinnerNumberModel(0, 0, m_paths.length - 1, 1);
		final JSpinner spinner = new JSpinner(snm);

		//最大公約数的なxpathを作る。
		String[] reps = repXPath.split("/");
		String temp_rep = "";
		if (repXPath.length() > 0) {
			for (int i = 0; i < reps.length; i++) {
				if (reps[i].equals(m_paths[i])) {
					if (temp_rep.length() > 0) {
						temp_rep += "/";
					}
					temp_rep += reps[i];
				} else if (i == 0) {
					//最初から共通項がない。独立系なので代表は変えない。
					spinner.setEnabled(false);
					break;
				} else {
					repXPath = temp_rep;
					break;
				}
			}
		}

		if (pathMap.containsKey(getCurKey(0, true) + "#attrMap")) { //$NON-NLS-1$
			m_attrMap = (HashMap<String, String>)pathMap.get(getCurKey(0, true) + "#attrMap"); //$NON-NLS-1$
		} else {
			m_attrMap = new HashMap<String, String>();
		}
		if (repMap != null && repMap.size() > 0) {
			//代表Xpathの属性が設定されている場合、m_attrMapに移す。
			for (Entry<String, String> entry: repMap.entrySet()) {
				m_attrMap.put(entry.getKey(), entry.getValue());
			}
		}

		final JList<String> tagLayerList = new JList<String>(layer_model);
		scrollPane.setViewportView(tagLayerList);

		childTextField = new JTextField();
		childTextField.setBounds(282, 33, 329, 19);
		getContentPane().add(childTextField);
		childTextField.setColumns(10);

		//代表パスと子パスを入れる。
		repTextField.setText(repXPath);

		String chtext = curPath.replaceFirst("^" + Pattern.quote(repXPath) + "/", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		childTextField.setText(chtext);

		JLabel lblNewLabel = new JLabel(Messages.getString("XpathEditor4Element.13")); //$NON-NLS-1$
		lblNewLabel.setBounds(12, 10, 258, 13);
		getContentPane().add(lblNewLabel);

		JLabel lblNewLabel_1 = new JLabel(Messages.getString("XpathEditor4Element.14")); //$NON-NLS-1$
		lblNewLabel_1.setBounds(283, 10, 258, 13);
		getContentPane().add(lblNewLabel_1);

		JScrollPane scrollPane_1 = new JScrollPane();
		scrollPane_1.setBounds(165, 86, 447, 206);
		getContentPane().add(scrollPane_1);

		//元からの属性は先頭//でコメントアウトの形。コメントを外すと、有効になる。
		final JTextArea textPane = new JTextArea();
		scrollPane_1.setViewportView(textPane);

		tagLayerList.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				int n = tagLayerList.getSelectedIndex();
				if (m_prevpos != n) {
					if (m_prevpos >= 0) {
						String p_path = getCurKey(m_prevpos, true);
						String t_data = textPane.getText();
						if (p_path.length() > 0) {
							m_attrMap.put(p_path, t_data);
						}
					}
				}
				if (n >= 0) {
					String s_path = getCurKey(n, true);
					if (m_attrMap.containsKey(s_path)) {
						//編集中の情報があるなら、そのまま表示する。
						textPane.setText(m_attrMap.get(s_path));
					} else if (s_path.length() > 0) {
						//以下は初期値

						HashMap<String, String> t_map = null;
						if (!m_pathmap.containsKey(s_path)) {
							//初回などで情報がない場合、下からのPathを試みる。
							t_map = (HashMap<String, String>)Tool.getObjectfromJSON(HashMap.class, m_pathmap.get(getCurKey(n, false)).toString());
						} else {
							t_map = (HashMap<String, String>)Tool.getObjectfromJSON(HashMap.class, m_pathmap.get(s_path).toString());
						}
						if (t_map != null && t_map.size() > 0) {
							String t_str = ""; //$NON-NLS-1$
							for (Map.Entry<String, String> entry : t_map.entrySet()) {
								if (t_str.length() > 0) {
									t_str += "\n"; //$NON-NLS-1$
								}
								//初期表示はコメントである。
								t_str += "//[@" + entry.getKey() + "='" + entry.getValue() + "']"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
							}
							if (t_str.length() > 0) {
								textPane.setText(t_str);
								m_attrMap.put(s_path, t_str);
							}
						}
					}
					m_prevpos = n;
				}
			}
		});

		JLabel lblNewLabel_2 = new JLabel(Messages.getString("XpathEditor4Element.20")); //$NON-NLS-1$
		lblNewLabel_2.setBounds(12, 66, 98, 13);
		getContentPane().add(lblNewLabel_2);

		JLabel lblNewLabel_3 = new JLabel(Messages.getString("XpathEditor4Element.21")); //$NON-NLS-1$
		lblNewLabel_3.setBounds(165, 63, 151, 13);
		getContentPane().add(lblNewLabel_3);

		JButton btnOK = new JButton(Messages.getString("XpathEditor4Element.22")); //$NON-NLS-1$
		btnOK.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				//今、編集中の属性を一旦格納する。
				if (m_prevpos >= 0) {
					String p_path = getCurKey(m_prevpos, true);
					String t_data = textPane.getText();
					if (p_path.length() > 0) {
						//ノード位置が変わったら自動的に一時保存する。
						m_attrMap.put(p_path, t_data);
					}
				}

				m_result = m_attrMap;
				m_result.put("representative", repTextField.getText()); //$NON-NLS-1$
				m_result.put("subxpath", childTextField.getText()); //$NON-NLS-1$

				setVisible(false);
			}
		});
		btnOK.setBounds(202, 300, 91, 21);
		getContentPane().add(btnOK);

		JButton btnCancel = new JButton(Messages.getString("XpathEditor4Element.25")); //$NON-NLS-1$
		btnCancel.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				m_result = null;
				setVisible(false);
			}
		});
		btnCancel.setBounds(331, 300, 91, 21);
		getContentPane().add(btnCancel);

		JButton btnReset = new JButton(Messages.getString("XpathEditor4Element.26")); //$NON-NLS-1$
		btnReset.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				textPane.setText(""); //$NON-NLS-1$

				int n = tagLayerList.getSelectedIndex();
				String s_path = ""; //$NON-NLS-1$
				for (int i = n; i < m_paths.length; i++) {
					if (s_path.length() > 0) {
						s_path += "/"; //$NON-NLS-1$
					}
					s_path += m_paths[i];
				}
				//メモリ上の情報をクリア
				if (m_attrMap.containsKey(s_path)) {
					m_attrMap.remove(s_path);
				}

				//以下は初期値
				HashMap<String, String> t_map = (HashMap<String, String>)Tool.getObjectfromJSON(HashMap.class, m_pathmap.get(s_path).toString());
				if (t_map != null && t_map.size() > 0) {
					String t_str = ""; //$NON-NLS-1$
					for (Map.Entry<String, String> entry : t_map.entrySet()) {
						if (t_str.length() > 0) {
							t_str += "\n"; //$NON-NLS-1$
						}
						t_str += "//[@" + entry.getKey() + "='" + entry.getValue() + "']"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
					}
					if (t_str.length() > 0) {
						textPane.setText(t_str);
						m_attrMap.put(s_path, t_str);
					}
				}
			}
		});
		btnReset.setBounds(520, 62, 91, 21);
		getContentPane().add(btnReset);

		spinner.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				Integer i = (Integer)spinner.getValue();
				if (m_spinpos != i) {
					String old_key = null;
					if (m_spinpos < i && m_spinpos > 0) {
						//repが延びる。
						old_key = getCurKey(m_spinpos, true);
					}
					//0はrep=""、1で最初の要素。
					m_spinpos = i;

					String t_rep = ""; //$NON-NLS-1$
					String t_child = ""; //$NON-NLS-1$

					for (int j = 0; j < m_paths.length; j++) {
						if (j < m_spinpos) {
							if (t_rep.length() > 0) {
								t_rep += "/"; //$NON-NLS-1$
							}
							t_rep += m_paths[j];
						} else {
							if (t_child.length() > 0) {
								t_child += "/"; //$NON-NLS-1$
							}
							t_child += m_paths[j];
						}
					}
					repTextField.setText(t_rep);
					childTextField.setText(t_child);

					if (old_key != null && m_spinpos > 0) {
						//repの範囲が変わったので、子属性をそちらに移す。
						String new_key = getCurKey(m_spinpos - 1, true);
						String n_val = m_attrMap.get(old_key);
						m_attrMap.put(new_key, n_val);
					}
				}
			}
		});
		if (b_single) {
			//単要素の場合、代表Pathは変更しない。
			spinner.setEnabled(false);
		}
		if (repXPath.length() > 0) {
			int n = repXPath.split("/").length; //$NON-NLS-1$
			spinner.setValue(n);

			//0はrep=""、1で最初の要素。
			m_spinpos = n;
		}
		spinner.setBounds(545, 7, 66, 20);
		getContentPane().add(spinner);
	}

	//先頭から要素からのPathを使ってキーを作る
	// b_repがtrueなら、代表pathの要素を頭から数える。
	private String getCurKey(int n, boolean b_rep) {
		String t_rep = repTextField.getText();
		String s_path = ""; //$NON-NLS-1$

		if (b_rep && t_rep.length() > 0) {
			String[] temp = t_rep.split("/"); //$NON-NLS-1$
			if (n < temp.length) {
				for (int i = 0; i < n + 1; i++) {
					if (s_path.length() > 0) {
						s_path += "/"; //$NON-NLS-1$
					}
					s_path += temp[i];
				}
				s_path = "//" + s_path; //$NON-NLS-1$
			}
		}
		if (s_path.length() == 0) {
			//単独コントロール
			if (m_paths != null) {
				for (int i = n; i < m_paths.length; i++) {
					if (s_path.length() > 0) {
						s_path += "/"; //$NON-NLS-1$
					}
					s_path += m_paths[i];
				}
			}
		}
		return s_path;
	}

	protected HashMap<String, String> getResult() {
		return m_result;
	}

	protected HashMap<String, String> getRepDictionary() {
		return m_repdic;
	}

}
