package cn.net.connor.std.processedit.processview;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.DefaultCellEditor;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;

import com.teamcenter.rac.aif.kernel.AIFComponentContext;
import com.teamcenter.rac.aifrcp.AIFUtility;
import com.teamcenter.rac.kernel.TCComponent;
import com.teamcenter.rac.kernel.TCComponentBOMLine;
import com.teamcenter.rac.kernel.TCComponentDataset;
import com.teamcenter.rac.kernel.TCComponentFolder;
import com.teamcenter.rac.kernel.TCComponentItem;
import com.teamcenter.rac.kernel.TCComponentItemRevision;
import com.teamcenter.rac.kernel.TCSession;
import com.teamcenter.rac.treetable.SwingTextContextActivator;
import com.teamcenter.rac.util.MessageBox;
import com.teamcenter.rac.util.Registry;
import com.teamcenter.rac.util.iTextField;
import com.teamcenter.rac.util.combobox.iComboBox;

import cn.net.connor.std.aifrcp.util.KEmptyDialog;
import cn.net.connor.std.aifrcp.util.KTableRowTableLoader;
import cn.net.connor.std.aifrcp.util.KUtil;
import cn.net.connor.std.processedit.newmeop.NewMeopDialogController;
import cn.net.connor.std.processedit.processview.safeicon.SafeIconBean;
import cn.net.connor.std.processedit.processview.safeicon.SafeIconDialog;
import cn.net.connor.std.processedit.util.PrefComponent;
import cn.net.connor.std.processedit.util.ProcessUtil;

@SuppressWarnings("serial")
public class PropertyPanel extends JPanel {

	private TCComponentBOMLine targetLine;
	public static final String PREF_SAFE_ICON = "connor_process_aqtb_zsjm";
	public static final String PREF_TABLEROW = "connor_process_ggjl";
	public static final String PREF_PREFIX = "Connor_AVIC_ME_Properties_";
	public static final String PREF_TABLEROW_EDITABLE = "connor_process_ggjl_editable";
	private List<PrefComponent> prefComponents = new ArrayList<PrefComponent>();
	private String relRevIcon;
	private String propRevIconDesc;
	private SafeIconBean safeIconRootNode;
	private JTable t_SafeIcon;
	private KTableRowTableLoader t_TableRow;
	private DefaultTableModel tm_SafeIcon;
	private JTextArea ta_SafeDesc;
	private List<String> iconDatasetTypes;
	public static final String FLAG_HIDE_LISTENTER = "HIDE_LISTENER:";
	private static final Registry REG = Registry.getRegistry(PropertyPanel.class);
	private Map<String, TCComponent> revChildren = new HashMap<>();
	private iTextField tf_WorkCenter;
	private KAssignResourceCommand workcenterCmd;
	private TCComponentBOMLine currentWorkCenter;

	public boolean refreshUI(TCComponentBOMLine targetLine) throws Exception {
		System.out.println("Reload: " + targetLine);
		if (targetLine != null && targetLine.equals(this.targetLine)) {
			System.out.println("SKIP LOAD");
			return true;
		}
		if (isModified(targetLine)) {
			int op = JOptionPane.showConfirmDialog(this, REG.getString("savedata.INFO"), REG.getString("info"), JOptionPane.YES_NO_CANCEL_OPTION);
			if (op == JOptionPane.YES_OPTION) {// save
				try {
					save();
				} catch (Exception e) {
					e.printStackTrace();
					MessageBox.post(e);
					return true;
				}
			} else if (op == JOptionPane.NO_OPTION) {// change

			} else {// do nothing
				return true;
			}
		}
		this.removeAll();
		this.currentWorkCenter = null;
		this.setLayout(new GridBagLayout());
		this.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
		GridBagConstraints s = new GridBagConstraints(0, 0, 1, 1, 0, 0, GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(6, 5, 6, 5), 0, 0);
		if (targetLine == null) {
			this.targetLine = null;
			KUtil.newRow(this, new JLabel(REG.getString("processviewnoselect.INFO")), s, 1);
			return false;
		}
		this.targetLine = targetLine;
		this.ta_SafeDesc = null;
		this.t_SafeIcon = null;
		this.t_TableRow = null;
		this.tm_SafeIcon = null;
		TCSession session = targetLine.getSession();
		TCComponentItem targetItem = targetLine.getItem();
		String itemType = targetItem.getType();
		if (ProcessUtil.isMEOP(session, itemType)) {
			this.workcenterCmd = new KAssignResourceCommand(KUtil.getPrefVal(session, NewMeopDialogController.PREF_WORKCENTER_CLS_ID), this.targetLine);
		} else {
			this.workcenterCmd = null;
		}
		System.out.println("Type: " + itemType);
		String prefName = PREF_PREFIX + itemType;
		String[] prefs = KUtil.getPrefVals(session, prefName);
		this.prefComponents.clear();
		this.revChildren.clear();
		int len = KUtil.getLen(prefs);
		Map<String[], String[]> hideListenerMap = new HashMap<String[], String[]>();
		System.out.println("Load Pref: " + prefName);
		for (int i = 0; i < len; i++) {
			String pref = prefs[i];
			if (pref.startsWith(FLAG_HIDE_LISTENTER)) {
				String cond = pref.substring(FLAG_HIDE_LISTENTER.length());
				System.out.println("Hide Listener: " + cond);
				int ind = cond.indexOf(':');
				if (ind > 0) {
					String[] hidePropNames = cond.substring(ind + 1).split(";");
					cond = cond.substring(0, ind);
					ind = cond.indexOf('=');
					if (ind > 0) {
						String condPropName = cond.substring(0, ind);
						String condPropValue = cond.substring(ind + 1);
						if (!KUtil.isEmpty(condPropName) && KUtil.getLen(hidePropNames) > 0) {
							hideListenerMap.put(new String[] { condPropName, condPropValue }, hidePropNames);
						}
					}
				}
				continue;
			}
			PrefComponent comp = new PrefComponent(pref, itemType);
			if (comp.init(session)) {
				if (comp.canDisplay(targetLine.getItemRevision())) {
					this.prefComponents.add(comp);
				} else {
					System.out.println("HIDE Config: " + pref);
				}
			} else {
				System.out.println("ERROR Config: " + pref);
			}
		}
		if (this.prefComponents.size() == 0) {
			System.out.println("No Valid Pref: " + prefName);
			KUtil.newRow(this, new JLabel(String.format(REG.getString("prefnotconfiged.ERROR1"), prefName)), s, 1);
			return false;
		}
		Map<PrefComponent, JButton> chooseFromExcelComponents = new HashMap<PrefComponent, JButton>();
		Map<PrefComponent, JButton> chooseFromSqlComponents = new HashMap<PrefComponent, JButton>();
		for (PrefComponent prefComponent : prefComponents) {
			KUtil.newRow(this, prefComponent.getLabel(), s, 1);
			JComponent valueComp = prefComponent.getValueComp();
			if (valueComp instanceof JTextArea) {
				JScrollPane scroll = new JScrollPane(valueComp);
				prefComponent.addAdditionalComp(scroll);
				s.gridheight = 2;
				KUtil.addCol(this, scroll, s, 1, 1);
				s.gridheight = 1;
			} else {
				KUtil.addCol(this, valueComp, s, 1, 1);
			}
			if (KUtil.getLen(prefComponent.getExcelConfig()) > 0) {
				JButton b_choose = new JButton(REG.getString("select"));
				KUtil.addCol(this, b_choose, s, 1, 0);
				chooseFromExcelComponents.put(prefComponent, b_choose);
				prefComponent.addAdditionalComp(b_choose);
			}
			if (KUtil.getLen(prefComponent.getSqlConfig()) > 0) {
				JButton b_choose = new JButton(REG.getString("select"));
				KUtil.addCol(this, b_choose, s, 1, 0);
				chooseFromSqlComponents.put(prefComponent, b_choose);
				prefComponent.addAdditionalComp(b_choose);
			}
			if (valueComp instanceof JTextArea) {
				s.gridy++;
			}
		}
		// 添加工作中心
		{
			addWorkcenter(session, s);
		}
		// 添加安全图标
		{
			addSafeIconPanel(session, s);
		}
		// 添加表格行
		{
			addTableRowPanel(session, s);
		}
		/////////////
		s.gridx = 5;
		KUtil.addCol(this, new JLabel(""), s, 1, 1);
		s.weighty = 1;
		KUtil.newRow(this, new JLabel(""), s, 1);
		for (PrefComponent bean : chooseFromExcelComponents.keySet()) {
			JButton btn = chooseFromExcelComponents.get(bean);
			btn.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					bean.performChoose(new KEmptyDialog(), itemType, AIFUtility.getCurrentApplication(), prefComponents);
				}
			});
		}
		for (PrefComponent bean : chooseFromSqlComponents.keySet()) {
			JButton btn = chooseFromSqlComponents.get(bean);
			btn.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					bean.performChooseFromSql(null, AIFUtility.getCurrentApplication(), prefComponents, revChildren);
				}
			});
		}
		// add Hide Listener
		for (String[] hideProp : hideListenerMap.keySet()) {
			String condPropName = hideProp[0];
			String condPropValue = hideProp[1];
			String[] hidePropNames = hideListenerMap.get(hideProp);
			for (PrefComponent prefComponent : prefComponents) {
				if (!condPropName.equals(prefComponent.getPropConfig())) {
					continue;
				}
				System.out.println(">> Add Hide Listener: " + condPropName);
				JComponent valueComp = prefComponent.getValueComp();
				if (valueComp instanceof iComboBox) {
					((iComboBox) valueComp).addActionListener(new ActionListener() {
						@Override
						public void actionPerformed(ActionEvent arg0) {
							String item = prefComponent.getValue();
							System.out.println("[Check Hide] Select: " + item);
							if (item == null) {
								item = "";
							}
							boolean visible = !condPropValue.equals(item);
							System.out.println("Set Visible: " + visible + " -> " + Arrays.toString(hidePropNames));
							for (PrefComponent prefComponent : prefComponents) {
								if (KUtil.inArray(prefComponent.getPropConfig(), hidePropNames) >= 0) {
									System.out.println(">> " + prefComponent.getPropConfig());
									prefComponent.setVisible(visible);
								}
							}
							revalidate();
							repaint();
						}
					});
				}
			}
		}
		// Load Property
		loadData();
		return true;
	}

	private void addWorkcenter(TCSession session, GridBagConstraints s) {
		if (this.workcenterCmd == null) {
			return;
		}
		KUtil.newRow(this, new JLabel(REG.getString("workcenter")), s, 1);
		this.tf_WorkCenter = new iTextField(18);
		this.tf_WorkCenter.setRequired(true);
		this.tf_WorkCenter.setEditable(false);
		KUtil.addCol(this, tf_WorkCenter, s, 1, 1);
		JButton b_WorkCenter;
		KUtil.addCol(this, b_WorkCenter = new JButton(REG.getString("select")), s, 1, 0);
		b_WorkCenter.addActionListener(e -> {
			try {
				chooseWorkCenter(session);
			} catch (Exception e1) {
				e1.printStackTrace();
				MessageBox.post(e1);
			}
		});
	}

	public void chooseWorkCenter(TCSession session) throws Exception {
		this.workcenterCmd.executeModal();
		TCComponent comp = workcenterCmd.getSelected();
		tf_WorkCenter.setText(comp == null ? "" : comp.toString());
	}

	public void loadCurrentWorkcenter() throws Exception {
		if (this.workcenterCmd == null) {
			return;
		}
		this.currentWorkCenter = null;
		AIFComponentContext[] cc = this.targetLine.getChildren();
		int len = KUtil.getLen(cc);
		for (int i = 0; i < len; i++) {
			TCComponentBOMLine cLine = (TCComponentBOMLine) cc[i].getComponent();
			TCComponentItemRevision cRev = cLine.getItemRevision();
			if (cRev == null) {
				continue;
			}
			// this.currentWorkCenter = cLine; // TODO
			if ("NHL8_EquipmentsRevision".equals(cRev.getType())) {
				this.currentWorkCenter = cLine;
				System.out.println("Current Workcenter: " + this.currentWorkCenter);
				break;
			}
		}
		tf_WorkCenter.setText(this.currentWorkCenter == null ? "" : this.currentWorkCenter.toString());
	}

	private void addTableRowPanel(TCSession session, GridBagConstraints s) throws Exception {
		Boolean editableValue = session.getPreferenceService().getLogicalValue(PREF_TABLEROW_EDITABLE);
		boolean editable = editableValue != null && editableValue;
		this.t_TableRow = KTableRowTableLoader.parse(session, targetLine.getItemRevision().getRelatedComponent("IMAN_master_form_rev"), PREF_TABLEROW, editable);
		if (this.t_TableRow == null) {
			return;
		}
		JComponent tablePanel = this.t_TableRow.getTablePanel();
		KUtil.newRow(this, new JLabel(REG.getString("ggjl.LABEL")), s, 1);
		s.gridheight = 3;
		KUtil.addCol(this, tablePanel, s, 1, 0);
		tablePanel.setPreferredSize(new Dimension(300, 200));
		s.gridheight = 1;
		if (!editable) {
			s.gridy += 2;
			return;
		}
		JTable table = this.t_TableRow.getTable();
		JTextField tf_Cell = new JTextField();;
		table.setDefaultEditor(Object.class, new DefaultCellEditor(tf_Cell));
		tf_Cell.addFocusListener(new FocusAdapter() {
			public void focusGained(FocusEvent param1FocusEvent) {
				SwingTextContextActivator.instance().activateContext();
			}
			
			public void focusLost(FocusEvent param1FocusEvent) {
				super.focusLost(param1FocusEvent);
				SwingTextContextActivator.instance().deactivateContext();
			}
		});
		JButton addBtn = new JButton("+");
		JButton removeBtn = new JButton("-");
		KUtil.addCol(this, addBtn, s, 1, 0);
		s.gridy++;
		this.add(removeBtn, s);
		s.gridy++;
		addBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					t_TableRow.addRow(null);
				} catch (Exception e1) {
					e1.printStackTrace();
					MessageBox.post(e1);
				}
			}
		});
		removeBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					t_TableRow.removeRow();
				} catch (Exception e1) {
					e1.printStackTrace();
					MessageBox.post(e1);
				}
			}
		});
	}

	private void addSafeIconPanel(TCSession session, GridBagConstraints s) throws Exception {
		String[] iconProps = KUtil.getPrefVals(session, PREF_SAFE_ICON);
		System.out.println("Safe Icon2: " + Arrays.toString(iconProps));
		int len = KUtil.getLen(iconProps);
		if (len == 1) {
			this.propRevIconDesc = iconProps[0].trim();
			KUtil.newRow(this, new JLabel(REG.getString("safedesc.LABEL")), s, 1);
			this.ta_SafeDesc = new JTextArea(8, 28);
			s.gridheight = 3;
			KUtil.addCol(this, new JScrollPane(ta_SafeDesc), s, 1, 0);
			s.gridheight = 1;
			s.gridy += 2;
		}
		if (len < 5) {
			return;
		}
		TCComponentFolder iconFolder = (TCComponentFolder) session.stringToComponent(iconProps[0]);
		System.out.println("Icon folder: " + iconFolder);
		this.relRevIcon = iconProps[1].trim();
		this.propRevIconDesc = iconProps[2].trim();
		String[] dsTypeArr = iconProps[3].split(";");
		String[] itemTypes = iconProps[4].split(";");
		String targetType = this.targetLine == null ? null : this.targetLine.getItem().getType();
		System.out.println("Target type: " + targetType);
		if (KUtil.isEmpty(targetType) || KUtil.inArray(targetType, itemTypes) < 0) {
			return;
		}
		this.iconDatasetTypes = new ArrayList<>();
		for (String string : dsTypeArr) {
			iconDatasetTypes.add(string);
		}
		this.safeIconRootNode = SafeIconBean.parse(iconFolder, iconDatasetTypes);
		System.out.println("Icon Root: " + safeIconRootNode);
		if (safeIconRootNode == null) {
			return;
		}
		String[] header = REG.getStringArray("safeicon.HEADER");
		String[] headerWidth = REG.getStringArray("safeicon.HEADERWIDTH");
		this.tm_SafeIcon = new DefaultTableModel() {
			@Override
			public boolean isCellEditable(int row, int column) {
				return false;
			}
		};
		this.t_SafeIcon = new JTable(tm_SafeIcon);
		t_SafeIcon.setRowHeight(26);
		tm_SafeIcon.setDataVector(null, header);
		t_SafeIcon.getTableHeader().setReorderingAllowed(false);
		t_SafeIcon.getColumnModel().getColumn(2).setCellRenderer(t_SafeIcon.getDefaultRenderer(ImageIcon.class));
		TableColumnModel colModel = t_SafeIcon.getColumnModel();
		int colCnt = KUtil.getLen(headerWidth);
		for (int i = 0; i < colCnt; i++) {
			colModel.getColumn(i).setPreferredWidth(Integer.parseInt(headerWidth[i]));
		}
		KUtil.newRow(this, new JLabel(REG.getString("safeicon.LABEL")), s, 1);
		s.gridheight = 3;
		JScrollPane ss;
		KUtil.addCol(this, ss = new JScrollPane(t_SafeIcon), s, 1, 0);
		ss.setPreferredSize(new Dimension(300, 200));
		s.gridheight = 1;
		JButton addBtn = new JButton("+");
		JButton removeBtn = new JButton("-");
		KUtil.addCol(this, addBtn, s, 1, 0);
		s.gridy++;
		this.add(removeBtn, s);
		s.gridy++;
		// KUtil.newRow(this, new JLabel(REG.getString("safedesc.LABEL")), s, 1);
		// this.ta_SafeDesc = new JTextArea(8, 28);
		// s.gridheight = 3;
		// KUtil.addCol(this, ss = new JScrollPane(ta_SafeDesc), s, 1, 0);
		// s.gridheight = 1;
		// s.gridy += 2;
		addBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					addSafeIcon();
				} catch (Exception e1) {
					e1.printStackTrace();
					MessageBox.post(e1);
				}
			}
		});
		removeBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					removeSafeIcon();
				} catch (Exception e1) {
					e1.printStackTrace();
					MessageBox.post(e1);
				}
			}
		});
	}

	protected void removeSafeIcon() throws Exception {
		int[] rows = t_SafeIcon.getSelectedRows();
		if (rows == null) {
			return;
		}
		Arrays.sort(rows);
		System.out.println("Remove icons: " + Arrays.toString(rows));
		int len = rows.length;
		for (int i = len - 1; i >= 0; i--) {
			tm_SafeIcon.removeRow(rows[i]);
		}
		int rowCnt = tm_SafeIcon.getRowCount();
		for (int i = 0; i < rowCnt; i++) {
			tm_SafeIcon.setValueAt("" + (i + 1), i, 0);
		}
	}

	protected void addSafeIcon() throws Exception {
		SwingUtilities.invokeLater(new SafeIconDialog(safeIconRootNode, tm_SafeIcon));
	}

	public boolean isModified(TCComponentBOMLine targetLine) {
		for (PrefComponent prefComponent : prefComponents) {
			if (prefComponent.isModified()) {
				System.out.println("PROP Change: " + prefComponent.getPropConfig() + " -> " + prefComponent.getValue());
				return true;
			}
		}
		if (this.targetLine != null) {
			try {
				TCComponentItemRevision rev = this.targetLine.getItemRevision();
				System.out.println("Check modified: " + rev);
				if (ta_SafeDesc != null) {
					String oldValue = rev.getProperty(propRevIconDesc);
					String newValue = ta_SafeDesc.getText();
					if (!newValue.equals(oldValue)) {
						System.out.println("PROP Change " + propRevIconDesc + ": " + oldValue + " -> " + newValue);
						return true;
					}
				}
				if (tm_SafeIcon != null) {
					List<TCComponent> children = new ArrayList<TCComponent>();
					int rowCnt = tm_SafeIcon.getRowCount();
					for (int i = 0; i < rowCnt; i++) {
						SafeIconBean bean = (SafeIconBean) tm_SafeIcon.getValueAt(i, 1);
						if (!children.contains(bean.getIconDataset())) {
							children.add(bean.getIconDataset());
						}
					}
					TCComponent[] oldChildren = rev.getRelatedComponents(relRevIcon);
					if (!Arrays.equals(children.toArray(new TCComponent[] {}), oldChildren)) {
						System.out.println("PROP Change: " + relRevIcon + " " + Arrays.toString(oldChildren) + " -> " + children);
						return true;
					}
				}
				if (t_TableRow != null) {
					if (t_TableRow.isModified()) {
						return true;
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return false;
	}

	public void loadData() throws Exception {
		System.out.println("Load Data...");
		TCComponentItemRevision rev = this.targetLine.getItemRevision();
		TCComponentItem item = this.targetLine.getItem();
		TCComponent revForm = rev.getRelatedComponent("IMAN_master_form_rev");
		if (revForm == null) {
			throw new Exception(String.format(REG.getString("nomasterform.ERROR1"), rev.toString()));
		}
		TCComponent itemForm = item.getRelatedComponent("IMAN_master_form");
		if (itemForm == null) {
			throw new Exception(String.format(REG.getString("nomasterform.ERROR1"), item.toString()));
		}
		for (PrefComponent prefComponent : prefComponents) {
			String propConfig = prefComponent.getPropConfig();
			String propFrom = null, propName = null;
			String[] split = propConfig.split("\\.");
			if (KUtil.getLen(split) == 2) {
				propFrom = split[0].trim().toUpperCase();
				propName = split[1].trim();
			}
			if (KUtil.isEmpty(propFrom) || KUtil.isEmpty(propName)) {
				continue;
			}
			if ("ITEM".equals(propFrom)) {
				prefComponent.setValueAndSave(prefComponent.getProperty(item));
			} else if ("REV".equals(propFrom)) {
				prefComponent.setValueAndSave(prefComponent.getProperty(rev));
			} else if ("ITEMMASTER".equals(propFrom)) {
				prefComponent.setValueAndSave(prefComponent.getProperty(itemForm));
			} else if ("REVMASTER".equals(propFrom)) {
				prefComponent.setValueAndSave(prefComponent.getProperty(revForm));
			} else {
				throw new Exception(String.format(REG.getString("proplocationnotdefined.ERROR1"), propFrom));
			}
		}
		if (ta_SafeDesc != null) {
			ta_SafeDesc.setText(rev.getProperty(propRevIconDesc));
		}
		if (tm_SafeIcon != null) {
			this.tm_SafeIcon.getDataVector().clear();
			TCComponent[] children = rev.getRelatedComponents(relRevIcon);
			int len = KUtil.getLen(children);
			for (int i = 0; i < len; i++) {
				SafeIconBean bean = SafeIconBean.parse(children[i], iconDatasetTypes);
				if (bean != null) {
					tm_SafeIcon.addRow(bean.getRowData(tm_SafeIcon.getRowCount() + 1));
				}
			}
		}
		if (t_TableRow != null) {
			t_TableRow.loadTCData();
		}
		loadCurrentWorkcenter();
		System.out.println("Load Data Complete");
	}

	public void save() throws Exception {
		System.out.println("Save..." + this.targetLine);
		if (this.targetLine == null || !checkRequire()) {
			return;
		}
		// Save
		Map<String, String> revPropMap = new HashMap<>();
		Map<String, String> revMasterPropMap = new HashMap<>();
		Map<String, String> itemPropMap = new HashMap<>();
		Map<String, String> itemMasterPropMap = new HashMap<>();
		for (PrefComponent prefComponent : this.prefComponents) {
			KUtil.initPropMap(prefComponent.getPropConfig(), prefComponent.getValue(), itemPropMap, itemMasterPropMap, revPropMap, revMasterPropMap);
		}
		TCComponentItemRevision rev = this.targetLine.getItemRevision();
		TCComponentItem item = this.targetLine.getItem();
		if (itemPropMap.size() > 0) {
			item.setProperties(itemPropMap);
		}
		if (itemMasterPropMap.size() > 0) {
			TCComponent itemForm = item.getRelatedComponent("IMAN_master_form");
			if (itemForm != null) {
				itemForm.setProperties(itemPropMap);
			}
		}
		if (ta_SafeDesc != null) {
			String safeDesc = ta_SafeDesc.getText();
			revPropMap.put(propRevIconDesc, safeDesc);
		}
		if (revPropMap.size() > 0) {
			rev.setProperties(revPropMap);
		}
		if (revMasterPropMap.size() > 0) {
			TCComponent revForm = rev.getRelatedComponent("IMAN_master_form_rev");
			if (revForm != null) {
				revForm.setProperties(revMasterPropMap);
			}
		}
		if (tm_SafeIcon != null) {
			List<TCComponentDataset> children = new ArrayList<TCComponentDataset>();
			int rowCnt = tm_SafeIcon.getRowCount();
			for (int i = 0; i < rowCnt; i++) {
				SafeIconBean bean = (SafeIconBean) tm_SafeIcon.getValueAt(i, 1);
				if (!children.contains(bean.getIconDataset())) {
					children.add(bean.getIconDataset());
				}
			}
			System.out.println("Set Security Icons: " + children);
			TCComponent[] oldChildren = rev.getRelatedComponents(relRevIcon);
			System.out.println("Remove Old Icons: " + Arrays.toString(oldChildren));
			if (KUtil.getLen(oldChildren) > 0) {
				rev.remove(relRevIcon, oldChildren);
			}
			if (children.size() > 0) {
				rev.add(relRevIcon, children);
			}
		}
		if (t_TableRow != null) {
			t_TableRow.saveTCData();
		}
		System.out.println("Add children " + this.revChildren);
		if (revChildren.size() > 0) {
			rev.refresh();
			for (String relationName : revChildren.keySet()) {
				TCComponent comp = revChildren.get(relationName);
				TCComponent[] oldChildren = rev.getRelatedComponents(relationName);
				System.out.println(">> Old children: " + Arrays.toString(oldChildren));
				if (KUtil.getLen(oldChildren) > 0) {
					rev.remove(relationName, oldChildren);
				}
				rev.add(relationName, comp);
			}
			rev.refresh();
		}
		// workcenter
		if (this.workcenterCmd != null && this.workcenterCmd.getSelected() != null) {
			if (this.currentWorkCenter != null) {
				this.currentWorkCenter.cut();
				this.currentWorkCenter = null;
			}
			this.workcenterCmd.doAssign(this.targetLine);
		}
		this.targetLine.refresh();
		loadData();
		System.out.println("Save Success");
	}

	private boolean checkRequire() {
		List<String> requireTitles = new ArrayList<String>();
		for (PrefComponent prefComponent : this.prefComponents) {
			if (!prefComponent.checkRequire()) {
				requireTitles.add(prefComponent.getTitle().replace(" ", "").replace(":", "").replace(REG.getString("CN_SYMBEL4"), "").replace(REG.getString("CN_SYMBEL5"), ""));
			}
		}
		if (requireTitles.size() > 0) {
			MessageBox.post(String.format(REG.getString("requireprop.INFO1"), requireTitles.toString()), "", MessageBox.WARNING);
			return false;
		}
		return true;
	}

}
