package com.szpg.rmi;

import com.szpg.db.dao.PgDeviceDao;
import com.szpg.db.dao.PgZmDao;
import com.szpg.db.dao.impl.PgDeviceDaoImpl;
import com.szpg.db.dao.impl.PgZmDaoImpl;
import com.szpg.db.data.PgZmStat;
import com.szpg.service.RemoteDeviceControlService;
import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;
import com.szpg.db.dao.PgAcuDao;
import com.szpg.db.dao.impl.PgAcuDaoImpl;
import com.szpg.db.data.PgAcu;
import com.szpg.plc.message.AppMessageConstants;
import com.szpg.plc.message.command.ReadMemoryCommand;
import com.szpg.plc.message.command.write.SetZmOffBitCommand;
import com.szpg.plc.message.command.write.SetZmOnBitCommand;
import com.szpg.plc.protocol.DTProtocolInterface;
import com.szpg.plc.protocol.ProtocolFactory;
import com.szpg.plc.protocol.fins.FINSConstants;
import com.szpg.plc.server.ACUClient;
import com.szpg.plc.server.ACUClientUtil;
import com.szpg.plc.util.ByteUtil;
import com.szpg.service.ReadControllerStatusService;
import com.szpg.service.command.LightCommandService;
import com.szpg.util.Configure;
import com.szpg.util.HttpRequest;
import com.szpg.util.UnicodeConvertor;

import z.json.JSONObject;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class RemoteZMCommandAction extends ActionSupport {

	/**
	 * 
	 */
	private static final long serialVersionUID = 2221187086461756012L;

	private String zcbh;
	
	private String format;
	private String jsoncallback;
	
	private Logger logger = Logger.getLogger(this.getClass().getName());
	
	public String getZcbh() {
		return zcbh;
	}

	public void setZcbh(String zcbh) {
		this.zcbh = zcbh;
	}

	public String getFormat() {
		return format;
	}

	public void setFormat(String format) {
		this.format = format;
	}

	public String getJsoncallback() {
		return jsoncallback;
	}

	public void setJsoncallback(String jsoncallback) {
		this.jsoncallback = jsoncallback;
	}
	
	/**
	 * 读取照明实时状态
	 * @return
	 * @throws Exception
	 */
	public String readZmStatus() throws Exception {
		// 返回结果
		JSONObject jResult = new JSONObject();
		
		PgAcuDao acuDao = new PgAcuDaoImpl();
		
		if (null == zcbh || zcbh.equals("") == true) {
			jResult.put("success", false);
			jResult.put("code", "1");
			jResult.put("resaon", UnicodeConvertor.string2Unicode("资产编号为空"));
			
			returnToFront(jResult);
			return null;
		}
		
		String acucode = zcbh.substring(0, zcbh.indexOf(".", 6));
		PgAcu acu = acuDao.findACUByCode(acucode);
		if (null == acu) {
			jResult.put("success", false);
			jResult.put("code", "2");
			jResult.put("resaon", UnicodeConvertor.string2Unicode("未找到资产对应的PLC主机"));
			
			returnToFront(jResult);
			return null;
		}
		
		ACUClient client = ACUClientUtil.getInstance().getClients().get(acu.getAcu_host() + ":" + acu.getAcu_port());
		if (null != client) {
			ReadMemoryCommand command = ReadMemoryCommand.getInstance(AppMessageConstants.CMD_TYPE_READZMSTAT);
			String sour = Configure.getProperty("sys", "LOCALHOST.NET") + 
						  Configure.getProperty("sys", "LOCALHOST.NODE") + 
						  Configure.getProperty("sys", "LOCALHOST.UNIT");
			command.setMessageProducerId(sour);
			command.setMessageProducerHost(client.getHost());
			
			String dest = client.getNet() + client.getNode() + client.getUnit();
			command.setDestinationId(dest);
			command.setMemoryArea(FINSConstants.MEMORY_WORK_AREA_WORD); //按字读取内容
			
			try {
				// 没有找到对应的配置项，直接返回
				String start = Configure.getProperty("acubl", client.getAcucode() + ".ZMSTAT.START");
				String countWord = Configure.getProperty("acubl", client.getAcucode() + ".ZMSTAT.WORDCOUNT");
				if (null == start || start.equals("")) {
					jResult.put("success", false);
					jResult.put("code", "4");
					jResult.put("resaon", UnicodeConvertor.string2Unicode("未找到对应的变量配置项"));

					returnToFront(jResult);
					return null;
				}

				// 设置读取的地址范围
				// 从配置文件读取而来
				command.setStartAddress(ByteUtil.binToHexString(ByteUtil.intToBins(Integer.parseInt(start), 2)) + "00");
				command.setCountWord(Integer.parseInt(countWord));
				
				// 调用服务过程执行命令发送服务
				ReadControllerStatusService service = new ReadControllerStatusService();
				service.executeService(client, command);
				logger.info(command);
			} catch (Exception ex) {
				logger.error("发送查询照明指令异常" + ex);
			}
			
			jResult.put("success", true);
			jResult.put("resaon", UnicodeConvertor.string2Unicode("发送成功，请等待响应"));
			
			returnToFront(jResult);
			return null;
		} else {
			jResult.put("success", false);
			jResult.put("code", "3");
			jResult.put("resaon", UnicodeConvertor.string2Unicode("PLC主机不在线"));
			
			returnToFront(jResult);
			return null;
		}
	}
	
	/**
	 * 远程打开照明
	 * @return
	 * @throws Exception
	 */
	public String turnOnZm() throws Exception {
		// 返回结果
		JSONObject jResult = new JSONObject();
		
		if (null == zcbh || zcbh.equals("") == true) {
			jResult.put("success", false);
			jResult.put("code", "1");
			jResult.put("resaon", UnicodeConvertor.string2Unicode("资产编号为空"));
			
			returnToFront(jResult);
			return null;
		}
		
		// 查找ACU的信息
		PgAcuDao acuDao = new PgAcuDaoImpl();
		
		String acucode = zcbh.substring(0, zcbh.indexOf(".", 6));
		PgAcu acu = acuDao.findACUByCode(acucode);
		if (null == acu) {
			jResult.put("success", false);
			jResult.put("code", "2");
			jResult.put("resaon", UnicodeConvertor.string2Unicode("未找到资产对应的PLC主机"));
			
			returnToFront(jResult);
			return null;
		}
		
		ACUClient client = ACUClientUtil.getInstance().getClients().get(acu.getAcu_host() + ":" + acu.getAcu_port());
		if (null != client) {
			// 源地址
			String sour = Configure.getProperty("sys", "LOCALHOST.NET") + 
						  Configure.getProperty("sys", "LOCALHOST.NODE") + 
						  Configure.getProperty("sys", "LOCALHOST.UNIT");
			
			// 目标地址
			String dest = client.getNet() + client.getNode() + client.getUnit();
			
			DTProtocolInterface finspi = ProtocolFactory.getDefaultDTProtocol();
			
			// 1首先将停止位置0
			// 该逻辑取消，由设备自行控制
			
			// 2 发送设置启动位的命令
			// 构建打开照明指令
			SetZmOnBitCommand setOnCmd = LightCommandService.buildTurnOnCommand(sour, dest, zcbh);
			if (null != setOnCmd) {
				setOnCmd.setMessageProducerHost(client.getHost());

				RemoteDeviceControlService service = new RemoteDeviceControlService();
				service.executeService(client, setOnCmd, zcbh);

				Logger.getLogger(this.getClass().getName()).info(setOnCmd);
			} else {
				jResult.put("success", false);
				jResult.put("code", "4");
				jResult.put("reason", UnicodeConvertor.string2Unicode("未找到资产对应的打开照明变量"));
				
				returnToFront(jResult);
				return null;
			}
			
			// 20190515增加的逻辑，在置1打开位一秒钟后，将该位复位
			Thread.sleep(1 * 1000);
			setOnCmd = LightCommandService.buildResetTurnOnCommand(sour, dest, zcbh);
			if (null != setOnCmd) {
				byte[] content = finspi.messageToBytes(setOnCmd);
				ACUClientUtil.getInstance().sendACUCommand(client, content);
				Logger.getLogger(this.getClass().getName()).info("[打开照明置1位复位]");
			}
			
			// 5秒后查询一次照明的状态
			new ScheduledThreadPoolExecutor(1).schedule(new ReadZmStatusTask(zcbh), 5, TimeUnit.SECONDS);
			
			// 返回成功给界面
			jResult.put("success", true);
			jResult.put("code", "0");
			returnToFront(jResult);
			
			return null;
		} else {
			jResult.put("success", false);
			jResult.put("code", "3");
			jResult.put("resaon", UnicodeConvertor.string2Unicode("PLC主机不在线"));
			
			returnToFront(jResult);
			return null;
		}
	}
	
	/**
	 * 远程关闭照明
	 * @return
	 * @throws Exception
	 */
	public String turnOffZm() throws Exception {
		// 返回结果
		JSONObject jResult = new JSONObject();
		
		if (null == zcbh || zcbh.equals("") == true) {
			jResult.put("success", false);
			jResult.put("code", "1");
			jResult.put("resaon", UnicodeConvertor.string2Unicode("资产编号为空"));
			
			returnToFront(jResult);
			return null;
		}
		
		// 查找ACU的信息
		PgAcuDao acuDao = new PgAcuDaoImpl();
		
		String acucode = zcbh.substring(0, zcbh.indexOf(".", 6));
		PgAcu acu = acuDao.findACUByCode(acucode);
		if (null == acu) {
			jResult.put("success", false);
			jResult.put("code", "2");
			jResult.put("resaon", UnicodeConvertor.string2Unicode("未找到资产对应的PLC主机"));
			
			returnToFront(jResult);
			return null;
		}
		
		ACUClient client = ACUClientUtil.getInstance().getClients().get(acu.getAcu_host() + ":" + acu.getAcu_port());
		if (null != client) {
			// 源地址
			String sour = Configure.getProperty("sys", "LOCALHOST.NET") + 
						  Configure.getProperty("sys", "LOCALHOST.NODE") + 
						  Configure.getProperty("sys", "LOCALHOST.UNIT");
			
			// 目标地址
			String dest = client.getNet() + client.getNode() + client.getUnit();
			
			DTProtocolInterface finspi = ProtocolFactory.getDefaultDTProtocol();
			
			// 1首先将启动位置0
			// 逻辑取消，由PLC设备自行控制
			
			// 2 发送设置停止位的命令
			SetZmOffBitCommand setOffCmd = LightCommandService.buildTurnOffCommand(sour, dest, zcbh);
			if (null != setOffCmd) {
				setOffCmd.setMessageProducerHost(client.getHost());

				RemoteDeviceControlService service = new RemoteDeviceControlService();
				service.executeService(client, setOffCmd, zcbh);

				Logger.getLogger(this.getClass().getName()).info(setOffCmd);
			} else {
				jResult.put("success", false);
				jResult.put("code", "4");
				jResult.put("reason", UnicodeConvertor.string2Unicode("未找到资产对应的关闭照明变量"));
				
				returnToFront(jResult);
				return null;
			}
			
			// 20190515增加的逻辑，在置1打开位一秒钟后，将该位复位
			Thread.sleep(1 * 1000);
			setOffCmd = LightCommandService.buildResetTurnOffCommand(sour, dest, zcbh);
			if (null != setOffCmd) {
				byte[] content = finspi.messageToBytes(setOffCmd);
				ACUClientUtil.getInstance().sendACUCommand(client, content);
				Logger.getLogger(this.getClass().getName()).info("[关闭照明置1位复位]");
			}
			
			// 5秒后查询一次照明的状态
			new ScheduledThreadPoolExecutor(1).schedule(new ReadZmStatusTask(zcbh), 5, TimeUnit.SECONDS);
			
			// 返回成功给界面
			jResult.put("success", true);
			jResult.put("code", "0");
			returnToFront(jResult);
			
			return null;
		} else {
			jResult.put("success", false);
			jResult.put("code", "3");
			jResult.put("resaon", UnicodeConvertor.string2Unicode("PLC主机不在线"));
			
			returnToFront(jResult);
			return null;
		}
	}

	public String readZmStatusFromDB() throws Exception {
		// 返回结果
		JSONObject jResult = new JSONObject();

		PgDeviceDao deviceDao = new PgDeviceDaoImpl();
		PgZmDao zmDao = new PgZmDaoImpl();

		int deviceId = deviceDao.findDeviceIdByCode(zcbh);
		if (deviceId > 0) {
			PgZmStat zmStat = zmDao.findLatestStatByDevice(deviceId);
			if (null != zmStat) {
				jResult.put("zmStat", zmStat.toJson());
			}
		}

		returnToFront(jResult);
		return null;
	}
	
	
	/**
	 * 给前端返回
	 * @param jResult
	 * @throws Exception
	 */
	private void returnToFront(JSONObject jResult) throws Exception {
		// 返回jsonp格式的数据
		if (null != format && format.equalsIgnoreCase("jsonp") == true) {
			ServletActionContext.getResponse().getWriter().write(jsoncallback + "(" + jResult.toString() + ");");
		}

		ServletActionContext.getResponse().getWriter().write(jResult.toString());
	}


	/**
	 * 执行照明操作之后的查询照明状态单次任务
	 */
	class ReadZmStatusTask implements Runnable {

		private String zcbh;

		public ReadZmStatusTask(String zcbh) {
			this.zcbh = zcbh;
		}

		@Override
		public void run() {
			// 调用远程接口查询照明状态
			String baseURL = Configure.getProperty("sys", "PGDSC_API_URL");
			HttpRequest.sendGet(baseURL + "remote/readZmStatus.action", "zcbh=" + zcbh);
		}
	}
}
