package com.ht.ui.user;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.ToolBar;
import javafx.scene.control.Tooltip;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;

import org.javafxdata.control.cell.ChoiceBoxCellFactory;
import org.javafxdata.control.cell.TextFieldCellFactory;

import com.ht.ui.MainApplication;
import com.ht.ui.controls.MessageInfoLabel;
import com.ht.ui.property.UserProperty;
import com.ht.ui.util.HessianResponseService;
import com.ht.ui.util.HessianResponseTask;
import com.ht.ui.util.MessageConstants;
import com.ht.ui.util.RedoUndoManager;
import com.ht.util.UserSession;
import com.ht.web.hessian.HessianFactoryManger;
import com.ht.web.mongo.domain.User;
import com.ht.web.mongo.domain.UserGroup;
import com.ht.web.remoting.HessianResponse;

public class UserEditor extends VBox {
	//private static final Logger log = LoggerFactory.getLogger(UserEditor.class);

	private TableView<UserProperty> userTableView;
	private ObservableList<UserProperty> data;

	private TableColumn<UserProperty, String> usernameCol;
	private TableColumn<UserProperty, String> nameCol;
	private TableColumn<UserProperty, String> genderCol;
	private TableColumn<UserProperty, String> departmenCol;
	private TableColumn<UserProperty, String> addressCol;
	private TableColumn<UserProperty, String> emailCol;
	private TableColumn<UserProperty, String> telphoneCol;

	// private Set<User> changedUserGroupSet = new HashSet<UserEditor.User>();
	private Set<UserProperty> deletedUserSet = new HashSet<UserProperty>();
	private Set<UserProperty> updatedUserSet = new HashSet<UserProperty>();

	private RedoUndoManager redoUndoManager;
	private MessageInfoLabel message;

	private TableColumn<UserProperty, String> groupCol;

	private Map<String, UserGroup> userGroupNameMap = new HashMap<String, UserGroup>();

	public UserEditor() {
		super(5);

		setAlignment(Pos.TOP_CENTER);

		message = new MessageInfoLabel();

		// 创建工具栏
		createToolBar();
		// 用户列表
		createTablePanel();
		
		// 操作按钮
		createBottomButton();
	}

	private void createToolBar() {
		ToolBar toolbar = new ToolBar();
		toolbar.getStyleClass().add("mini-toolbar");

		Button undoButton = new Button();
		undoButton.setGraphic(new ImageView(new Image(MainApplication.class
				.getResourceAsStream("images/back.png"))));
		undoButton.setTooltip(new Tooltip("撤消"));
		undoButton.setOnAction(new EventHandler<ActionEvent>() {
			public void handle(ActionEvent event) {
				// back();
				redoUndoManager.undo();
			}
		});
		undoButton.setMaxHeight(Double.MAX_VALUE);

		Button redoButton = new Button();
		redoButton.setGraphic(new ImageView(new Image(MainApplication.class
				.getResourceAsStream("images/forward.png"))));
		redoButton.setTooltip(new Tooltip("重做"));
		redoButton.setOnAction(new EventHandler<ActionEvent>() {
			public void handle(ActionEvent event) {
				// forward();
				redoUndoManager.redo();
			}
		});

		redoUndoManager = new RedoUndoManager(undoButton, redoButton);

		Button reloadButton = new Button();
		reloadButton.setGraphic(new ImageView(new Image(getClass()
				.getResourceAsStream("/com/ht/ui/images/reload.png"))));
		reloadButton.setOnAction(new EventHandler<ActionEvent>() {
			public void handle(ActionEvent event) {
				reload();
			}
		});
		reloadButton.setMaxHeight(Double.MAX_VALUE);

		toolbar.getItems().addAll(undoButton, redoButton, reloadButton);

		getChildren().add(toolbar);
	}

	private void createBottomButton() {
		Button saveBtn = new Button("保存");
		saveBtn.setPrefWidth(80);
		saveBtn.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent event) {

				if (UserSession.INSTANCE.getUser() == null) {

					UserLoginDialog.getInstance().showDialog(null,
							"您已自动退出, 请重新登录.");
				} else {
					User user = UserSession.INSTANCE.getUser();
					if (user != null && !user.getGroup().getUserEdit()) {
						showMessage("您所在的用户组没有权限执行该操作");
						return;
					}

					List<User> deletedUserList = new ArrayList<User>();
					for (UserProperty userP : deletedUserSet) {
						deletedUserList.add(userP.getUser());
					}

					List<User> updatedUserList = new ArrayList<User>();
					for (UserProperty userP : updatedUserSet) {
						if (!userGroupNameMap.isEmpty()) {
							userP.getUser().setGroup(
									userGroupNameMap.get(userP.groupProperty()
											.getValue()));
						}
						updatedUserList.add(userP.getUser());
					}

					try {
						HessianResponse resp = HessianFactoryManger.INSTANCE
								.getUserService().addOrUpdateAllUsers(
										deletedUserList, updatedUserList);
						if (resp.isSuccessful()) {
							if (!resp.getMsg().isEmpty()) {
								showMessage(resp.getMsg());
							}
							deletedUserSet.clear();
							updatedUserSet.clear();
							redoUndoManager.reset();
							reload();
						} else {
							if (resp.isLogin()) {
								showMessage(resp.getMsg());
							} else {

								UserLoginDialog.getInstance().showDialog(null,
										resp.getMsg());
							}
						}
					} catch (Exception e) {
						showMessage("服务器响应错误");
					}

				}

			}
		});
		getChildren().add(saveBtn);
	}

	@SuppressWarnings("unchecked")
	private void createTablePanel() {
		StringCellEditEventHandler cellEditEventHandler = new StringCellEditEventHandler();

		usernameCol = new TableColumn<UserProperty, String>("用户名");
		usernameCol.setPrefWidth(80);
		usernameCol.setEditable(false);
		usernameCol
				.setCellValueFactory(new PropertyValueFactory<UserProperty, String>(
						"username"));

		nameCol = new TableColumn<UserProperty, String>("姓名");
		nameCol.setPrefWidth(80);
		nameCol.setCellValueFactory(new PropertyValueFactory<UserProperty, String>(
				"name"));
		nameCol.setCellFactory(TextFieldCellFactory
				.<UserProperty> forTableColumn());
		nameCol.setOnEditCommit(cellEditEventHandler);

		genderCol = new TableColumn<UserProperty, String>("性别");
		genderCol.setPrefWidth(40);
		genderCol
				.setCellValueFactory(new PropertyValueFactory<UserProperty, String>(
						"gender"));
		genderCol.setCellFactory(ChoiceBoxCellFactory.<UserProperty, String> forTableColumn("男", "女"));
		//genderCol.setCellFactory(ComboBoxCellFactory.<UserProperty, String>forTableColumn("男", "女"));
		genderCol.setOnEditCommit(cellEditEventHandler);

		departmenCol = new TableColumn<UserProperty, String>("部门");
		departmenCol.setPrefWidth(80);
		departmenCol
				.setCellValueFactory(new PropertyValueFactory<UserProperty, String>(
						"department"));
		departmenCol.setCellFactory(TextFieldCellFactory
				.<UserProperty> forTableColumn());
		departmenCol.setOnEditCommit(cellEditEventHandler);

		addressCol = new TableColumn<UserProperty, String>("地址");
		addressCol.setMinWidth(250);
		addressCol
				.setCellValueFactory(new PropertyValueFactory<UserProperty, String>(
						"address"));
		addressCol.setCellFactory(TextFieldCellFactory
				.<UserProperty> forTableColumn());
		addressCol.setOnEditCommit(cellEditEventHandler);

		emailCol = new TableColumn<UserProperty, String>("Email");
		emailCol.setMinWidth(150);
		emailCol.setCellValueFactory(new PropertyValueFactory<UserProperty, String>(
				"email"));
		emailCol.setCellFactory(TextFieldCellFactory
				.<UserProperty> forTableColumn());
		emailCol.setOnEditCommit(cellEditEventHandler);

		telphoneCol = new TableColumn<UserProperty, String>("电话");
		telphoneCol.setMinWidth(100);
		telphoneCol
				.setCellValueFactory(new PropertyValueFactory<UserProperty, String>(
						"telphone"));
		telphoneCol.setCellFactory(TextFieldCellFactory
				.<UserProperty> forTableColumn());
		telphoneCol.setOnEditCommit(cellEditEventHandler);

		TableColumn<UserProperty, String> handleCol = new TableColumn<UserProperty, String>(
				"联系方式");
		handleCol.getColumns().addAll(addressCol, emailCol, telphoneCol);

		groupCol = new TableColumn<UserProperty, String>("用户组");
		groupCol.setMinWidth(100);
		groupCol.setCellValueFactory(new PropertyValueFactory<UserProperty, String>(
				"group"));
		groupCol.setCellFactory(ChoiceBoxCellFactory
				.<UserProperty, String> forTableColumn("管理员", "女"));
		groupCol.setOnEditCommit(cellEditEventHandler);

		userTableView = new TableView<UserProperty>();
		userTableView.setEditable(true);
		userTableView.getSelectionModel()
				.setSelectionMode(SelectionMode.SINGLE);
		userTableView.getSelectionModel().setCellSelectionEnabled(true);
		userTableView.getColumns().addAll(usernameCol, nameCol, genderCol,
				departmenCol, handleCol, groupCol);

		data = FXCollections.observableArrayList();
		userTableView.setItems(data);

		ContextMenu contextMenu = new ContextMenu();
		MenuItem deleteItem = new MenuItem("删除");
		deleteItem.setOnAction(new EventHandler<ActionEvent>() {
			@Override
			public void handle(ActionEvent event) {
				final UserProperty deletedGroup = userTableView
						.getSelectionModel().getSelectedItem();
				deletedUserSet.add(deletedGroup);
				data.remove(deletedGroup);

				Runnable undo = new Runnable() {

					@Override
					public void run() {

						deletedUserSet.remove(deletedGroup);
						data.add(deletedGroup);
					}
				};

				Runnable redo = new Runnable() {

					@Override
					public void run() {
						deletedUserSet.add(deletedGroup);
						data.remove(deletedGroup);
					}
				};

				redoUndoManager.updateUndoRedoList(undo, redo);
			}
		});
		contextMenu.getItems().add(deleteItem);
		userTableView.setContextMenu(contextMenu);
		VBox.setVgrow(userTableView, Priority.ALWAYS);
//		getChildren().add(userTableView);
		
		ProgressIndicator progress = new ProgressIndicator();
		progress.setMaxSize(150, 150);
		Region veil = new Region();
		veil.setStyle("-fx-background-color: rgba(0, 0, 0, 0.4)");
		
		StackPane stackPane = new StackPane();
		VBox.setVgrow(stackPane, Priority.ALWAYS);
		stackPane.getChildren().addAll(userTableView, veil, progress);
		getChildren().add(stackPane);
		
		progress.progressProperty().bind(getAllUsersService.progressProperty());
        veil.visibleProperty().bind(getAllUsersService.runningProperty());
        progress.visibleProperty().bind(getAllUsersService.runningProperty());

	}

	private void showMessage(String content) {
		// if (!getChildren().contains(message)) {
		// getChildren().add(message);
		// }
		message.show(content);
	}

	private HessianResponseService getAllUsersService = new HessianResponseService() {
		
		@Override
		protected Task<HessianResponse> createTask() {
			return new HessianResponseTask() {

				@Override
				protected HessianResponse call() throws Exception {
					try {
						return HessianFactoryManger.INSTANCE.getUserService()
								.getAllUser();
					} catch (Exception e) {
						e.printStackTrace();
					}
					return null;
				}

				@Override
				public void successResponse(HessianResponse resp) {
					userTableView.getItems().clear();
					
					List<User> list = (List<User>) resp.getData();
					for (User user : list) {
						userTableView.getItems().add(new UserProperty(user));
					}
					
				}

				@Override
				public void nullResponse() {
					showMessage(MessageConstants.ERROR_APP_ERROR);
				}

				@Override
				public void failureResponse(HessianResponse resp) {
					if (resp.isLogin()) {
						showMessage(resp.getMsg());
					} else {
						UserLoginDialog.getInstance().showDialog(null, resp.getMsg());
					}
				}
			};
		}
	};
	
	private HessianResponseService getAllGroupsService = new HessianResponseService() {
		
		@Override
		protected Task<HessianResponse> createTask() {
			return new HessianResponseTask() {
				
				@Override
				protected HessianResponse call() throws Exception {
					try {
						return HessianFactoryManger.INSTANCE
								.getUserService().getAllGroups();
					} catch (Exception e) {
						e.printStackTrace();
					}
					return null;
				}
				
				@Override
				public void successResponse(HessianResponse resp) {
					List<UserGroup> userGroups = (List<UserGroup>) resp.getData();
					ObservableList<String> groupNameList = FXCollections
							.observableArrayList();
					userGroupNameMap.clear();
					for (UserGroup group : userGroups) {
						groupNameList.add(group.getName());
						userGroupNameMap.put(group.getName(), group);
					}
					//groupCol.setCellFactory(ComboBoxCellFactory.<UserProperty, String>forTableColumn(groupNameList));
					groupCol.setCellFactory(ChoiceBoxCellFactory.<UserProperty, String> forTableColumn(groupNameList));
				}
				
				@Override
				public void nullResponse() {
					showMessage(MessageConstants.ERROR_APP_ERROR);
				}
				
				@Override
				public void failureResponse(HessianResponse resp) {
					if (resp.isLogin()) {
						showMessage(resp.getMsg());
					} else {
						UserLoginDialog.getInstance().showDialog(null,
								resp.getMsg());
					}
				}
			};
		}
	};

	public void reload() {

		getAllUsersService.restart();
		getAllGroupsService.restart();
	}

	public void changeUser(final UserProperty user, final String oldValue,
			final String newValue, final StringProperty property) {

		final boolean isContained = updatedUserSet.contains(user);

		Runnable undo = new Runnable() {

			@Override
			public void run() {
				if (!isContained) {
					updatedUserSet.remove(user);
				}
				property.setValue(oldValue);
			}
		};

		Runnable redo = new Runnable() {

			@Override
			public void run() {
				if (!isContained) {
					updatedUserSet.add(user);
				}
				property.setValue(newValue);
			}
		};

		redoUndoManager.updateUndoRedoList(undo, redo);
		redo.run();
	}

	private class StringCellEditEventHandler implements
			EventHandler<TableColumn.CellEditEvent<UserProperty, String>> {
		@Override
		public void handle(CellEditEvent<UserProperty, String> event) {
			final UserProperty group = event.getRowValue();

			final String oldValue = event.getOldValue();
			final String newValue = event.getNewValue();

			String propertyName = ((PropertyValueFactory) event
					.getTableColumn().getCellValueFactory()).getProperty();
			try {
				String methodName = propertyName + "Property";
				StringProperty property = (StringProperty) group.getClass()
						.getMethod(methodName, new Class[] {}).invoke(group);
				changeUser(group, oldValue, newValue, property);
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (SecurityException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			}
		}
	}

}
