package org.apache.maven.plugin.surefire.util;

/*
 * 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.surefire.api.testset.TestFilter;

import java.io.File;
import java.util.Collection;

import static org.apache.maven.surefire.shared.utils.StringUtils.isBlank;

final class FileScanner
{
    private final File basedir;

    private final String ext;

    FileScanner( File basedir, String ext )
    {
        this.basedir = basedir;
        ext = ext.trim();
        if ( isBlank( ext ) )
        {
            throw new IllegalArgumentException( "No file extension" );
        }
        this.ext = ext.startsWith( "." ) ? ext : "." + ext;
    }

    void scanTo( Collection<String> scannedJavaClassNames, TestFilter<String, String> filter )
    {
        scan( scannedJavaClassNames, filter, basedir );
    }

    private void scan( Collection<String> scannedJavaClassNames,
                       TestFilter<String, String> filter, File basedir, String... subDirectories )
    {
        File[] filesAndDirs = basedir.listFiles();
        if ( filesAndDirs != null )
        {
            final String pAckage = toJavaPackage( subDirectories );
            final String path = toPath( subDirectories );
            final String ext = this.ext;
            final boolean hasExtension = ext != null;
            final int extLength = hasExtension ? ext.length() : 0;
            for ( File fileOrDir : filesAndDirs )
            {
                String name = fileOrDir.getName();
                if ( !name.isEmpty() )
                {
                    if ( fileOrDir.isFile() )
                    {
                        final int clsLength = name.length() - extLength;
                        if ( clsLength > 0
                            && ( !hasExtension || name.regionMatches( true, clsLength, ext, 0, extLength ) ) )
                        {
                            String simpleClassName = hasExtension ? name.substring( 0, clsLength ) : name;
                            if ( filter.shouldRun( toFile( path, simpleClassName ), null ) )
                            {
                                String fullyQualifiedClassName =
                                    pAckage.isEmpty() ? simpleClassName : pAckage + '.' + simpleClassName;
                                scannedJavaClassNames.add( fullyQualifiedClassName );
                            }
                        }
                    }
                    else if ( fileOrDir.isDirectory() )
                    {
                        String[] paths = new String[subDirectories.length + 1];
                        System.arraycopy( subDirectories, 0, paths, 0, subDirectories.length );
                        paths[subDirectories.length] = name;
                        scan( scannedJavaClassNames, filter, fileOrDir, paths );
                    }
                }
            }
        }
    }

    private static String toJavaPackage( String... subDirectories )
    {
        StringBuilder pkg = new StringBuilder();
        for ( int i = 0; i < subDirectories.length; i++ )
        {
            if ( i > 0 && i < subDirectories.length )
            {
                pkg.append( '.' );
            }
            pkg.append( subDirectories[i] );
        }
        return pkg.toString();
    }

    private static String toPath( String... subDirectories )
    {
        StringBuilder pkg = new StringBuilder();
        for ( int i = 0; i < subDirectories.length; i++ )
        {
            if ( i > 0 && i < subDirectories.length )
            {
                pkg.append( '/' );
            }
            pkg.append( subDirectories[i] );
        }
        return pkg.toString();
    }

    private String toFile( String path, String fileNameWithoutExtension )
    {
        String pathWithoutExtension =
            path.isEmpty() ? fileNameWithoutExtension : path + '/' + fileNameWithoutExtension;
        return pathWithoutExtension + ext;
    }
}
