package ru.bitel.bgbilling.modules.inet.dyn.device.des3200;

import java.util.Observable;
import java.util.Set;
import java.util.concurrent.Future;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import ru.bitel.bgbilling.apps.inet.access.sa.ServiceActivatorAdapter;
import ru.bitel.bgbilling.apps.inet.access.sa.ServiceActivatorEvent;
import ru.bitel.bgbilling.modules.inet.common.bean.InetDevice;
import ru.bitel.bgbilling.modules.inet.common.bean.InetDeviceType;
import ru.bitel.bgbilling.modules.inet.common.bean.enums.InetServState;
import ru.bitel.bgbilling.modules.inet.server.bean.Keys;
import ru.bitel.common.ParameterMap;
import ru.bitel.common.concurrent.FutureObserver;
import uk.co.westhawk.snmp.stack.AsnInteger;
import uk.co.westhawk.snmp.stack.AsnObject;
import uk.co.westhawk.snmp.stack.AsnObjectId;
import uk.co.westhawk.snmp.stack.SetPdu;
import uk.co.westhawk.snmp.stack.SnmpContext;
import uk.co.westhawk.snmp.stack.SnmpContextv2c;

public class DES320028ServiceActivator
    extends ServiceActivatorAdapter
{
	private static final Logger logger = LogManager.getLogger();

	InetDevice device;
	String host;
	int snmpVersion;
	int snmpPort;

	SnmpContext context;

	long[] oidRxValue = new AsnObjectId( "1.3.6.1.4.1.171.11.113.1.3.2.3.1.1.2" ).getOid();
	long[] oidTxValue = new AsnObjectId( "1.3.6.1.4.1.171.11.113.1.3.2.3.1.1.3" ).getOid();

	@Override
	public Object init( int moduleId, InetDevice device, InetDeviceType deviceType, ParameterMap deviceConfig )
	{
		logger.info( "INIT" );

		this.device = device;

		this.host = device.getHost();
		this.snmpVersion = deviceConfig.getInt( Keys.SNMP_VERSION.key, 1 );
		this.snmpPort = deviceConfig.getInt( Keys.SNMP_PORT.key, 161 );

		this.context = null;

		return true;
	}

	@Override
	public Object destroy()
	{
		logger.info( "DESTROY" );

		return true;
	}

	@Override
	public Object connect()
	        throws Exception
	{
		logger.info( "CONNECT" );

		switch( snmpVersion )
		{
			case 1:
			{
				this.context = new SnmpContext( host, snmpPort );
				break;
			}

			case 2:
			{
				this.context = new SnmpContextv2c( host, snmpPort );
				break;
			}

			default:
			{
				logger.info( "snmpVersion=" + snmpVersion );
				return false;
			}
		}

		this.context.setCommunity( device.getSecret() );

		return true;
	}

	@Override
	public Object disconnect()
	{
		logger.info( "DISCONNECT" );
		if ( context != null )
		{
			context.destroy();
		}

		return true;
	}

	/**
	* Set speed on specified port in kbps.
	*/
	Future<?> setSpeed( int port, int rxKbps, int txKbps )
	        throws Exception
	{
		logger.info( "SET SPEED rx/tx: " + rxKbps + "/" + txKbps + " kbps" );

		AsnObjectId oidRx = new AsnObjectId( oidRxValue );
		oidRx.add( port );
		AsnObjectId oidTx = new AsnObjectId( oidTxValue );
		oidTx.add( port );

		SetPdu setPdu = new SetPdu( context );
		setPdu.addOid( oidRx, new AsnInteger( rxKbps ) );
		setPdu.addOid( oidTx, new AsnInteger( txKbps ) );

		FutureObserver<?> result = new FutureObserver<>()
		{
			@Override
			protected Object updateImpl( Observable obs, Object varbind )
			{
				SetPdu pdu = (SetPdu)obs;
				if ( pdu.getErrorStatus() == AsnObject.SNMP_ERR_NOERROR )
				{
					logger.info( "Ok: " + pdu );

					return true;
				}
				else
				{
					logger.error( "PDU set error: " + varbind );
				}

				return false;
			}
		};

		setPdu.addObserver( result );
		setPdu.send();

		return result;
	}

	@Override
	public Future<?> serviceModify( ServiceActivatorEvent e )
	        throws Exception
	{
		logger.info( "SERVICE MODIFY" );

		int port = e.getNewInetServ().getInterfaceId();
		Set<Integer> optionSet = e.getNewOptions();
		int speed = 64;

		if ( e.getNewState() == InetServState.STATE_ENABLE.getCode() )
		{
			speed = 512;

			if ( optionSet.contains( 1 ) )
			{
				speed = 1024;
			}
			else if ( optionSet.contains( 2 ) )
			{
				speed = 2048;
			}
		}

		return setSpeed( port, speed, speed );
	}

	@Override
	public Object serviceCancel( ServiceActivatorEvent e )
	{
		logger.info( "SERVICE CANCEL" );
		return null;
	}
}
