/*
 *    InsertUniqueValue.java
 *    A task to replace occurences of a given pattern with a given replacement in a given file
 *
 *    Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package org.greenstone.anttasks;

import java.util.ArrayList;
import org.apache.tools.ant.*;
import org.apache.tools.ant.taskdefs.*;
import java.util.*;
import java.io.*;
import java.util.regex.*;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.DirectoryScanner;

public class InsertUniqueValue extends Task {

	private File file = null;
	private ArrayList jobs = null;
	private FileSet fileset = null;
	private String pattern = null;
	private int fromLine = -1;
	private int toLine = -1;
	private boolean winPath = false;
	private int count = 0;

	public static void main( String[] args ) {

		InsertUniqueValue rsr = new InsertUniqueValue();
		rsr.setFile(new File (args[0]));
		rsr.setPattern(args[1]);
		rsr.setLines(args[3]);

		rsr.execute();

	}

	public void execute() {

		if ( file == null && fileset == null ) {
			throw new BuildException( "Error - No file or fileset specified !!" );
		}

		if ( file != null && !file.exists() ) {
			throw new BuildException( "Error - File not found !!" );
		}

		DirectoryScanner dirScanner = null;
		if ( fileset != null ) {
			dirScanner = fileset.getDirectoryScanner(project);
			dirScanner.scan();
		}

		if ( jobs == null && pattern == null ) {
			throw new BuildException( "Error - No pattern attribute and no nested jobs !!" );
		}

		if ( jobs != null && pattern != null ) {
			throw new BuildException( "Error - Both pattern attribute and nested jobs given !!" );
		}

		if ( jobs != null ) {
			for ( int i=0; i<jobs.size(); i++ ) {
				if ( ((InsertUniqueValueJob)(jobs.get(i))).getPattern() == null ) {
					throw new BuildException( "Error - One of the jobs lacks a pattern!!" );
				}
			}
		}


		//sus out filename(s)
		File[] files = null;
		if ( file != null ) {
			files = new File[1];
			files[0] = file;
		} else {
			String[] fileStrings = dirScanner.getIncludedFiles();
			files = new File[fileStrings.length];
			for ( int i=0; i<fileStrings.length; i++ ) {
				files[i] = new File( dirScanner.getBasedir() + File.separator + fileStrings[i] );
			}
		}

		//output greeting
		System.out.println( "-------------------" );
		System.out.println( " InsertUniqueValue " );
		System.out.println( "-------------------" );

		//output lines if necessary
		if ( this.fromLine != -1 || this.toLine != -1 ) {
			System.out.println( "Lines: " + (this.fromLine==-1?"Start":Integer.toString(this.fromLine)) + " ~ " + (this.toLine==-1?"End":Integer.toString(this.toLine)) );
			System.out.println();
		}

		System.out.println( "Files: " );
		for ( int fileIndex=0; fileIndex<files.length; fileIndex++ ) {

			int noReplaces = 0;

			File inputFile = files[fileIndex];
			System.out.println( " " + inputFile );

			//create the output stream
			BufferedWriter out = null;
			File temp = null;
			try {
				//create temp file.
				temp = File.createTempFile("iuv", ".tmp");

				//delete temp file when program exits.
				temp.deleteOnExit();

				//writer to temp file
				out = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(temp), "UTF8") );

			} catch (IOException e) {
				throw new BuildException( "Error - Couldn't create or open the temp file" );
			}


			//create the input stream
			BufferedReader in = null;
			try {
				in = new BufferedReader( new InputStreamReader(new FileInputStream(inputFile), "UTF8") );
			} catch ( Exception e ) {
				throw new BuildException( "Error - Couldn't open the specified file" );
			}

			//pass the file through, searching and replacing
			String line = null;
			int lineNumber = 1;
			boolean hasMoreLines = true;
			while ( hasMoreLines ) {

				try {
					line = in.readLine();
				} catch ( Exception e ) {
					System.err.println( e.getMessage() );
					throw new BuildException( "Error - Couldn't read from the specified file" );
				}

				if ( line == null ) {
					hasMoreLines = false;
				} else {
					//only if within the given line range
					if ( ( fromLine == -1 || lineNumber >= fromLine ) && ( toLine == -1 || lineNumber < toLine ) ) {
						String oldLine = line;
						if ( pattern != null ) {
							int index = 0;
							int prevIndex = 0;
							StringBuffer newLine = new StringBuffer();
							while((index = line.indexOf((String)pattern, index)) != -1)
							{
								newLine.append(line.substring(prevIndex, index));
								newLine.append(pattern + count++);
								index += pattern.length();
								prevIndex = index;
							}
							newLine.append(line.substring(prevIndex, line.length()));
							line = newLine.toString();
						} else {
							for ( int i=0; i<jobs.size(); i++ ) {
								int index = 0;
								int prevIndex = 0;
								StringBuffer newLine = new StringBuffer();
								String currentPattern = ((InsertUniqueValueJob)(jobs.get(i))).getPattern();
								while((index = line.indexOf((String)currentPattern, index)) != -1)
								{
									newLine.append(line.substring(prevIndex, index));
									newLine.append(currentPattern + count++);
									index += currentPattern.length();
									prevIndex = index;
								}
								newLine.append(line.substring(prevIndex, line.length()));
								line = newLine.toString();
							}
						}
						if ( !oldLine.equals( line ) ) {
							noReplaces++;
						}
					}

					try {
						out.write( line );
						out.newLine();
					} catch ( Exception e ) {
						throw new BuildException( "Error - Couldn't write to the temp file" );
					}
				}
				lineNumber++;
			}
			
			try {
				//close them both up
				in.close();
				out.close();
			} catch ( Exception e ) {
				throw new BuildException( "Error - Couldn't close a file" );
			}


			//copy the new file (temp) over the original
			InputStream i;
			OutputStream o;
			try {
				i = new FileInputStream(temp);
				o = new FileOutputStream(inputFile);

			} catch ( Exception e ) {
				throw new BuildException( "Error - Couldn't open the temp file" );
			}

			try {
		
				// Transfer bytes from in to out
				byte[] buf = new byte[1024];
				int len;
				while ((len = i.read(buf)) > 0) {
				   o.write(buf, 0, len);
				}

				//close them up
				i.close();
				o.close();
			} catch ( Exception e ) {
				throw new BuildException( "Error - Couldn't write to the specified file" );
			}

		
			if ( noReplaces == 0 ) {
				System.out.println( " No Changes Made" );
			} else if ( noReplaces == 1 ) {
				System.out.println( " Successfully changed 1 line" );
			} else {
				System.out.println( " Successfully changed " + noReplaces + " lines" );
			}
			System.out.println();

		}

	}

	public void setFile(File file) {
		if ( this.fileset != null || this.file != null ) {
			throw new BuildException( "Error - Only one file or one fileset may be given!!" );
		}
		this.file = file;
	}

	public void setLines(String lines) {
		//lines should be in the form "2" or "2-5"

		//trim
		lines.replaceAll("\\s","");

		if ( lines == "" ) {
			throw new BuildException( "Error - no line number(s) given in lines attribute!! " );
		}

		//split into parts
		String[] parts = lines.split("-",2);

		try {
			if ( parts.length == 1 ) {
				this.fromLine = Integer.parseInt( parts[0] );
				this.toLine = this.fromLine + 1;
			} else {
				if ( !parts[0].equals("") ) this.fromLine = Integer.parseInt( parts[0] );
				if ( !parts[1].equals("") ) this.toLine = Integer.parseInt( parts[1] );
			}
		} catch( NumberFormatException nfe ) {
			throw new BuildException( "Error - invalid line numbers given in lines attribute!! '" + parts[0] + "' - '" + parts[1] + "'" );
		}

	}


	public void setPattern(String pattern) {
		this.pattern = pattern;
	}

	public void setWinPath( boolean isWinPath ) {
		this.winPath = isWinPath;
	}

	public InsertUniqueValueJob createJob() {
		InsertUniqueValueJob job = new InsertUniqueValueJob();
		if ( jobs == null ) {
			jobs = new ArrayList();
		}
		jobs.add( job );
		return job;

	}

	public FileSet createFileset() {
		if ( this.fileset != null || this.file != null ) {
			throw new BuildException( "Error - Only one file or one fileset may be given!!" );
		}
		fileset = new FileSet();
		return fileset;
	}

}
