package com.yeejoin.amos.iec104.tcp.client.invoke;

import java.util.Date;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;

import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;

import com.yeejoin.amos.iec104.business.entity.mybatis.RecData;
import com.yeejoin.amos.iec104.tcp.entity.Apdu;
import com.yeejoin.amos.iec104.tcp.entity.Asdu;
import com.yeejoin.amos.iec104.tcp.entity.IeCP56Time2a;
import com.yeejoin.amos.iec104.tcp.entity.IeQuality;
import com.yeejoin.amos.iec104.tcp.entity.IeShortFloat;
import com.yeejoin.amos.iec104.tcp.entity.IeSinglePointWithQuality;
import com.yeejoin.amos.iec104.tcp.entity.InformationElement;
import com.yeejoin.amos.iec104.tcp.entity.InformationObject;
import com.yeejoin.amos.iec104.tcp.entity.ServerData;

public class ApduQueue {
	
	private static final BlockingQueue<ServerData> blockingQueue = new LinkedBlockingQueue<ServerData>();
	ScheduledExecutorService service_apdu = null;
	
	private volatile static ApduQueue instance = null;
	
	private ApduQueue() {}
	
    public static ApduQueue getInstance(){
    	//先检查实例是否存在，如果不存在才进入下面的同步块
         if(instance == null){
        	 //同步块，线程安全的创建实例
             synchronized(ApduQueue.class){
            	 //再次检查实例是否存在，如果不存在才真的创建实例
                 if(instance == null){
                     instance = new ApduQueue();
                 }
             }
         }
         return instance;
    }
	
    /**
     * 启动apdu数据消费任务
     */
    public void start() {
    	service_apdu = Executors.newSingleThreadScheduledExecutor();
        // 第二个参数为首次执行的延时时间，第三个参数为定时执行的间隔时间
    	service_apdu.execute(task_runnable);
    }
    
	public void add(ServerData apdu) {
		blockingQueue.add(apdu);
	}
	
	Runnable task_runnable = new Runnable() {
        public void run() {
            while(true) {
            	try {
            		ServerData serverData = blockingQueue.take();
            		String serverId = serverData.getServerId();
            		Apdu apdu = serverData.getApdu();
					if (apdu.getApciType() == Apdu.ApciType.I_FORMAT) {
						Asdu asdu = apdu.getAsdu();
						int numberOfSequenceElements = 0;
						switch (asdu.getTypeId()) {
			            // 1 单点遥信
			            case 1:
			            	InformationObject[] informationObjects = asdu.getInformationObjects();
			            	for (InformationObject obj : informationObjects) {
			            		InformationElement[][] informationElement = obj.getInformationElements();
			            		int informationObjectAddress = obj.getInformationObjectAddress();
			            		numberOfSequenceElements = asdu.getSequenceLength();
			            		asdu.isSequenceOfElements();
			            		for (int i = 0; i < numberOfSequenceElements; i++) {
			            			RecData data = new RecData(serverId);
			            			data.setCommonAddress(asdu.getCommonAddress());
			            			data.setCreatedTime(new Date());
			            			data.setDataType(1);
			            			data.setInformationAddress(informationObjectAddress);
			            			
			            			IeSinglePointWithQuality singlePoint = (IeSinglePointWithQuality) informationElement[i][0];
			            			data.setIsBlocked(singlePoint.isBlocked() ? 0 : 1);
			            			data.setIsSubstituted(singlePoint.isSubstituted() ? 0 : 1);
			            			data.setIsNotTopical(singlePoint.isNotTopical() ? 0 : 1);
			            			data.setIsInvalid(singlePoint.isInvalid() ? 0 : 1);
			   
			            			data.setValue(singlePoint.isOn() + "");
			            			informationObjectAddress++;
			            			
			            			data.setQuality(singlePoint.toJson().toString());
			            			RecDataQueue.getInstance().add(data);
			            		}
			            	}
			                break;
			            // 13 浮点型遥测
			            case 13:
			            	InformationObject[] floatInformationObjects = asdu.getInformationObjects();
			                numberOfSequenceElements = asdu.getSequenceLength();
			                for (int i = 0; i < numberOfSequenceElements; i++) {
			                 InformationObject obj = floatInformationObjects[i];
			                 InformationElement[][] informationElement = obj.getInformationElements();
			                 int informationObjectAddress = obj.getInformationObjectAddress();
			                 
//			                 for (int i = 0; i < numberOfSequenceElements; i++) {
			                 RecData data = new RecData(serverId);
			                 data.setCommonAddress(asdu.getCommonAddress());
			                 data.setCreatedTime(new Date());
			                 data.setDataType(2);
			                 data.setInformationAddress(informationObjectAddress);
			                 IeShortFloat shortFloat = (IeShortFloat) informationElement[0][0];
			                 IeQuality ieQuality = (IeQuality) informationElement[0][1];
			                 data.setValue(shortFloat.getValue() + "");
			                 data.setQuality(ieQuality.toJson().toString());
			                 data.setIsBlocked(ieQuality.isBlocked() ? 0 : 1);
			                 data.setIsSubstituted(ieQuality.isSubstituted() ? 0 : 1);
			                 data.setIsNotTopical(ieQuality.isNotTopical() ? 0 : 1);
			                 data.setIsInvalid(ieQuality.isInvalid() ? 0 : 1);
			                 data.setIsOverflow(ieQuality.isOverflow() ? 0: 1);
			                 
			                 informationObjectAddress++;
			                 RecDataQueue.getInstance().add(data);
//			                 }
			                }
			                break;
							// 21 浮点型遥测
							case 21:
								InformationObject[] normalizedObjects = asdu.getInformationObjects();
								numberOfSequenceElements = asdu.getSequenceLength();
								for (int i = 0; i < numberOfSequenceElements; i++) {
									InformationObject obj = normalizedObjects[i];
									InformationElement[][] informationElement = obj.getInformationElements();
									int informationObjectAddress = obj.getInformationObjectAddress();

									RecData data = new RecData(serverId);
									data.setCommonAddress(asdu.getCommonAddress());
									data.setCreatedTime(new Date());
									data.setDataType(2);
									data.setInformationAddress(informationObjectAddress);
									IeShortFloat shortFloat = (IeShortFloat) informationElement[0][0];
									data.setValue(shortFloat.getValue() + "");

									informationObjectAddress++;
									RecDataQueue.getInstance().add(data);
								}
								break;
			            // 30 带 CP56Time2a 时标的单点信息
			            case 30:
			            	InformationObject[] informationCP56Time2aObjects = asdu.getInformationObjects();
			            	// for (InformationObject obj : informationCP56Time2aObjects) {
			            	numberOfSequenceElements = asdu.getSequenceLength();
			            	for (int i = 0; i < numberOfSequenceElements; i++) {
			            		InformationObject obj = informationCP56Time2aObjects[i];
			            		InformationElement[][] informationElement = obj.getInformationElements();
			            		int informationObjectAddress = obj.getInformationObjectAddress();
			            		
			            		// asdu.isSequenceOfElements();
			            		
		            			RecData data = new RecData(serverId);
		            			data.setCommonAddress(asdu.getCommonAddress());
		            			data.setCreatedTime(new Date());
		            			data.setDataType(1);
		            			data.setInformationAddress(informationObjectAddress);
		            			IeSinglePointWithQuality singlePoint = (IeSinglePointWithQuality) informationElement[0][0];
		            			IeCP56Time2a ieCP56Time2a = (IeCP56Time2a) informationElement[0][1];
		            			data.setValue(singlePoint.isOn() + "");
		            			data.setOccurTime(ieCP56Time2a.getDate());
		            			data.setSoe(1);
		            			data.setQuality(singlePoint.toJson().toString());
		            			data.setIsBlocked(singlePoint.isBlocked() ? 0 : 1);
		            			data.setIsSubstituted(singlePoint.isSubstituted() ? 0 : 1);
		            			data.setIsNotTopical(singlePoint.isNotTopical() ? 0 : 1);
		            			data.setIsInvalid(singlePoint.isInvalid() ? 0 : 1);
		            			Logger.getLogger(this.getClass()).debug("31类型   I帧: " +data.toString());
		            			RecDataQueue.getInstance().add(data);
			            		// }
			            	}
			                break; 
			           // 31 带 CP56Time2a 时标的双点信息
			            case 31:
			            	InformationObject[] twoInformationCP56Time2aObjects = asdu.getInformationObjects();
			            	numberOfSequenceElements = asdu.getSequenceLength();
			            	//for (InformationObject obj : twoInformationCP56Time2aObjects) {
			            	for (int i = 0; i < numberOfSequenceElements; i++) {
			            		InformationObject obj = twoInformationCP56Time2aObjects[i];
			            		InformationElement[][] informationElement = obj.getInformationElements();
			            		int informationObjectAddress = obj.getInformationObjectAddress();
			            		
			            		asdu.isSequenceOfElements();
			            		
		            			RecData data = new RecData(serverId);
		            			data.setCommonAddress(asdu.getCommonAddress());
		            			data.setCreatedTime(new Date());
		            			data.setDataType(1);
		            			data.setInformationAddress(informationObjectAddress);
		            			IeSinglePointWithQuality singlePoint = (IeSinglePointWithQuality) informationElement[0][0];
		            			IeCP56Time2a ieCP56Time2a = (IeCP56Time2a) informationElement[0][2];
		            			data.setValue(singlePoint.isOn() + "");
		            			data.setOccurTime(ieCP56Time2a.getDate());
		            			data.setQuality(singlePoint.toJson().toString());
		            			data.setIsBlocked(singlePoint.isBlocked() ? 0 : 1);
		            			data.setIsSubstituted(singlePoint.isSubstituted() ? 0 : 1);
		            			data.setIsNotTopical(singlePoint.isNotTopical() ? 0 : 1);
		            			data.setIsInvalid(singlePoint.isInvalid() ? 0 : 1);
		            			data.setSoe(1);
		            			RecDataQueue.getInstance().add(data);
		            			
		            			informationObjectAddress++;
		            			RecData data1 = new RecData();
		            			BeanUtils.copyProperties(data, data1);
		            			data1.setInformationAddress(informationObjectAddress);
		            			IeSinglePointWithQuality singlePoint1 = (IeSinglePointWithQuality) informationElement[0][1];
		            			data1.setQuality(singlePoint1.toJson().toString());
		            			RecDataQueue.getInstance().add(data1);
			            		//}
			            	}
			                break;                
			            default:
			            	Logger.getLogger(this.getClass()).error("其他类型   I帧: " + asdu.getTypeId());
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
					Logger.getLogger(this.getClass()).error(e.getMessage());
				}
            }
        }
    };
}
