package com.imyeyu.fx.ui.components.table;

import com.imyeyu.fx.ui.TimiFXUI;
import javafx.beans.property.Property;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.TableCell;

/**
 * 抽象表格绑定单元格
 *
 * @author 夜雨
 * @since 2023-03-14 14:42
 *
 * @param <S> 表格数据类型
 * @param <T> 数据属性类型
 * @param <P> 绑定类型
 * @param <N> 组件类型
 */
public abstract class BindingTableCell<S, T, P extends Property<T>, N extends Node> extends TableCell<S, T> implements TimiFXUI {

	/** 组件 */
	protected final N node;

	/** 当前绑定 */
	protected P nowBind;

	/** 默认构造器 */
	public BindingTableCell() {
		node = component();
		onInit(node);
		node.focusedProperty().addListener((obs, o, isFocused) -> {
			if (isFocused) {
				getTableView().getSelectionModel().clearAndSelect(getIndex());
			}
		});
		setPadding(Insets.EMPTY);
	}

	/**
	 * 构建组件
	 *
	 * @return 组件
	 */
	protected abstract N component();

	/**
	 * 组件属性绑定类
	 *
	 * @param node 组件
	 * @return 属性绑定类
	 */
	protected abstract P componentValue(N node);

	/**
	 * 双向绑定属性，组件对数据的双向绑定属性
	 *
	 * @param s 数据对象
	 * @return 监听属性
	 */
	protected abstract P property(S s);

	@Override
	protected void updateItem(T item, boolean empty) {
		super.updateItem(item, empty);
		if (empty || item == null || getTableRow() == null || getTableRow().getItem() == null) {
			setGraphic(null);
		} else {
			// 动态绑定
			P thisBind = property(getTableRow().getItem());
			if (nowBind == null) {
				nowBind = thisBind;
				componentValue(node).bindBidirectional(nowBind);
				onUpdateBinding(getTableRow().getItem());
			} else {
				if (nowBind != thisBind) {
					componentValue(node).unbindBidirectional(nowBind);
					nowBind = thisBind;
					componentValue(node).bindBidirectional(nowBind);
					onUpdateBinding(getTableRow().getItem());
				}
			}
			setGraphic(node);
		}
	}

	/**
	 * 构造完成触发
	 *
	 * @param node 组件
	 */
	protected void onInit(N node) {
		// 子类实现
	}

	/**
	 * 发生更新绑定时触发
	 *
	 * @param s 数据对象
	 */
	protected void onUpdateBinding(S s) {
		// 子类实现
	}
}
