/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * JFlex Anttask                                                           *
 * Copyright (C) 2001       Rafal Mantiuk <Rafal.Mantiuk@bellstream.pl>    *
 * Copyright (C) 2003       changes by Gerwin Klein <lsf@jflex.de>         *
 * All rights reserved.                                                    *
 *                                                                         *
 * This program is free software; you can redistribute it and/or modify    *
 * it under the terms of the GNU General Public License. See the file      *
 * COPYRIGHT for more information.                                         *
 *                                                                         *
 * This program is distributed in the hope that it will be useful,         *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
 * GNU General Public License for more details.                            *
 *                                                                         *
 * You should have received a copy of the GNU General Public License along *
 * with this program; if not, write to the Free Software Foundation, Inc., *
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                 *
 *                                                                         *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

package JFlex.anttask;

import org.apache.tools.ant.Task;
import org.apache.tools.ant.BuildException;

import JFlex.Main;
import JFlex.Options;

import java.io.*;

/**
 * JFlex task class
 *
 * @author Rafal Mantiuk
 * @version JFlex 1.4.3, $Revision: 433 $, $Date: 2009-01-31 19:52:34 +1100 (Sat, 31 Jan 2009) $
 */
public class JFlexTask extends Task {
  private File inputFile;

	// found out by looking into .flex file 
	private String className = null;
	private String packageName = null;

  /** for javac-like dest dir behaviour */
  private File destinationDir;
	
	/** the actual output directory (outputDir = destinationDir + package)) */
	private File outputDir = null;

  public JFlexTask() {
    // ant default is different from the rest of JFlex
    setVerbose(false);
    Options.progress = false;
  }

  public void execute() throws BuildException {
   	try {
      if (inputFile == null) 
        throw new BuildException("Input file needed. Use <jflex file=\"your_scanner.flex\"/>");

			if (!inputFile.canRead()) 
				throw new BuildException("Cannot read input file "+inputFile);

			try {
      	findPackageAndClass();        
        normalizeOutdir();
        File destFile = new File(outputDir, className + ".java");
        
        if (inputFile.lastModified() > destFile.lastModified()) {      
          Main.generate(inputFile);      
          if (!Options.verbose)
            System.out.println("Generated: " + destFile.getName());
        }
      } catch (IOException e1) {
        throw new BuildException("IOException: " + e1.toString());
      }
    } catch (JFlex.GeneratorException e) {
      throw new BuildException("JFlex: generation failed!");
    }
  }

	/**
	 * Peek into .flex file to get package and class name
	 * 
	 * @throws IOException  if there is a problem reading the .flex file 
	 */
	public void findPackageAndClass() throws IOException {
		// find name of the package and class in jflex source file
		packageName = null;
		className = null;

		LineNumberReader reader = new LineNumberReader(new FileReader(inputFile));

		while (className == null || packageName == null) {
			String line = reader.readLine();
			if (line == null)	break;

			if (packageName == null) {
				int index = line.indexOf("package");
				if (index >= 0) {
					index += 7;

					int end = line.indexOf(';', index);
					if (end >= index) {
						packageName = line.substring(index, end);
						packageName = packageName.trim();
					}
				}
			}

			if (className == null) {
				int index = line.indexOf("%class");
				if (index >= 0) {
					index += 6;

					className = line.substring(index);
					className = className.trim();
				}
			}
		}

		// package name may be null, but class name not
		if (className == null) className = "Yylex";
	}

	/**
	 * Sets the actual output directory if not already set. 	
	 *
	 * Uses javac logic to determine output dir = dest dir + package name
	 * If not destdir has been set, output dir = parent of input file
	 * 
	 * Assumes that package name is already set. 
	 */
  public void normalizeOutdir() {
  	if (outputDir != null) return;
  	
    // find out what the destination directory is. Append packageName to dest dir.      
    File destDir;
    
    // this is not the default the jflex logic, but javac-like 
    if (destinationDir != null) {
      if (packageName == null) {
    		destDir = destinationDir;
      }
      else {
        String path = packageName.replace('.', File.separatorChar);
        destDir = new File(destinationDir,path);
      }
    } else { //save parser to the same dir as .flex
      destDir = new File(inputFile.getParent());
    }
    
    setOutdir(destDir);
  }

	/**
	 * @return package name of input file
	 * 
	 * @see JFlexTask.findPackageAndClass
	 */
	public String getPackage() {
		return packageName;
	}

	/**
	 * @return class name of input file
	 * 
	 * @see JFlexTask.findPackageAndClass
	 */
	public String getClassName() {
		return className;
	}

  public void setDestdir(File destinationDir) {
    this.destinationDir = destinationDir;
  }

	public void setOutdir(File outDir) {
		this.outputDir = outDir;
    Options.setDir(outputDir);
	}

  public void setFile(File file) {
    this.inputFile = file;
  }

  public void setGenerateDot(boolean genDot) {
    setDot(genDot);
  }

  public void setTimeStatistics(boolean displayTime) {
    Options.time = displayTime;
  }
  
  public void setTime(boolean displayTime) {
    setTimeStatistics(displayTime);
  }

  public void setVerbose(boolean verbose) {
    Options.verbose = verbose;
  }

  public void setSkeleton(File skeleton) {
    Options.setSkeleton(skeleton);
  }
 
  public void setSkel(File skeleton) {
    setSkeleton(skeleton);
  }

  public void setSkipMinimization(boolean skipMin) {
    setNomin(skipMin);
  }
  
  public void setNomin(boolean b) {
  	Options.no_minimize = b;
  }

  public void setNobak(boolean b) {
    Options.no_backup = b;
  }

  public void setSwitch(boolean b) {
    if (b) {
      Options.gen_method = Options.SWITCH;
    }
    else {
      Options.gen_method = Options.PACK;
    }
  }

  public void setTable(boolean b) {
    if (b) {
      Options.gen_method = Options.TABLE;
    }
    else {
      Options.gen_method = Options.PACK;
    }
  }

  public void setPack(boolean b) {
    if (b) {
      Options.gen_method = Options.PACK;
    }
    else {
      Options.gen_method = Options.SWITCH;
    }    
  }

  public void setDot(boolean b) {
    Options.dot = b;
  }

  public void setDump(boolean b) {
    Options.dump = b;
  }
  
  public void setJLex(boolean b) {    
    Options.jlex = b;
  }
}
