package cn.net.connor.std.processedit.meopviewfx.ui;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.teamcenter.rac.kernel.TCComponent;
import com.teamcenter.rac.kernel.TCComponentBOMLine;
import com.teamcenter.rac.kernel.TCComponentBOMLineType;
import com.teamcenter.rac.kernel.TCComponentItemRevision;
import com.teamcenter.rac.kernel.TCComponentItemRevisionType;
import com.teamcenter.rac.kernel.TCComponentItemType;
import com.teamcenter.rac.kernel.TCComponentListOfValues;
import com.teamcenter.rac.kernel.TCComponentType;
import com.teamcenter.rac.kernel.TCProperty;
import com.teamcenter.rac.kernel.TCPropertyDescriptor;
import com.teamcenter.rac.kernel.TCSession;
import com.teamcenter.rac.treetable.SwingTextContextActivator;
import com.teamcenter.rac.util.Registry;

import cn.net.connor.std.aifrcp.util.KUtil;
import cn.net.connor.std.fx.KFXTextLocator;
import cn.net.connor.std.fx.KLOVComboBox;
import cn.net.connor.std.processedit.meopviewfx.bean.KTableRow;
import cn.net.connor.std.processedit.meopviewfx.bean.PropConfig;
import cn.net.connor.std.processedit.util.ProcessUtil;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Pos;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Control;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.TextInputControl;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.Region;

@SuppressWarnings("unchecked")
public class PropFlowLoader extends KFXTextLocator {

	protected List<PropConfig> propConfigs = new ArrayList<PropConfig>();
	private TCSession session;
	private static final Registry REG = Registry.getRegistry(PropFlowLoader.class);

	public PropFlowLoader(TCSession session) {
		this.session = session;
	}

	public boolean load(FlowPane flowPane, String prefName, TCComponentItemType itemType) throws Exception {
		clearLocatorData();
		Platform.runLater(() -> {
			flowPane.getChildren().clear();
		});
		propConfigs.clear();
		if (KUtil.isEmpty(prefName) || itemType == null) {
			return false;
		}
		System.out.println("Load FlowPane from pref: " + prefName);
		String[] prefVals = KUtil.getPrefVals(session, prefName);
		int len = KUtil.getLen(prefVals);
		if (len <= 1) {
			return false;
		}
		System.out.println(">> Item Type: " + itemType.getDisplayTypeName());
		TCComponentType revMasterType = null;
		TCComponentBOMLineType bomlineType = null;
		TCComponentItemRevisionType revType = itemType.getItemRevisionType();
		revMasterType = session.getTypeComponent(revType.getTypeName() + "Master");
		if (revMasterType == null) {
			revMasterType = session.getTypeComponent(revType.getTypeName() + " Master");
		}
		if (revMasterType == null) {
			throw new Exception(String.format(REG.getString("typenotfound.ERROR1"), revType.getTypeName() + "Master"));
		}
		bomlineType = (TCComponentBOMLineType) session.getTypeComponent("BOMLine");
		if (bomlineType == null) {
			throw new Exception(String.format(REG.getString("typenotfound.ERROR1"), "BOMLine"));
		}
		for (int i = 0; i < len; i++) {
			String propName = prefVals[i];
			System.out.println("Load Config: " + propName);
			if (KUtil.isEmpty(propName)) {
				continue;
			}
			String propLoc = KTableRow.REVMASTER;
			String filterValue = null;
			int width = 0;
			int height = 0;
			while (!KUtil.isEmpty(propName) && Character.isDigit(propName.charAt(0))) {
				width = width * 10 + (propName.charAt(0) - '0');
				propName = propName.substring(1);
			}
			if (propName.startsWith("x")) {
				propName = propName.substring(1);
				while (!KUtil.isEmpty(propName) && Character.isDigit(propName.charAt(0))) {
					height = height * 10 + (propName.charAt(0) - '0');
					propName = propName.substring(1);
				}
			}
			// while (!KUtil.isEmpty(propName) && Character.isDigit(propName.charAt(0))) {
			// width = width * 10 + (propName.charAt(0) - '0');
			// propName = propName.substring(1);
			// }
			// int ind = propName.indexOf('.');
			// if (ind > 0) {
			// propLoc = propName.substring(0, ind);
			// propName = propName.substring(ind + 1);
			// }
			int ind = propName.indexOf('=');
			if (ind > 0) {
				filterValue = propName.substring(ind + 1);
				propName = propName.substring(0, ind);
			}
			TCPropertyDescriptor propDesc;
			if (propName.startsWith("**")) {
				propLoc = KTableRow.BOMLINE;
				propName = propName.substring(2);
				propDesc = bomlineType.getPropDesc(propName);
				if (propDesc == null) {
					throw new Exception(String.format(REG.getString("propnotdefinedintype.ERROR2"), propName, bomlineType.getDisplayTypeName()));
				}
			} else if (propName.startsWith("*")) {
				propLoc = KTableRow.REV;
				propName = propName.substring(1);
				propDesc = revType.getPropDesc(propName);
				if (propDesc == null) {
					throw new Exception(String.format(REG.getString("propnotdefinedintype.ERROR2"), propName, revType.getDisplayTypeName()));
				}
			} else {
				propDesc = revMasterType.getPropDesc(propName);
				if (propDesc == null) {
					throw new Exception(String.format(REG.getString("propnotdefinedintype.ERROR2"), propName, revMasterType.getDisplayTypeName()));
				}
			}
			this.propConfigs.add(new PropConfig(propLoc, propDesc, filterValue, width, height, 0));
		}
		System.out.println("Load complete");
		int size = this.propConfigs.size();
		if (size == 0) {
			return false;
		}
		for (int i = 0; i < size; i++) {
			PropConfig config = propConfigs.get(i);
			addPropPane(flowPane, config);
		}
		return true;
	}

	public void loadTCData(TCComponentBOMLine targetLine) throws Exception {
		if (targetLine == null) {
			return;
		}
		TCComponent revMaster = targetLine == null ? null : targetLine.getItemRevision().getRelatedComponent("IMAN_master_form_rev");
		TCComponent rev = targetLine == null ? null : targetLine.getItemRevision();
		int size = this.propConfigs.size();
		if (size == 0) {
			return;
		}
		for (int j = 0; j < size; j++) {
			PropConfig config = propConfigs.get(j);
			Control control = config.getControl();
			if (control == null) {
				continue;
			}
			TCComponent comp = KTableRow.REV.equals(config.propLoc) ? rev : KTableRow.BOMLINE.equals(config.propLoc) ? targetLine : revMaster;
			if (control instanceof TextInputControl) {
				TCPropertyDescriptor propDesc = comp.getTypeComponent().getPropDesc(config.propName);
				String text;
				if (propDesc.getType() == TCPropertyDescriptor.SERVER_PROP_double) {
					double num = comp.getDoubleProperty(config.propName);
					text = KUtil.isEmpty(comp.getProperty(config.propName)) ? "" : (ProcessUtil.DF.format(num));
				} else {
					text = comp.getStringProperty(config.propName);
				}
				((TextInputControl) control).setText(text);
				config.setSavedValue(text);
			} else if (control instanceof DatePicker) {
				Date date = comp.getDateProperty(config.propName);
				((DatePicker) control).setValue(KUtil.dateToLocalDate(date));
				config.setSavedValue(date);
			} else if (control instanceof KLOVComboBox) {
				String text = comp.getStringProperty(config.propName);
				((KLOVComboBox) control).setValue(text);
				config.setSavedValue(text);
			} else if (control instanceof ComboBox) {
				String text = comp.getStringProperty(config.propName);
				((ComboBox<String>) control).setValue(text);
				config.setSavedValue(text);
			}
		}
	}

	public void saveTCData(TCComponentBOMLine targetLine) throws Exception {
		if (targetLine == null) {
			return;
		}
		System.out.println("Update Property: " + targetLine);
		TCComponentItemRevision rev = targetLine == null ? null : targetLine.getItemRevision();
		TCComponent revMaster = targetLine == null ? null : targetLine.getItemRevision().getRelatedComponent("IMAN_master_form_rev");
		int size = this.propConfigs.size();
		if (size == 0) {
			return;
		}
		for (int j = 0; j < size; j++) {
			PropConfig config = propConfigs.get(j);
			Control control = config.getControl();
			if (control == null || !config.canEdit) {
				continue;
			}
			TCComponent comp = KTableRow.REV.equals(config.propLoc) ? rev : KTableRow.BOMLINE.equals(config.propLoc) ? targetLine : revMaster;
			String propName = config.propName;
			if (control instanceof TextInputControl) {
				String value = ((TextInputControl) control).getText();
				if (config.valueChanged(value)) {
					System.out.println(">> " + propName + " = " + value);
					comp.setProperty(propName, value);
				}
			} else if (control instanceof DatePicker) {
				Date value = KUtil.localDateToDate(((DatePicker) control).getValue());
				if (config.valueChanged(value)) {
					System.out.println(">> " + propName + " = " + value);
					comp.setDateProperty(propName, value);
				}
			} else if (control instanceof KLOVComboBox) {
				String value = ((KLOVComboBox) control).getSelectionModel().getSelectedItem();
				if (config.valueChanged(value)) {
					System.out.println(">> " + propName + " = " + value);
					comp.setStringProperty(propName, value);
				}
			} else if (control instanceof ComboBox) {
				String value = ((ComboBox<String>) control).getSelectionModel().getSelectedItem();
				if (config.valueChanged(value)) {
					System.out.println(">> " + propName + " = " + value);
					comp.setStringProperty(propName, value);
				}
			}
		}
		rev.refresh();
		revMaster.refresh();
		targetLine.refresh();
	}

	private void addPropPane(FlowPane flowPane, PropConfig config) throws Exception {
		String title = config.propDisplayName;
		TCComponentListOfValues lov = config.lov;
		// HBox propPane = new HBox();
		BorderPane propPane = new BorderPane();
		// propPane.setSpacing(5);
		// propPane.setAlignment(Pos.CENTER_LEFT);
		propPane.setPrefWidth(280);
		Label label = new Label(title + "  ");
		label.setAlignment(Pos.CENTER_RIGHT);
		label.setMinWidth(80);
		Platform.runLater(() -> {
			// propPane.getChildren().add(label);
			BorderPane.setAlignment(label, Pos.CENTER_LEFT);
			propPane.setLeft(label);
			flowPane.getChildren().add(propPane);
		});
		if (config.propDesc.isType(TCProperty.PROP_date)) {
			DatePicker dp = new DatePicker();
			config.setControl(dp);
			dp.setDisable(!config.canEdit);
		} else if (lov == null) {
			if (!KUtil.isEmpty(config.filterValue)) {
				String[] split = config.filterValue.split(";");
				ComboBox<String> cb = new ComboBox<String>();
				cb.getItems().add("");
				for (String string : split) {
					cb.getItems().add(string);
				}
				cb.setMaxWidth(300);
				config.setControl(cb);
				cb.setDisable(!config.canEdit);
			} else {
				// Text
				TextInputControl tf;
				if (config.width > 0 && config.height > 0) {
					tf = new TextArea();
					tf.setPrefWidth(config.width);
					tf.setPrefHeight(config.height);
					((TextArea)tf).setWrapText(true);
					propPane.setPrefWidth(Region.USE_COMPUTED_SIZE);
				} else {
					tf = new TextField();
				}
				config.setControl(tf);
				tf.setEditable(config.canEdit);
				tf.focusedProperty().addListener(new ChangeListener<Boolean>() {
					@Override
					public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
						if (newValue) {
							System.out.println("focus get: " + title);
							updateControl(tf);
						} else {
							System.out.println("focus lost: " + title);
						}
					}
				});
				tf.caretPositionProperty().addListener(new ChangeListener<Number>() {
					@Override
					public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
						if (tf.isFocused()) {
							System.out.println("caret: " + oldValue + " -> " + newValue);
							currentCaret = newValue.intValue();
						}
					}
				});
			}
		} else {
			KLOVComboBox cb = new KLOVComboBox(lov);
			cb.setMaxWidth(300);
			config.setControl(cb);
			cb.setDisable(!config.canEdit);
		}
		if (config.getControl() != null) {
			config.getControl().focusedProperty().addListener(new ChangeListener<Boolean>() {
				@Override
				public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2) {
					if (arg2) {
						SwingTextContextActivator.instance().activateContext();
					} else {
						SwingTextContextActivator.instance().deactivateContext();
					}
				}
			});
		}
		Platform.runLater(() -> {
			propPane.setCenter(config.getControl());
		});
	}

	@Override
	public void insertText(String text) {
		if (KUtil.isEmpty(text)) {
			return;
		}
		Control currentControl = getCurrentControl();
		if (currentControl == null) {
			return;
		}
		if (currentControl instanceof TextField) {
			((TextField) currentControl).insertText(currentCaret, text);
			currentCaret += text.length();
			int temp = currentCaret;
			currentControl.requestFocus();
			((TextField) currentControl).positionCaret(temp);
		} else if (currentControl instanceof TextArea) {
			TextArea textArea = (TextArea) currentControl;
			String oldValue = textArea.getText();
			String newValue;
			System.out.println(currentCaret + ":" + oldValue);
			int temp = currentCaret;
			if (oldValue == null) {
				newValue = text;
			} else if (currentCaret >= 0 && currentCaret <= oldValue.length()) {
				newValue = oldValue.substring(0, currentCaret) + text + oldValue.substring(currentCaret);
				currentCaret += text.length();
				temp = currentCaret;
			} else {
				newValue = oldValue + text;
			}
			System.out.println("-> " + newValue);
			textArea.setText(newValue);
			currentControl.requestFocus();
			textArea.positionCaret(temp);
		}
	}

}
