/*
 * Copyright (C) The Apache Software Foundation. All rights reserved.
 *
 * This software is published under the terms of the Apache Software License
 * version 1.1, a copy of which has been included  with this distribution in
 * the LICENSE file.
 */
package org.apache.avalon.excalibur.logger.factory;

import org.apache.avalon.excalibur.logger.LogTargetFactory;

import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.context.Context;

import org.apache.log.LogTarget;
import org.apache.log.format.ExtendedPatternFormatter;
import org.apache.log.format.Formatter;
import org.apache.log.format.PatternFormatter;
import org.apache.log.format.RawFormatter;
import org.apache.log.output.io.FileTarget;
import org.apache.log.output.io.rotate.RotatingFileTarget;
import org.apache.log.output.io.rotate.RotateStrategy;
import org.apache.log.output.io.rotate.OrRotateStrategy;
import org.apache.log.output.io.rotate.RotateStrategyBySize;
import org.apache.log.output.io.rotate.RotateStrategyByTime;
import org.apache.log.output.io.rotate.FileStrategy;
import org.apache.log.output.io.rotate.RevolvingFileStrategy;
import org.apache.log.output.io.rotate.UniqueFileStrategy;

import java.io.File;
import java.io.IOException;
import java.util.StringTokenizer;

/**
 * FileTargetFactory class.
 *
 * @author <a href="mailto:giacomo@apache,org">Giacomo Pati</a>
 * @version CVS $Revision: 1.4 $ $Date: 2001/08/25 15:00:26 $
 * @since 4.0
 */
public final class FileTargetFactory implements LogTargetFactory
{
    ///Format of default formatter
    private static final String FORMAT =
        "%7.7{priority} %5.5{time}   [%8.8{category}] (%{context}): %{message}\\n%{throwable}";

    /**
     * Create a LogTarget based on a Configuration
     */
    public final LogTarget createTarget( final Configuration configuration ) 
        throws ConfigurationException
    {
        final Configuration conf_filename = configuration.getChild( "filename" );
        final String filename = conf_filename.getValue();
        
        final Configuration conf_rotation = configuration.getChild( "rotation" );
        
        final Configuration conf_format = configuration.getChild( "format" );

        final Configuration conf_append = configuration.getChild( "append" );
        final boolean append = conf_append.getValueAsBoolean( false );

        
        final LogTarget logtarget;
        
        final File file = new File( filename );
        final Formatter formatter = getFormatter( conf_format );
                      
        try 
        {
            if (conf_rotation == null) 
            {
                logtarget = new FileTarget( file, append, formatter );
            }
            else 
            {    
                final Configuration conf_strategy = conf_rotation.getChildren()[0];
                RotateStrategy rotateStrategy = getRotateStrategy( conf_strategy );
                FileStrategy fileStrategy = getFileStrategy( conf_rotation, file );
                
                logtarget = 
                    new RotatingFileTarget( formatter, rotateStrategy, fileStrategy );
            }
        }
        catch( final IOException ioe ) 
        {
            throw new ConfigurationException( "cannot create FileTarget", ioe );
        }

        return logtarget;
    }

    protected RotateStrategy getRotateStrategy (final Configuration conf)    
    {
        final String type = conf.getName();
        
        if ( "or".equals( type ) )
        {
            final Configuration[] configurations = conf.getChildren();        
            final int size = configurations.length;
            
            final RotateStrategy[] strategies = new RotateStrategy[size];            
            for (int i = 0; i < size; i++)
            {
                strategies[i] = getRotateStrategy(configurations[i]);
            }
            
            return new OrRotateStrategy(strategies);            
        }
        
        if ( "size".equals(type) ) 
        {
            final String value = conf.getValue("2m");
            final long KILOBYTE = 1000;
            final long MEGABYTE = 1000*KILOBYTE;
            
            final int count = value.length();
            final char end = value.charAt(count-1);
            final long no;
            final long size;
            
            switch ( end )
            {
                case 'm':no = Long.parseLong(value.substring(0, count-1));
                         size = no * MEGABYTE;
                         break;
                case 'k':no = Long.parseLong(value.substring(0, count-1));
                         size = no * KILOBYTE;
                         break;
                default: size = Long.parseLong(value);
            }
            
            return new RotateStrategyBySize(size);
        }
        
        // default rotate strategy
        final String value = conf.getValue("24:00:00");
        final long SECOND = 1000;
        final long MINUTE = 60*SECOND;
        final long HOUR = 60*MINUTE;
        final long DAY = 24*HOUR;

        // interpret a string like: ddd:hh:mm:ss ...
        final StringTokenizer tokenizer = new StringTokenizer(value, ":");
        final int count = tokenizer.countTokens();
        long time = 0;
        for (int i = count; i > 0; i--)
        {
            final long no = Long.parseLong(tokenizer.nextToken());
            if (i == 4) 
            {                    
                time += no * DAY;
            }
            if (i == 3) 
            {                    
                time += no * HOUR;
            }
            if (i == 2) 
            {                    
                time += no * MINUTE;
            }
            if (i == 1) 
            {                    
                time += no * SECOND;
            }
        }

        return new RotateStrategyByTime(time);            
    }    
    
    protected FileStrategy getFileStrategy(final Configuration conf, File file) 
    {        
        final String type = conf.getAttribute( "type", "unique" );
        
        if ( "revolving".equals(type) )
        {
            final int initialRotation = 
                conf.getAttributeAsInteger("init", 5); 
            final int maxRotation = 
                conf.getAttributeAsInteger("max", 10); 
            
            return new RevolvingFileStrategy(file, initialRotation, maxRotation);
        }
        
        // default file strategy
        return new UniqueFileStrategy( file );
    }    

    protected Formatter getFormatter(final Configuration conf) 
    {
        final String type = conf.getAttribute( "type", "pattern" );
        final String format = conf.getValue( FORMAT );
        
        if( "extended".equals( type ) )
        {
            return new ExtendedPatternFormatter( format );
        }
        else if( "raw".equals( type ) )
        {
            return new RawFormatter();
        }
        
        // default formatter
        return new PatternFormatter( format );
    }
}

