package org.apache.maven.archiva.repository.content;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import org.apache.maven.archiva.common.utils.VersionUtil;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Generic Filename Parser for use with layout routines.
 *
 * @version $Id$
 */
public class FilenameParser
{
    private String name;

    private String extension;

    private int offset;

    private static final Pattern mavenPluginPattern = Pattern.compile( "(maven-.*-plugin)|(.*-maven-plugin)" );

    private static final Pattern extensionPattern =
        Pattern.compile( "(\\.tar\\.gz$)|(\\.tar\\.bz2$)|(\\.[\\-a-z0-9]*$)", Pattern.CASE_INSENSITIVE );

    private static final Pattern SNAPSHOT_PATTERN = Pattern.compile( "^([0-9]{8}\\.[0-9]{6}-[0-9]+)(.*)$" );

    private static final Pattern section = Pattern.compile( "([^-]*)" );

    private Matcher matcher;

    protected FilenameParser( String filename )
    {
        this.name = filename;

        Matcher mat = extensionPattern.matcher( name );
        if ( mat.find() )
        {
            extension = filename.substring( mat.start() + 1 );
            name = name.substring( 0, name.length() - extension.length() - 1 );
        }

        matcher = section.matcher( name );

        reset();
    }

    protected void reset()
    {
        offset = 0;
    }

    protected String next()
    {
        // Past the end of the string.
        if ( offset > name.length() )
        {
            return null;
        }

        // Return the next section.
        if ( matcher.find( offset ) )
        {
            // Return found section.
            offset = matcher.end() + 1;
            return matcher.group();
        }

        // Nothing to return.
        return null;
    }

    protected String expect( String expected )
    {
        String value = null;

        if ( name.startsWith( expected, offset ) )
        {
            value = expected;
        }
        else if ( VersionUtil.isGenericSnapshot( expected ) )
        {
            String version = name.substring( offset );

            // check it starts with the same version up to the snapshot part
            int leadingLength = expected.length() - 9;
            if ( leadingLength > 0 && version.startsWith( expected.substring( 0, leadingLength ) ) &&
                version.length() > leadingLength )
            {
                // If we expect a non-generic snapshot - look for the timestamp
                Matcher m = SNAPSHOT_PATTERN.matcher( version.substring( leadingLength + 1 ) );
                if ( m.matches() )
                {
                    value = version.substring( 0, leadingLength + 1 ) + m.group( 1 );
                }
            }
        }

        if ( value != null )
        {
            // Potential hit. check for '.' or '-' at end of expected.
            int seperatorOffset = offset + value.length();

            // Test for "out of bounds" first. 
            if ( seperatorOffset >= name.length() )
            {
                offset = name.length();
                return value;
            }

            // Test for seperator char.
            char seperatorChar = name.charAt( seperatorOffset );
            if ( ( seperatorChar == '-' ) || ( seperatorChar == '.' ) )
            {
                offset = seperatorOffset + 1;
                return value;
            }
        }

        return null;
    }

    /**
     * Get the current seperator character.
     *
     * @return the seperator character (either '.' or '-'), or 0 if no seperator character available.
     */
    protected char seperator()
    {
        // Past the end of the string?
        if ( offset >= name.length() )
        {
            return 0;
        }

        // Before the start of the string?
        if ( offset <= 0 )
        {
            return 0;
        }

        return name.charAt( offset - 1 );
    }

    protected String getName()
    {
        return name;
    }

    protected String getExtension()
    {
        return extension;
    }

    protected String remaining()
    {
        if ( offset >= name.length() )
        {
            return null;
        }

        String end = name.substring( offset );
        offset = name.length();
        return end;
    }

    protected String nextNonVersion()
    {
        boolean done = false;

        StringBuffer ver = new StringBuffer();

        // Any text upto the end of a special case is considered non-version. 
        Matcher specialMat = mavenPluginPattern.matcher( name );
        if ( specialMat.find() )
        {
            ver.append( name.substring( offset, specialMat.end() ) );
            offset = specialMat.end() + 1;
        }

        while ( !done )
        {
            int initialOffset = offset;
            String section = next();
            if ( section == null )
            {
                done = true;
            }
            else if ( !VersionUtil.isVersion( section ) )
            {
                if ( ver.length() > 0 )
                {
                    ver.append( '-' );
                }
                ver.append( section );
            }
            else
            {
                offset = initialOffset;
                done = true;
            }
        }

        return ver.toString();
    }

    protected String nextVersion()
    {
        boolean done = false;

        StringBuffer ver = new StringBuffer();

        while ( !done )
        {
            int initialOffset = offset;
            String section = next();
            if ( section == null )
            {
                done = true;
            }
            else if ( VersionUtil.isVersion( section ) )
            {
                if ( ver.length() > 0 )
                {
                    ver.append( '-' );
                }
                ver.append( section );
            }
            else
            {
                offset = initialOffset;
                done = true;
            }
        }

        return ver.toString();
    }


}
