package ru.bitel.bgbilling.modules.inet.dyn.device.wifi;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.util.List;

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.common.bean.IPUtils;
import ru.bitel.bgbilling.common.model.ConfigParameter;
import ru.bitel.bgbilling.kernel.wifi.common.WiFiPacket;
import ru.bitel.bgbilling.kernel.wifi.common.WiFiPacketRecord;
import ru.bitel.bgbilling.kernel.wifi.common.WiFiUtil;
import ru.bitel.bgbilling.modules.inet.common.bean.AccessCodes;
import ru.bitel.bgbilling.modules.inet.common.bean.InetConnection;
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.server.util.Setup;
import ru.bitel.common.ParameterMap;
import ru.bitel.common.inet.IpAddress;

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

    protected final static String SA_HOST = "sa.host";
    protected final static String SA_PORT = "sa.port";
	
	private DatagramSocket socket = null;

	private String host;
	private int port;
	private String secret;

	/**
	 * Инициализация обработчика. Вызывается после создания объекта.
	 * @param setup
	 * @param moduleId
	 * @param device
	 * @param deviceType
	 * @param config
	 * @return
	 * @throws Exception
	 */
	@Override
    public Object init( Setup setup, int moduleId, InetDevice device, InetDeviceType deviceType, ParameterMap config )
	    throws Exception
	{
		this.secret = device.getSecret();

		if ( device.getHosts().size() > 0 )
		{
			InetSocketAddress socketAddress = device.getHosts().get( 0 );
			this.host = socketAddress.getAddress().getHostAddress();
			this.port = socketAddress.getPort();
		}
		
        this.host = config.get( SA_HOST, this.host );
        this.port = config.getInt( SA_PORT, this.port );

		return true;
	}

	/**
	 * Подключение к устройству для работы с ним.
	 * @return
	 * @throws Exception
	 */
	@Override
    public Object connect()
	    throws Exception
	{
		socket = new DatagramSocket();
		socket.setSoTimeout( 3000 );
		
		return true;
	}

	/**
	 * Отключение от устройства.
	 * @return
	 * @throws Exception
	 */
	@Override
    public Object disconnect()
	    throws Exception
	{
		socket.close();
		return true;
	}
	/**

	/**
	 * Закрытие (принудительное) соединения.<br>
	 * Обычно вызывается при {@link AccessCodes#TOO_MANY_SESSIONS_ERROR} или из метода {@link #connectionModify(ServiceActivatorEvent)}
	 * @param e
	 * @return
	 * @throws Exception
	 */
	@Override
	public Object connectionClose( ServiceActivatorEvent e )
	    throws Exception
	{	
		logger.debug( "connection close" );
		InetConnection connection = e.getConnection();
		
		WiFiPacketRecord record = null;

		WiFiPacket packetOut = new WiFiPacket();
		packetOut.setSecret( this.secret );
		packetOut.setType( WiFiPacket.TYPE_KILL );

		int ip = IPUtils.convertStringIPtoInt( IpAddress.toString( connection.getInetAddressBytes() ) );

		packetOut.add( ip );
		WiFiUtil.sendPacket( socket, packetOut, host, port );

		WiFiPacket packetIn = WiFiUtil.recievePacket( socket, secret );
		if ( packetIn != null )
		{
			record = packetIn.getFirstRecord();
		}

		// если вернули то же ip занчит все в порядке - убили ip
		return record != null && record.getIp() == ip;
	}

	@Override
    public Object connectionModify( ServiceActivatorEvent e )
        throws Exception
    {
		logger.debug( "connection modify" );
		if ( e.getNewState() == InetServState.STATE_DISABLE.getCode() )
		{
			return connectionClose( e );
		}
		
		return true;
    }
	
    @Override
    public List<ConfigParameter> configParameterList()
    {
        List<ConfigParameter> configParameters = super.configParameterList();
        configParameters.add( new ConfigParameter( SA_HOST, "" ) );
        configParameters.add( new ConfigParameter( SA_PORT, "" ) );
        return configParameters;
    }
}