/*
 * RegexFilter.java
 *
 * Created on March 7, 2001, 2:00 PM
 */

package com.sns.tools.ant.taskdefs;

import org.apache.tools.ant.*;
import org.apache.oro.text.regex.*;
import java.io.*;

/**
 * Performs a regular expression substitution on a given property or file, and
 * stores the source either to the outfile, if one is used, in the source file
 * if not, or else in the specified property if the source is a property.
 *
 *Usage:
 *<pre>
 *  <regexfilter src="${prop1}" search="/" replace="\" property="prop2"/>
 *</pre>
 *
 * @author  <a href="mailto:John.D.Casey@mail.sprint.com">John Casey</a>
 * @version 1.0
 */
public class RegexFilter extends org.apache.tools.ant.Task {
    private String src;
    private File file;
    private File outfile;
    private String search;
    private String replace;
    private String property;
    private boolean overwrite = false;
    
    /**
     * Sets the source property to use.
     *
     *@param src The property to get the search source from.
     */
    public void setSrc(String src){
        this.src = src;
    }
    
    /**
     * Sets the file to search. This and the src attribute are mutually
     * exclusive.
     *
     *@param f The file to search.
     */
    public void setFile(File f){
        this.file = f;
    }
    
    /**
     * Sets the output file for the result of a substitution on a file.
     *
     *@param f The file to write to.
     */
    public void setOutfile(File f){
        this.outfile = f;
    }
    
    /**
     * Sets the search regex. This must be a Perl 5 compliant regular expression.
     *
     *@param srch The search pattern.
     */
    public void setSearch(String srch){
        this.search = srch;
    }
    
    /**
     * Sets the replacement pattern. This must be a Perl 5 compliant regular
     * expression.
     *
     *@param repl The pattern to replace the search results with.
     */
    public void setReplace(String repl){
        this.replace = repl;
    }
    
    /**
     * Sets the property name to store the result of the substitution to.
     *
     *@param prop The property name.
     */
    public void setProperty(String prop){
        this.property = prop;
    }
    
    /**
     * Sets the flag to allow overwriting of a property already in the 
     * environment.
     *
     *@param over Whether or not to overwrite an existing property with the
     * results of this substitution.
     */
    public void setOverwrite(boolean over){
        this.overwrite =  over;
    }
    
    /**
     * Executes the task.
     */
    public void execute(){
        try{
            String source = getSource();
            Perl5Compiler compiler = new Perl5Compiler();
            Perl5Matcher matcher = new Perl5Matcher();
            Pattern pattern = compiler.compile(search);
            Perl5Substitution substitution = new Perl5Substitution(replace, Perl5Substitution.INTERPOLATE_ALL);
            String str = org.apache.oro.text.regex.Util.substitute(matcher,
                                                            pattern, 
                                                            substitution, 
                                                            source, 
                                                            Util.SUBSTITUTE_ALL);
            setOutput(str);
        }
        catch(Exception ex){
            throw new BuildException(ex);
        }
    }
    
    /**
     * Retrieves the source for substitution from the file speficied by the 
     * global file field.
     */
    private String getSource() throws BuildException{
        if(file != null){
            if(outfile == null){
                outfile = file;
            }
            try{
                BufferedReader in = new BufferedReader(new FileReader(file.getAbsolutePath()));
                StringBuffer sb = new StringBuffer();
                char[] c = new char[4096];
                int read = -1;
                while((read = in.read(c)) > -1){
                    sb.append(c, 0, read);
                }
                in.close();
                return sb.toString();
            }
            catch(Exception ex){
                throw new BuildException(ex);
            }
        }
        else{
            if(property == null){
                throw new BuildException("You must specify a property in which to store the output of the regex substitution.");
            }
            return src;
        }
    }
    
    /**
     * Writes the result of the substitution, either to the appropriate file,
     * or to the outgoing property name.
     *
     *@param output The result of the substitution.
     */
    private void setOutput(String output) throws BuildException{
        if(file != null){
            String outF = null;
            if(outfile != null){
                outF = file.getAbsolutePath();
            }
            else if(overwrite){
                outF = file.getAbsolutePath();
            }
            else{
                throw new BuildException("You must either specify an output file to write to (outfile attribute), or set overwrite=\"true\".");
            }
            try{
                PrintWriter out = new PrintWriter(new FileWriter(outF));
                out.print(output);
                out.flush();
                out.close();
            }
            catch(Exception ex){
                throw new BuildException(ex);
            }
        }
        else{
            if(property != null){
                Project prj = getProject();
                if((overwrite) || (prj.getProperty(property) == null)){
                    prj.setProperty(property, output);
                }
                else{
                    log("Couldn't set property: " + property, prj.MSG_VERBOSE);
                }
            }
            else{
                throw new BuildException("You must set the property attribute if using the \'src\' attribute.");
            }
        }
    }

}
