package ru.bitel.bgbilling.modules.voice.dyn.mediator.phone;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipInputStream;

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

import ru.bitel.bgbilling.apps.voice.accounting.mediation.AbstractMediator;
import ru.bitel.bgbilling.apps.voice.accounting.mediation.VoiceRecord;
import ru.bitel.bgbilling.apps.voice.accounting.mediation.VoiceRecordProcessor;
import ru.bitel.bgbilling.modules.voice.common.bean.VoiceDevice;
import ru.bitel.bgbilling.modules.voice.common.bean.VoiceDeviceType;
import ru.bitel.bgbilling.modules.voice.common.mediation.Mediator;
import ru.bitel.bgbilling.modules.voice.server.runtime.VoiceSessionRuntime;
import ru.bitel.common.TimeUtils;
import ru.bitel.bgbilling.server.util.Setup;
import ru.bitel.common.ParameterMap;
import ru.bitel.common.Utils;

/* TODO переделать на java nio2 и написать unit-тест. Точнее вначале написать unit-Тест, потом переделать 
 * на java.nio2 . Суть unit-теста такая : у нас всего тут Один пока метод public - readHourDataLog - его 
 * тестируем.
 * Надо создать свой файл в тесте,подсунуть сюда и  вместо VoiceRecordProcessor подсунуть свою заглушку
 * (отнаследованную с переопределенными public методами) и потом  проверить с помощью этой заглушки что 
 * считали из этого файла.   
 * 
 */
public class DefaultMediator
	extends AbstractMediator
	implements Mediator
{
	private static final Logger logger = LogManager.getLogger();
	
	private final static Pattern PATTERN_HOUR = Pattern.compile( "(\\d{2})_(\\d{2}).zip" );
	
	private VoiceDevice device; 
	
	@Override
    public Object init( Setup setup, int moduleId, VoiceDevice device, VoiceDeviceType deviceType, ParameterMap config )
        throws Exception
    {
        this.device = device;
	    return super.init( setup, moduleId, device, deviceType, config );        
    }

	@Override
	public void readHourDataLog( final VoiceRecordProcessor processor, final Date hour )
		throws Exception
	{    			    
        InputStream is = null;
        BufferedReader reader = null;
        
        String path = device.getLogPath();
        
	    try
	    {
            String fullPath = path + TimeUtils.format( hour, "/yyyy/MM/dd_HH" );
    		
    		//TODO переделать чтение на java.nio2 
            File file = new File( fullPath + ".zip" );
    		
    		
    		if ( file.exists() )
    		{
    			ZipInputStream zis = new ZipInputStream( new FileInputStream( file ) );
    			zis.getNextEntry();
    
    			is = zis;			
    		}
    		else
    		{
    			file = new File( fullPath );
    			if ( file.exists() )
    			{
    				is = new FileInputStream( file );
    			}
    		}
    		
    		if ( is == null )
    		{
    			logger.warn( "log for " + hour +  " is empty" );
    			return;
    		}
    
    		reader = new BufferedReader( new InputStreamReader( is ), 128 * 1024 );

		    //final Pattern pattern = Pattern.compile( "\\t" );

			String line;
			while( (line = reader.readLine()) != null )
			{
				String[] params = line.split( "\t" );

				if( params.length >= 9 )
				{
					/*if( logger.isDebugEnabled() )
                    {
                        logger.debug( "LINE: " + line );
                    }*/
				    processLine( processor, params );
				}
				else
				{
					logger.warn( "Skip line: " + line );
				}
			}
		}
	    
		finally
		{
			if ( reader != null )
			{
                reader.close();
			}
			
			if ( is != null )
			{
                is.close();
			}
		}
	}
	
	@Override
	public  void getLogExists( Date month, int [] data )
	{
	    String path = device.getLogPath();
	    
        File rootDir = new File( path );
        if ( !rootDir.exists() )
        {
            logger.error( "Каталог не существует - " + rootDir.getAbsolutePath() );
            return;
        }
                
        File monthDir  = new File( path + File.separator + new SimpleDateFormat( "yyyy/MM" ).format( month ) );
        
        if ( monthDir == null || !monthDir.exists() )
        {
            logger.error( "Каталог не существует - " + monthDir.getAbsolutePath() );
            return;
        }
        
        for ( File  logFile : monthDir.listFiles() )
        {
            Matcher matcher = PATTERN_HOUR.matcher( logFile.getName() );
            if ( matcher.find() )
            {
                String dd = matcher.group( 1 );
                String hh = matcher.group( 2 );
                
                //TODO parseByte
                byte day = (byte) Utils.parseInt( dd, -1 );
                byte hour = (byte) Utils.parseInt( hh, -1 );
                
                if ( day > 0 && hour >= 0 )
                {
                    data[day - 1] |=  ( 1 << hour );   
                }
            }
        }
	}

	protected void processLine( final VoiceRecordProcessor processor, final String[] params )
		throws InterruptedException
	{
		final VoiceRecord record = processor.next();

		record.sessionStart = TimeUtils.parseDate( params[0], TimeUtils.DATE_FORMAT_PATTERN_DDMMYYYY_HHMMSS );
		record.duration = record.connectionDuration = Utils.parseInt( params[1], 0 );
		record.callingStationId = params[2];
		record.e164CallingStationId = params[3];
		record.calledStationId = params[4];
		record.e164CalledStationId = params[5];
		record.trunkIncoming = params[6];
		record.trunkOutgoing = params[7];
		record.category = Utils.parseInt( params[8], 0 );

		if( params.length > 9 )
		{
			record.connectionDuration = Utils.parseInt( params[9].trim(), 0 );
			try
			{
				record.callCost = new BigDecimal( params[10] );
				record.callOperCost = new BigDecimal( params[11] );
			}
			catch( Exception e )
			{
			}
		}
	}

	public boolean postSessionCreate( List<VoiceSessionRuntime> recordSessions, VoiceRecord record, boolean abonError, boolean operError )
    {
        return false;
    }
}
