/*
 *  @(#)XMLFileParserGenerator.java
 *
 * Copyright (C) 2002-2003 Matt Albrecht
 * groboclown@users.sourceforge.net
 * http://groboutils.sourceforge.net
 *
 *  Part of the GroboUtils package at:
 *  http://groboutils.sourceforge.net
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the 
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in 
 *  all copies or substantial portions of the Software. 
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL 
 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 *  DEALINGS IN THE SOFTWARE.
 */
package net.sourceforge.groboutils.pmti.v1.autodoc.v1.xml;


import java.io.File;
import java.io.Writer;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.io.IOException;
import java.io.FilenameFilter;

import java.util.Vector;
import java.util.Enumeration;

import net.sourceforge.groboutils.pmti.v1.itf.parser.IParserGenerator;
import net.sourceforge.groboutils.pmti.v1.itf.parser.IParser;
import net.sourceforge.groboutils.pmti.v1.itf.IIssueRecord;
import net.sourceforge.groboutils.pmti.v1.itf.ITestIssueRecord;

import org.xml.sax.Parser;


/**
 * Parses the directory or directories containing the output of XMLFileServer
 * into individual IParsers, one for each file.
 *
 * @author     Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
 * @since      March 17, 2002
 * @version    $Date: 2003/02/10 22:51:57 $
 */
public class XMLFileParserGenerator implements IParserGenerator
{
    public static final String DEFAULT_PREFIX = "ISSUES-";
    public static final String DEFAULT_POSTFIX = ".xml";
    
    private Vector sourceDirs = new Vector();
    private String filePrefix;
    private String filePostfix;
    private Parser parser;
    
    
    /**
     * Case-insensitive file filter.
     */
    private static class PrefixPostfixFilter implements FilenameFilter
    {
        private String pre;
        private String post;
        
        public PrefixPostfixFilter( String pre, String post )
        {
            this.pre = pre.toLowerCase();
            this.post = post.toLowerCase();
        }
        
        public boolean accept( File dir, String name )
        {
            String n = name.toLowerCase();
            return ( n.startsWith( this.pre )
                && n.endsWith( this.post ) );
        }
    }
    
    
    public XMLFileParserGenerator()
    {
        this( (File[])null, null, null );
    }
    
    
    public XMLFileParserGenerator( File dir )
    {
        this( new File[] { dir }, null, null );
    }
    
    
    public XMLFileParserGenerator( File dir, String prefix, String postfix )
    {
        this( new File[] { dir }, prefix, postfix );
    }
    
    
    public XMLFileParserGenerator( File dirs[] )
    {
        this( dirs, null, null );
    }
    
    
    public XMLFileParserGenerator( File dirs[], String prefix, String postfix )
    {
        addSourceDirs( dirs );
        setFilePrefix( prefix );
        setFilePostfix( postfix );
    }
    
    
    /**
     * Sets the SAX 1.0 parser.
     */
    public void setSAXParser( Parser p )
    {
        if (p != null)
        {
            this.parser = p;
        }
    }
    
    
    /**
     * Set the text that all XML Issue file names must begin with.  Unlike the
     * <tt>XMLFileServer</tt>, the prefix must not contain path information
     * due to the detection methods used.  If a <tt>null</tt> is passed in,
     * then the default value ("ISSUE-") is used instead.  The string will
     * be considered case-insensitive for searching purposes.
     *
     * @param prefix the new prefix value to use.
     */
    public void setFilePrefix( String prefix )
    {
        if (prefix == null)
        {
            prefix = DEFAULT_PREFIX;
        }
        this.filePrefix = prefix;
    }
    
    
    /**
     * Set the text that all XML Issue file names must end with.
     * If a <tt>null</tt> is passed in,
     * then the default value (".xml") is used instead.  The string will
     * be considered case-insensitive for searching purposes.
     *
     * @param postfix the new postfix value to use.
     */
    public void setFilePostfix( String postfix )
    {
        if (postfix == null)
        {
            postfix = DEFAULT_POSTFIX;
        }
        this.filePostfix = postfix;
    }
    
    
    /**
     * Adds <tt>dir</tt> to the internal list of directories to check
     * for issue XML files.  Subdirectories will not be inspected, unless they
     * are explicitly added.
     *
     * @param dir additional directory to search for issue files.
     *      <tt>null</tt> values, non-directories, and non-existent files will
     *      be ignored.
     * @see #addSourceDirs( File[] )
     */
    public void addSourceDir( File dir )
    {
        addSourceDirs( new File[] { dir } );
    }
    
    
    /**
     * Adds the given directories to the internal list of directories to check
     * for issue XML files.  Subdirectories will not be inspected, unless they
     * are explicitly added.
     *
     * @param dirs additional directories to search for issue files.
     *      <tt>null</tt> values, non-directories, and non-existent files will
     *      be ignored.
     * @see #addSourceDir( File )
     */
    public void addSourceDirs( File dirs[] )
    {
        if (dirs == null)
        {
            return;
        }
        
        // Get only the valid dirs
        for ( int i = 0; i < dirs.length; ++i )
        {
            if ( dirs[i] != null
                && dirs[i].exists()
                && dirs[i].isDirectory() )
            {
                this.sourceDirs.addElement( dirs[i] );
            }
        }
    }
    
    
    /**
     * Generate a collection of parsers which know how to create test records.
     */
    public IParser[] createParsers()
    {
        Vector parsers = new Vector();
        
        Enumeration dirs = this.sourceDirs.elements();
        while ( dirs.hasMoreElements() )
        {
            File f[] = findIssueFiles( (File)dirs.nextElement() );
            for ( int i = 0; i < f.length; ++i )
            {
                IParser p = createParser( f[i] );
                if ( p != null )
                {
                    parsers.addElement( p );
                }
            }
        }
        
        IParser p[] = new IParser[ parsers.size() ];
        parsers.copyInto( p );
        
        return p;
    }
    
    
    protected File[] findIssueFiles( File dir )
    {
        FilenameFilter filter = createFilter();
        String found[] = dir.list( filter );
        
        File ret[] = new File[ found.length ];
        for ( int i = 0; i < found.length; ++i )
        {
            ret[i] = new File( dir, found[i] );
        }
        return ret;
    }
    
    
    protected IParser createParser( File issueFile )
    {
        return new XMLFileParser( issueFile, this.parser );
    }
    
    
    protected FilenameFilter createFilter()
    {
        return new PrefixPostfixFilter( this.filePrefix, this.filePostfix );
    }
}

