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

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

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

import ru.bitel.bgbilling.apps.inet.access.sa.ProtocolHandler;
import ru.bitel.bgbilling.kernel.dynamic.server.DynamicClassManager;
import ru.bitel.bgbilling.kernel.network.dhcp.DhcpPacket;
import ru.bitel.bgbilling.kernel.network.radius.RadiusPacket;
import ru.bitel.bgbilling.modules.inet.common.bean.InetDevice;
import ru.bitel.bgbilling.modules.inet.common.bean.InetDeviceType;
import ru.bitel.bgbilling.server.util.Setup;
import ru.bitel.common.ParameterMap;
import ru.bitel.common.Preferences;
import ru.bitel.common.Utils;
import ru.bitel.common.sql.ConnectionSet;
import ru.bitel.common.worker.Destroyable;

/**
 * ProtocolHandler состоящий сразу из нескольких.<br>
 * Классы указываются в конфигурации типа устройства или устройства.<br>
 * <pre>
 * ph.composite.1.class=
 * ph.composite.2.class=
 * </pre>
 * 
 * @author amir
 */
public class CompositeProtocolHandler
	implements ProtocolHandler, Destroyable
{
	private static final Logger logger = LogManager.getLogger();

	private ProtocolHandler[] handlers;

	public CompositeProtocolHandler( ProtocolHandler... handlers )
	{
		this.handlers = handlers;
	}

	public CompositeProtocolHandler()
	{}

	@Override
	public void init( Setup setup, int moduleId, InetDevice device, InetDeviceType deviceType, ParameterMap config )
		throws Exception
	{
		if ( handlers == null )
		{
			loadHandlersFromConfig( device, deviceType );
		}

		for ( ProtocolHandler handler : handlers )
		{
			handler.init( setup, moduleId, device, deviceType, config );
		}
	}

	private void loadHandlersFromConfig( final InetDevice device, final InetDeviceType deviceType )
	{
		final DynamicClassManager dynamicClassManager = DynamicClassManager.getInstance();

		ParameterMap deviceConfig = new Preferences( Utils.maskNull( deviceType.getConfig() ), "\n" );
		deviceConfig = deviceConfig.inherit( new Preferences( Utils.maskNull( device.getInvConfig() ), "\n" ) );
		deviceConfig = deviceConfig.inherit( new Preferences( Utils.maskNull( device.getConfig() ), "\n" ) );

		List<ProtocolHandler> list = new ArrayList<>();

		for ( Map.Entry<Integer, ParameterMap> e : deviceConfig.subIndexed( "ph.composite." ).entrySet() )
		{
			String clazz = e.getValue().get( "class" );
			if ( e.getKey() <= 0 || clazz == null )
			{
				continue;
			}

			try
			{
				ProtocolHandler sa = dynamicClassManager.newInstance( ProtocolHandler.class, clazz );
				list.add( sa );
			}
			catch( Throwable t )
			{
				logger.error( "Error loading class: " + clazz + ". " + t.getMessage(), t );
			}
		}

		handlers = list.toArray( new ProtocolHandler[list.size()] );
	}

	@Override
	public void destroy()
		throws Exception
	{
		for ( ProtocolHandler handler : handlers )
		{
			if ( handler instanceof Destroyable )
			{
				((Destroyable)handler).destroy();
			}
		}
	}

	@Override
	public void preprocessAccessRequest( RadiusPacket request, RadiusPacket response, ConnectionSet connectionSet )
		throws Exception
	{
		for ( ProtocolHandler handler : handlers )
		{
			handler.preprocessAccessRequest( request, response, connectionSet );
		}
	}

	@Override
	public void postprocessAccessRequest( RadiusPacket request, RadiusPacket response, ConnectionSet connectionSet )
		throws Exception
	{
		for ( ProtocolHandler handler : handlers )
		{
			handler.postprocessAccessRequest( request, response, connectionSet );
		}
	}

	@Override
	public void preprocessAccountingRequest( RadiusPacket request, RadiusPacket response, ConnectionSet connectionSet )
		throws Exception
	{
		for ( ProtocolHandler handler : handlers )
		{
			handler.preprocessAccountingRequest( request, response, connectionSet );
		}
	}

	@Override
	public void postprocessAccountingRequest( RadiusPacket request, RadiusPacket response, ConnectionSet connectionSet )
		throws Exception
	{
		for ( ProtocolHandler handler : handlers )
		{
			handler.postprocessAccountingRequest( request, response, connectionSet );
		}
	}

	@Override
	public void preprocessDhcpRequest( DhcpPacket request, DhcpPacket response )
		throws Exception
	{
		for ( ProtocolHandler handler : handlers )
		{
			handler.preprocessDhcpRequest( request, response );
		}
	}

	@Override
	public void postprocessDhcpRequest( DhcpPacket request, DhcpPacket response )
		throws Exception
	{
		for ( ProtocolHandler handler : handlers )
		{
			handler.preprocessDhcpRequest( request, response );
		}
	}
}
