package com.hmsoft.app;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import org.apache.commons.beanutils.BeanUtils;
import com.alibaba.fastjson.JSON;
import com.hmsoft.bizpanel.BatchTab;
import com.hmsoft.bizpanel.MtzjTab;
import com.hmsoft.bizpanel.SchoolTab;
import com.hmsoft.bizpanel.StatisTab;
import com.hmsoft.bizpanel.SystTab;
import com.hmsoft.common.AppConst;
import com.hmsoft.common.BatchConst;
import com.hmsoft.common.FileConst;
import com.hmsoft.common.MsgTypeConst;
import com.hmsoft.common.util.CoursePlanDataUtil;
import com.hmsoft.common.util.DateUtil;
import com.hmsoft.common.util.ShoolDateUtil;
import com.hmsoft.model.Batch;
import com.hmsoft.model.CoursePlan;
import com.hmsoft.model.School;
import com.hmsoft.model.request.BizRequest;
import com.hmsoft.model.request.LoginRequest;
import com.hmsoft.model.request.LogoutRequest;
import com.hmsoft.model.request.RegisterRequest;
import com.hmsoft.model.response.LoginResponse;
import com.hmsoft.remote.rmi.exception.RemotingException;
import com.hmsoft.remote.rmi.handler.ExchangeHandler;
import com.hmsoft.remote.rmi.model.Message;
import com.hmsoft.remote.rmi.rpc.ExchangeClient;
import com.hmsoft.remote.rmi.transport.NettyChannel;
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonBar.ButtonData;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

/**
 * 命题征集管理端
 * @author zq
 *
 */
public class Manage extends Application {
	
	public static ExchangeClient CLIENT = null;
	private static Properties PROPS = new Properties();
	
	@Override
	public void start(final Stage primaryStage) {
		primaryStage.setTitle("命题征集服务端 1.0");
		BorderPane root = new BorderPane();
		Scene scene = new Scene(root);
		scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
		Rectangle2D screen = Screen.getPrimary().getVisualBounds();
		primaryStage.setX(screen.getMinX());
		primaryStage.setY(screen.getMinY());
		primaryStage.setWidth(screen.getWidth());
		primaryStage.setHeight(screen.getHeight());

		TabPane tabPane = new TabPane();
		Tab systTab = new SystTab(primaryStage);
		Tab batchTab = new BatchTab(primaryStage);
		Tab mtzjTab = new MtzjTab(primaryStage);
		Tab schoolTab = new SchoolTab(primaryStage);
		Tab statisTab = new StatisTab(primaryStage);
		//加入显示内容
		tabPane.getTabs().add(systTab);
		tabPane.getTabs().add(schoolTab);
		tabPane.getTabs().add(batchTab);
		tabPane.getTabs().add(mtzjTab);
		tabPane.getTabs().add(statisTab);
		
		tabPane.setMinWidth(100);
		tabPane.setMinWidth(100);
		
		root.setCenter(tabPane);
		//primaryStage.setAlwaysOnTop(true);//始终最上面
		primaryStage.setScene(scene);
		primaryStage.show();
		primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
			
			@Override
			public void handle(WindowEvent event) {
				closeHandleFunc(primaryStage, event);
			}

		});
	}
	
	public static void main(String[] args) throws RemotingException {
		startServerSocket();
		launch(args);

	}
	
	private static void startServerSocket() {
		try {
			PROPS.load(new FileInputStream(FileConst.CONF_SERVER_PATH));
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		final String IP_PORT = PROPS.getProperty(FileConst.KEY_IP, "127.0.0.1") + ":" + PROPS.getProperty(FileConst.KEY_PORT, "20880");
		new Thread(new Runnable() {
			@Override
			public void run() {
				CLIENT = new ExchangeClient(IP_PORT, new ExchangeHandler() {

					@Override
					public void caught(NettyChannel arg0, Throwable arg1) throws RemotingException {
					}

					@Override
					public void connected(NettyChannel arg0) throws RemotingException {
						System.err.println("manage: connected");
						//client建立完、连接建立后注册
						new Thread(new Runnable() {

							@Override
							public void run() {
								try {
									registerMgr();
								} catch (RemotingException e) {
									e.printStackTrace();
								}
							}
							
						}).start();
	
					}

					@Override
					public void disconnected(NettyChannel arg0) throws RemotingException {
					}

					@Override
					public void received(NettyChannel arg0, Object message) throws RemotingException {
						if (message instanceof Message) {
							System.err.println("manage: received," + message);
						}
					}

					@Override
					public void sent(NettyChannel arg0, Object arg1) throws RemotingException {
						
					}

					@Override
					public Object reply(NettyChannel channel, Object request) throws RemotingException {
						Object ret = null;
						if (request instanceof Message) {
							Message msg = (Message)request;
							byte type = msg.getType();
							try {
								if (type == MsgTypeConst.TYPE_LOGIN_REQ_TO_MGE) {
									//登录消息
									ret = loginReqFunc(msg);
									
								} else if (type == MsgTypeConst.TYPE_NOTIFY_CLIENT_LOGOUT) {
									//收到登出
									ret = logoutReqFunc(msg);
									
								} else if (type == MsgTypeConst.TYPE_BIZ_REQ_TO_MGE) {
									
									final BizRequest req = JSON.parseObject(msg.getMsgBody(), BizRequest.class);
									if (req.getReqType().intValue() == AppConst.SCH_SELECT_COURSE) {//学校提交选择课程
										
										ret = notifySelectFunc(req, msg);
										
									} else if (req.getReqType() == AppConst.SCH_CANCEL_COURSE) {//学校取消课程
										
										ret = cancelCourseFunc(req, msg);
										
									} else if (req.getReqType() == AppConst.SCH_FETCH_NEW_LIST) {//
										
										ret = pushLastestZjDataFunc(req, msg);
										
									} else if (req.getReqType() == AppConst.SCH_CONFIRM_OK) {//学校确认了
										
										ret = schConfirmFunc(req);
										
									} else if (req.getReqType() == AppConst.SCH_CHANGE_PASSWD) {//修改密码
										ret = changePasswdFunc(req);
									}
									
								} else if (type == MsgTypeConst.TYPE_HEARTBEAT) {
									//心跳验证  TODO...
								}

							} catch (Exception e) {
								e.printStackTrace();
							}
							
						}
						return ret;
					}
					
				});
	
			}
			
		}).start();

	}
	
	private static void registerMgr() throws RemotingException {
		long time = 0;
		while(Manage.CLIENT == null) {
			try {
				Thread.sleep(200L);
				time += 200L;
				if (time >= 4000) {
					System.err.println("manage: Manage.CLIENT create timeout.");
					break;
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		final RegisterRequest register = new RegisterRequest();
		register.setReqDateTime(LocalDateTime.now());
		String json = JSON.toJSONString(register);
		final Message regMsg = new Message(MsgTypeConst.TYPE_MGE_REGISTER, json);
		Object objReg = Manage.CLIENT.requestTwoWay(regMsg);
		System.err.println("------------>" + objReg);
		//TODO..
	}
	
	/**
	 * 处理登录.
	 * @param msg
	 * @throws RemotingException
	 */
	private static Message loginReqFunc(final Message msg) throws RemotingException {
		final LoginRequest login = JSON.parseObject(msg.getMsgBody(), LoginRequest.class);
		LoginResponse logRes = new LoginResponse();
		try {
			BeanUtils.copyProperties(logRes, login);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		final ObservableList<School> items = SchoolTab.DATALIST;
		for (int i=0; i<items.size(); i++) {
			final School school = items.get(i);
			if (school.getUserName().equals(login.getUserName())
					&& school.getPassWord().equals(login.getPassWord())) {
				
				logRes.setStatus(0);//成功
				logRes.setSchoolId(school.getSchoolId());
				logRes.setSchoolName(school.getSchoolName());
				String json = JSON.toJSONString(logRes);
				final Message resMsg = new Message(MsgTypeConst.TYPE_LOGIN_RESP_TO_CLIENT, json);
				resMsg.setShoolRemoteAddr(msg.getShoolRemoteAddr());
				//modify manage table
				school.setStatusDesc("已连接");
				school.setConnectedTime(DateUtil.format(LocalDateTime.now()));
				SchoolTab.SCH_TABLE.refresh();
				return resMsg;
			} 
			if (i == items.size() - 1) {
				logRes.setStatus(-1);//失败
				String json = JSON.toJSONString(login);
				Message resMsg = new Message(MsgTypeConst.TYPE_LOGIN_RESP_TO_CLIENT, json);
				resMsg.setShoolRemoteAddr(msg.getShoolRemoteAddr());
				return resMsg;
			}
		}
		return null;
	}
	
	/**
	 * 学校登出.
	 * @param msg
	 * @throws RemotingException
	 */
	private static Object logoutReqFunc(final Message msg) throws RemotingException {
		final LogoutRequest out = JSON.parseObject(msg.getMsgBody(), LogoutRequest.class);
		for (School school : SchoolTab.DATALIST) {
			if (school.getUserName().equals(out.getUserName())) {
				school.setStatusDesc("已断开");
				school.setDisconnectTime((DateUtil.format(LocalDateTime.now())));
				break;
			}
		}
		SchoolTab.SCH_TABLE.refresh();
		return 0;
	}
	
	/**
	 * 学校选择结果广播出去.
	 * @param req
	 * @throws RemotingException
	 */
	private static Object notifySelectFunc(final BizRequest req, final Message msg) throws RemotingException {
		req.setReqType(AppConst.SRV_NOTIFY_SELECT);
		//更新服务端列表
		String ids = req.getSelectIds();
		if (ids != null && ids.length() > 0) {
			String[] idArr = ids.split(",");
			for (String rowIndx : idArr) {
				final int id = Integer.parseInt(rowIndx);
				for (CoursePlan course : MtzjTab.DATALIST) {
					if (course.getCoursePlanId().intValue() == id) {
						final School school = new School(req.getSchoolId(), req.getSchoolName());
						course.getMultiSelectList().add(school);
						course.setSchSelectIds(getShoolIds(course.getMultiSelectList()));
						course.setSchSelectNames(getShoolNames(course.getMultiSelectList()));
						course.setSchSelectTime(DateUtil.format(LocalDateTime.now()));
					}
				}

			}
			MtzjTab.TABLE.refresh();
		}
		//实时方式才通知其他学校
		if (SystTab.FRSH_MINUTES == 0) {
			String json = JSON.toJSONString(req);
			Message resMsg = new Message(MsgTypeConst.TYPE_BIZ_RESP_TO_CLIENT, json);
			resMsg.setShoolRemoteAddr(msg.getShoolRemoteAddr());
			//IFuture future = 
			Object obj = Manage.CLIENT.requestTwoWay(resMsg);
			//TODO
		}
		return msg;
	}
	
	/**
	 * 学校取消课程广播出去.
	 * @param req
	 * @throws RemotingException
	 */
	private static Object cancelCourseFunc(final BizRequest req, final Message msg) throws RemotingException {
		//更新服务端列表
		String ids = req.getSelectIds();
		final List<CoursePlan> showList = new ArrayList<CoursePlan>();
		if (ids != null && ids.length() > 0) {
			String[] idArr = ids.split(",");
			for (String rowIndx : idArr) {
				final int id = Integer.parseInt(rowIndx);
				for (CoursePlan course : MtzjTab.DATALIST) {
					if (course.getCoursePlanId().intValue() == id) {
						final School school = new School(req.getSchoolId(), req.getSchoolName());
						course.getMultiSelectList().remove(school);
						showList.add(course);
						course.setSchSelectIds(getShoolIds(course.getMultiSelectList()));
						course.setSchSelectNames(getShoolNames(course.getMultiSelectList()));
						if (course.getMultiSelectList().size() == 0) {//2学校其中一个取消了，不能清空选择时间
							course.setSchSelectTime("");
						}
					}
				}
			}
			MtzjTab.TABLE.refresh();
		}
		//通知到其他客户端
		//notifyCancelToClient(req, msg, showList);
		return 0;
	}
	
	private static void notifyCancelToClient(final BizRequest req, final Message msg, final List<CoursePlan> showList) {
		req.setReqType(AppConst.SRV_NOTIFY_CANCEL);
		req.setSourceList(showList);//删除的列表重新加载到客户端.
		String json = JSON.toJSONString(req);
		Message resMsg = new Message(MsgTypeConst.TYPE_BIZ_RESP_TO_CLIENT, json);
		resMsg.setShoolRemoteAddr(msg.getShoolRemoteAddr());
		Object retObj;
		try {
			retObj = Manage.CLIENT.requestTwoWay(msg);
			if (retObj != null) {
				
			}
		} catch (RemotingException e) {
			e.printStackTrace();
			//TODO...
		}
	}

	/**
	 * 推送最新征集/已发布数据到学校.
	 * @param req
	 * @throws RemotingException
	 */
	private static Object pushLastestZjDataFunc(final BizRequest req, final Message msg) throws RemotingException {
		Batch batch = MtzjTab.BATCH_SELECT_BOX.getSelectionModel().getSelectedItem();
		if (batch != null && (batch.getStatus() == BatchConst.STATUS_COLLECTING || batch.getStatus() == BatchConst.STATUS_PUBLISHED)) {
			req.setReqType(AppConst.SRV_PUSH_NEW_LIST);
			req.setSourceList(MtzjTab.DATALIST);
			req.setZjStatus(batch.getStatus().byteValue());
			String json = JSON.toJSONString(req);
			final Message resMsg = new Message(MsgTypeConst.TYPE_BIZ_RESP_TO_CLIENT, json);
			resMsg.setShoolRemoteAddr(msg.getShoolRemoteAddr());
			return resMsg;
		}
		return null;
	}
	
	/**
	 * 学校确认处理.
	 * @param req
	 */
	private static Object schConfirmFunc(final BizRequest req) {
		if (req.getSelectIds() != null && req.getSelectIds().length() > 0) {
			String[] arr = req.getSelectIds().split(",");
			for (String id : arr) {
				for (CoursePlan cp : MtzjTab.DATALIST) {
					if (cp.getCoursePlanId().intValue() == Integer.parseInt(id)) {
						cp.setConfirmDesc("已确认");
						cp.setConfirmStatus(1);
						break;
					}
				}
			}
			MtzjTab.TABLE.refresh();
		}
		return 0;
	}
	
	private static Object changePasswdFunc(final BizRequest req) {
		String newPasswd = req.getSchoolName();//schoolName中为passwd
		ShoolDateUtil.resetPasswd(req.getSchoolId(), newPasswd);
		SchoolTab.changeTablePasswdData(req.getSchoolId(), newPasswd);
		return 0;
	}
	
	public static String getShoolNames(List<School> schoolList) {
		StringBuilder sb = new StringBuilder();
		for (School sch : schoolList) {
			sb.append(sch.getSchoolName()).append("|");
		}
		return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : "";
	}
	
	private static String getShoolIds(List<School> schoolList) {
		StringBuilder sb = new StringBuilder();
		for (School sch : schoolList) {
			sb.append(sch.getSchoolId()).append("|");
		}
		return sb.length() > 0 ? sb.substring(0, sb.length() - 1) : "";
	}
	
	private void closeHandleFunc(final Stage primaryStage, WindowEvent event) {
		Alert confirm = new Alert(Alert.AlertType.CONFIRMATION,
				"", 
				new ButtonType("否", ButtonData.NO),
                new ButtonType("是", ButtonData.YES));
		confirm.setTitle("请确认");
		confirm.setHeaderText("是否关闭？");
		confirm.initOwner(primaryStage);
		Optional<ButtonType> btnType = confirm.showAndWait();
		if (btnType.get().getButtonData().equals(ButtonData.YES)) {
			Batch batch = MtzjTab.BATCH_SELECT_BOX.getSelectionModel().getSelectedItem();
			if (batch != null && MtzjTab.DATALIST.size() > 0) {
				long batchId = MtzjTab.BATCH_SELECT_BOX.getSelectionModel().getSelectedItem().getBatchId();
				CoursePlanDataUtil.updateCoursePlan(MtzjTab.DATALIST, batchId);
			}
		} else {
			event.consume();
		}
	}
}
