package com.nms.server.snmp.trap;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;

import org.apache.log4j.Logger;
import org.snmp4j.CommandResponder;
import org.snmp4j.CommandResponderEvent;
import org.snmp4j.MessageDispatcherImpl;
import org.snmp4j.PDU;
import org.snmp4j.PDUv1;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.mp.MPv1;
import org.snmp4j.mp.MPv2c;
import org.snmp4j.mp.MPv3;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.security.AuthMD5;
import org.snmp4j.security.AuthSHA;
import org.snmp4j.security.PrivAES128;
import org.snmp4j.security.PrivAES192;
import org.snmp4j.security.PrivAES256;
import org.snmp4j.security.PrivDES;
import org.snmp4j.security.SecurityModels;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.TcpAddress;
import org.snmp4j.smi.UdpAddress;
import org.snmp4j.smi.Variable;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;
import org.snmp4j.util.MultiThreadedMessageDispatcher;
import org.snmp4j.util.ThreadPool;

import com.nms.server.bean.SetInfo;
import com.nms.server.bean.TrapMessageInfo;
import com.nms.server.common.Common;
import com.nms.server.common.Constants;
import com.nms.server.dao.CommonDao;
import com.nms.server.service.CommonService;
import com.nms.server.util.SNMP4JUtils;


/**
 * 本类用于监听代理进程的Trap信息
 * 
 * @author YJS
 * 
 */
public class TrapServer /**extends Service*/
implements CommandResponder{// implements CommandResponder, extends Service
	private static Logger logger = Logger.getLogger(TrapServer.class);
	private static TrapServer ts = null;
	public static TrapServer getInstance() throws IOException{
		if(ts == null){
			ts = new TrapServer();
			logger.info("SNMP Trap Server 启动成功");
		}else{
			logger.info("SNMP TrapServer 已启动");
		}
		return ts;
	}
	
	private TrapServer() throws IOException{
		ThreadPool threadPool = ThreadPool.create("Trap", Constants.SNMP_TRAP_THREAD_POOL_SIZE);
		MultiThreadedMessageDispatcher dispatcher = new MultiThreadedMessageDispatcher(threadPool,	new MessageDispatcherImpl());
		Address listenAddress = GenericAddress.parse(System.getProperty("snmp4j.listenAddress", "udp:" + Common.getLocalIp() + "/" + Constants.SNMP_TRAP_PORT)); // 本地IP与监听端口
		TransportMapping transport = null;
		
//	    			 对TCP与UDP协议进行处理
		if (listenAddress instanceof UdpAddress) {
			transport = new DefaultUdpTransportMapping((UdpAddress) listenAddress);
		} else {
			transport = new DefaultTcpTransportMapping((TcpAddress) listenAddress);
		}
		
		Snmp snmp = new Snmp(dispatcher, transport);
		snmp.getMessageDispatcher().addMessageProcessingModel(new MPv1());
		snmp.getMessageDispatcher().addMessageProcessingModel(new MPv2c());
		snmp.getMessageDispatcher().addMessageProcessingModel(new MPv3());
		USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
		SecurityModels.getInstance().addSecurityModel(usm);
		snmp.listen();
		snmp.addCommandResponder(this);
//	    	        OID authProtocol = getAuthProtocol(Constants.SNMP_V3_AUTH_PROTOCOL);	//认证协议
//	    	        OID privProtocol = getPrivProtocol(Constants.SNMP_V3_PRIV_PROTOCOL);	//加密协议
//	    	        OctetString securityName = new OctetString(Constants.SNMP_V3_SECURITY_NAME);	//认证用户
//	    	        OctetString authPassphrase = new OctetString(Constants.SNMP_V3_AUTH_PASSPHRASE);	//认证密码明文
//	    	        OctetString privPassphrase = new OctetString(Constants.SNMP_V3_PRIV_PASSPHRASE);	//加密密码明文
//	    	    	snmp.getUSM().addUser(securityName, new UsmUser(securityName, authProtocol, authPassphrase,privProtocol, privPassphrase));
	}
	 
    private OID getAuthProtocol(String auth){
    	if (auth.equals("MD5")) {
  		 	return  AuthMD5.ID;
        } else if (auth.equals("SHA")) {
        	return  AuthSHA.ID;
        }else{
        	return null;
        }
    }
    
    private OID getPrivProtocol(String priv){
        if (priv.equals("DES")) {
      	  return PrivDES.ID;
        } else if ((priv.equals("AES128"))
                || (priv.equals("AES"))) {
      	  return PrivAES128.ID;
        } else if (priv.equals("AES192")) {
      	  return PrivAES192.ID;
        } else if (priv.equals("AES256")) {
      	  return PrivAES256.ID;
        }else{
        	return null;
        }
    }

	
	
	
	/**
	 * 实现CommandResponder的processPdu方法, 用于处理传入的请求、PDU等信息 当接收到trap时，会自动进入这个方法
	 * 
	 * @param respEvnt
	 */
	
	public void processPdu(CommandResponderEvent commandresponderevent)
	{
		CommonDao dao = null;
		try
		{
			dao = new CommonDao();
			logger.debug((new StringBuilder("接收到snmp event：")).append(commandresponderevent.getPDU()).toString());
			UdpAddress udpaddress = (UdpAddress)commandresponderevent.getPeerAddress();
			String s = udpaddress.getInetAddress().getHostAddress();
			PDU pdu = commandresponderevent.getPDU();
			logger.debug((new StringBuilder("接收到TRap:")).append(pdu).toString());
			TrapMessageInfo trapmessageinfo = new TrapMessageInfo();
			trapmessageinfo.setAgentSendIP(s);
			setOIDList(trapmessageinfo, pdu);
			setValueList(trapmessageinfo, pdu);
			trapmessageinfo.setOriginalPDU(pdu);
			if (pdu instanceof PDUv1)
			{
				PDUv1 pduv1 = (PDUv1)pdu;
				trapmessageinfo.setTrapVersion(1);
				String s1 = pduv1.getEnterprise().toString();
				trapmessageinfo.setTrapOID(s1);
				String s2 = pduv1.getAgentAddress().toString();
				trapmessageinfo.setPduAgentIP(s);
				trapmessageinfo.setTrapV1SpecificType(pduv1.getSpecificTrap());
				trapmessageinfo.setTrapV1GenericType(pduv1.getGenericTrap());
				trapmessageinfo.setTrapName(trapmessageinfo.getTrapOID());
				switch (pduv1.getGenericTrap())
				{
				case 0: // '\0'
//					trapmessageinfo.setTrapName("设备冷启动");
//					trapmessageinfo.setTrapName("Device Cold Start");
					trapmessageinfo.setTrapName("i18n_server.UpgradeService.coldStart_n81i");
					break;

				case 1: // '\001'
//					trapmessageinfo.setTrapName("设备热启动");
//					trapmessageinfo.setTrapName("Device Hot Start");
					trapmessageinfo.setTrapName("i18n_server.UpgradeService.hotStart_n81i");
					break;

				case 2: // '\002'
//					trapmessageinfo.setTrapName("接口关闭");
//					trapmessageinfo.setTrapName("The Interface Is Closed");
					trapmessageinfo.setTrapName("i18n_server.UpgradeService.interClose_n81i");
					break;

				case 3: // '\003'
//					trapmessageinfo.setTrapName("接口启用");
//					trapmessageinfo.setTrapName("Interface Enabled");
					trapmessageinfo.setTrapName("i18n_server.UpgradeService.interUsed_n81i");
					break;

				case 4: // '\004'
//					trapmessageinfo.setTrapName("SNMP认证失败");
//					trapmessageinfo.setTrapName("SNMP Authentication Failed");
					trapmessageinfo.setTrapName("i18n_server.UpgradeService.snmp_n81i");
					break;

				case 5: // '\005'
//					trapmessageinfo.setTrapName("EGP邻居丢失");
//					trapmessageinfo.setTrapName("EGP Neighbor Lost");
					trapmessageinfo.setTrapName("i18n_server.UpgradeService.egp_n81i");
					break;
				}
			} else
			{
				trapmessageinfo.setTrapVersion(2);
				Variable variable = trapmessageinfo.getOIDValue(SnmpConstants.snmpTrapAddress.toString());
				logger.debug("pdu.snmpTrapAddress() =-=-= "+variable);
				if (variable != null)
					trapmessageinfo.setPduAgentIP(variable.toString());
				Variable variable1 = trapmessageinfo.getOIDValue(SnmpConstants.snmpTrapOID.toString());
				if (variable1 != null)
					trapmessageinfo.setTrapOID(variable1.toString());
				trapmessageinfo.setTrapName(trapmessageinfo.getTrapOID());
				if (variable1 != null)
					if (variable1.equals(SnmpConstants.coldStart))
//						trapmessageinfo.setTrapName("设备冷启动");
//						trapmessageinfo.setTrapName("Device Cold Start");
						trapmessageinfo.setTrapName("i18n_server.UpgradeService.coldStart_n81i");
					else
					if (variable1.equals(SnmpConstants.warmStart))
//						trapmessageinfo.setTrapName("设备热启动");
						trapmessageinfo.setTrapName("i18n_server.UpgradeService.hotStart_n81i");
					else
					if (variable1.equals(SnmpConstants.linkDown))
//						trapmessageinfo.setTrapName("接口关闭");
//						trapmessageinfo.setTrapName("The Interface Is Closed");
						trapmessageinfo.setTrapName("i18n_server.UpgradeService.interClose_n81i");
					else
					if (variable1.equals(SnmpConstants.linkUp))
//						trapmessageinfo.setTrapName("接口启用");
//						trapmessageinfo.setTrapName("Interface Enabled");
						trapmessageinfo.setTrapName("i18n_server.UpgradeService.interUsed_n81i");
					else
					if (variable1.equals(SnmpConstants.authenticationFailure))
//						trapmessageinfo.setTrapName("SNMP认证失败");
//						trapmessageinfo.setTrapName("SNMP Authentication Failed");
						trapmessageinfo.setTrapName("i18n_server.UpgradeService.snmp_n81i");
					else //系统默认的类别不能匹配时，再使用自定义的trap信息库。是否需要分别自定义snmpV1和snmpValue2的trap信息库（定义到文件或者定义到数据库，必须体统重新加载的界面接口）
					if(getTrapName(variable1)!=null &&!variable1.equals("")){
						trapmessageinfo.setTrapName(getTrapName(variable1));
					}else{
//						throw new Exception("未被定义的SNMPTRAP类型！");
						throw new Exception("Undefined SNMPTRAP type!");
					}
			}
			StringBuffer trapInfo = new StringBuffer();
			trapInfo.append("trapmessageinfo.getTrapName()："+trapmessageinfo.getTrapName());
			trapInfo.append("；trapmessageinfo.getAgentSendIP()："+trapmessageinfo.getAgentSendIP());
			trapInfo.append("；trapmessageinfo.getOriginalPDU()："+trapmessageinfo.getOriginalPDU());
			trapInfo.append("；trapmessageinfo.getTrapVersion()："+trapmessageinfo.getTrapVersion());
			trapInfo.append("；trapmessageinfo.getTrapOID()："+trapmessageinfo.getTrapOID());
			trapInfo.append("；trapmessageinfo.getPduAgentIP()："+trapmessageinfo.getPduAgentIP());
			trapInfo.append("；trapmessageinfo.getTrapV1GenericType()："+trapmessageinfo.getTrapV1GenericType());
			trapInfo.append("；trapmessageinfo.getTrapV1SpecificType()："+trapmessageinfo.getTrapV1SpecificType());
			logger.debug("agent IP："+s+"  trap信息："+trapInfo.toString());
			new CommonService(dao).newClientCheck(s,trapmessageinfo.getTrapVersion());
			SetInfo info = Common.getSnmpTrapSetInfo();
			String [] dsb = Common.alarmExceptionInfo(info.getId(), s, info.getCheckTypeName(), info.getProcessIden(), trapmessageinfo.getReceiverTime().getTime(), 1,Constants.DETECTION_INFO_ALARM_WRONG, trapInfo.toString());
			Common.addAlarmData(dsb);
			
		}
		catch (Exception exception)
		{
			logger.debug((new StringBuilder("解析UDP TRAP发生错误:")).append(exception.getMessage()).toString());
		}finally{
			if(dao!=null){
				dao.close();
				dao=null;
			}
		}
	}
	
	public String getTrapName(Variable variable1){
		String trapName = "";
		Map allTrapTypeDefine = new HashMap();
		trapName = allTrapTypeDefine.get(variable1.toString()).toString();
		return trapName;
	}
	
	void setOIDList(TrapMessageInfo trapmessageinfo, PDU pdu)
	{
		Vector vector = pdu.getVariableBindings();
		String s;
//		for(int i=0;i<vector.size();i++){
//			VariableBinding vbing = (VariableBinding)vector.elementAt(i);
//			s = vbing.getOid().toString();
//			trapmessageinfo.getTrapPDUOIDs().add(s);
//		}
		for (Iterator iterator = vector.iterator(); iterator.hasNext(); trapmessageinfo.getTrapPDUOIDs().add(s))
		{
			VariableBinding variablebinding = (VariableBinding)iterator.next();
			s = variablebinding.getOid().toString();
		}

	}

	void setValueList(TrapMessageInfo trapmessageinfo, PDU pdu)
	{
		Vector vector = pdu.getVariableBindings();
		Variable variable;
		for (Iterator iterator = vector.iterator(); iterator.hasNext(); trapmessageinfo.getTrapPDUOIDValues().add(variable))
		{
			VariableBinding variablebinding = (VariableBinding)iterator.next();
			variable = variablebinding.getVariable();
		}

	}
	
/*	public static void main(String[] args) {
		TrapServer multithreadedtrapreceiver = new TrapServer();
		multithreadedtrapreceiver.run();
	}*/

	/** */
	/**
	 * 解决snmp4j中文乱码问题
	 */
	public static String getChinese(String octetString) {
		try {
			String[] temps = octetString.split(":");
			byte[] bs = new byte[temps.length];
			for (int i = 0; i < temps.length; i++)
				bs[i] = (byte) Integer.parseInt(temps[i], 16);

			return new String(bs, "GB2312");
		} catch (Exception e) {
			return null;
		}
	}

	/** 
	 * 将十进六制转换成为中文 
	 *//*
	private static String hexString = "0123456789ABCDEF";

	public static String toStringHex(String bytes) {

		ByteArrayOutputStream baos = new ByteArrayOutputStream(
				bytes.length() / 2);
		//将每2位16进制整数组装成一个字节 
		for (int i = 0; i < bytes.length(); i += 2) {
			baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString
					.indexOf(bytes.charAt(i + 1))));
		}
		return new String(baos.toByteArray());
	}*/

	protected static String printVariableBindings(PDU response) {
		String strCom = "";
		for (int i = 0; i < response.size(); i++) {
			VariableBinding vb = response.get(i);
			String[] str = vb.getVariable().toString().toUpperCase().split(":");

			String strOut = "";
			int intLength = str.length;
			logger.debug("长度==> " + intLength);
			for (int j = 0; j < intLength; j++) {
				strOut += str[j];
			}
			strCom += vb.getVariable();
			if (str.length != 1) {
				logger.debug("==第行=vb.getVariable()=" + SNMP4JUtils.toStringHex(strOut));//显示中文 
			}
		}
		return strCom;

	}
	public static void  main(String [] args) {
		try {
			TrapServer.getInstance();
			TrapServer.getInstance();
			TrapServer.getInstance();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
