/*
 *    SplitResource.java
 *    A task to split a file into chunks and optionally add references to those
 *    chunks in an rc (resource compiler) script
 *
 *    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 org.apache.tools.ant.*;
import org.apache.tools.ant.taskdefs.*;
import java.util.*;
import java.io.*;
import java.util.regex.*;

/**
 * Splits a file (resource) into chunks of a given size and puts them in files 
 * with the same name as the resource but appended with a dot followed by the chunk number
 */
public class SplitResource extends Task {

	private File resource = null;
	private File resourceScript = null;
	private File outputDir = null;
	private String resourceName = null;
	private String resourceType = null;
	private int chunkSize = 0;
	

	/**
	 * for testing
	 */
	public static void main( String[] args ) {

		SplitResource sr = new SplitResource();
		sr.setResource( new File(args[0]) );
		sr.setOutputDir( new File(args[1]) );
		sr.setResourceScript( new File(args[2]) );
		sr.setResourceName( args[3] );
		sr.setResourceType( args[4] );
		sr.setChunkSize( Integer.parseInt(args[5]) );
		sr.execute();

	}

	public void execute() {

		if ( resource == null ) {
			throw new BuildException( "Error - No resource specified !!" );
		}

		if ( outputDir == null ) {
			outputDir = new File(".");
		}
		outputDir.mkdir();

		if ( chunkSize == 0 ) {
			throw new BuildException( "Error - No chunk size specified !!" );
		}

		DataInputStream is;

		try {
			is = new DataInputStream( new FileInputStream( resource ) );
		} catch ( IOException e ) {
			throw new BuildException( "Error - couldn't open the resource file" );
		}

		//figure out how many chunks to do this in
		int noChunks = (int)(resource.length() / chunkSize) + 1;

		System.out.println( "Splitting file into chunks" );
		System.out.println( "file: " + resource.getAbsolutePath() );
		System.out.println( "file size: " + resource.length() );
		System.out.println( "chunk size: " + chunkSize );
		System.out.println( "ergo, num chunks: " + noChunks );

		long written = 0;
		for ( int i=0; i<noChunks; i++  ) {

			//open a file for output
			DataOutputStream os;
			File partFile = new File( outputDir, resource.getName() + "." + i );
			//System.out.println( "partFile: " + partFile );

			try {
				os = new DataOutputStream( new FileOutputStream( partFile ) );
			} catch ( IOException e ) {
				throw new BuildException( "Error - couldn't create a part file" );
			}


			//sort out thisChunkSize
			int thisChunkSize = chunkSize;
			if ( i == noChunks - 1 ) {
				//System.out.println( "(Last Chunk)");
				thisChunkSize = (int)(resource.length() % chunkSize);
			}

			//System.out.println( "Read a chunk (" + thisChunkSize + " bytes)" );
			byte[] data = new byte[thisChunkSize];
			try {
				is.readFully( data, 0, thisChunkSize );
			} catch( EOFException eof ) {
				throw new BuildException( "Error - unexpectedly hit the end of the resource file" );
			} catch ( IOException e ) {
				throw new BuildException( "Error - couldn't read a byte from the resource file" );
			}

			//System.out.println( "Write to the file");
			try {
				os.write( data, 0, thisChunkSize );
				written += thisChunkSize;
			} catch ( IOException e ) {
				throw new BuildException( "Error - couldn't write out a byte to the part file" );
			}

			try {
				os.close();
			} catch ( IOException e ) {
				throw new BuildException( "Error - couldn't close a chunk output stream" );
			}
      }
		
		//System.out.println( "Total written: " + written + " bytes" );

		try {
	      is.close();
		} catch ( IOException e ) {
			throw new BuildException( "Error - couldn't close the input stream" );
		}


		//if they have specified a resource script and resource name, write an rc file
		if ( resourceScript != null && resourceName != null && resourceType != null ) {
			System.out.println( "Putting references into a resource script" );
			System.out.println( "resourceScript: " + resourceScript.getAbsolutePath() );
			System.out.println( "resourceName  : " + resourceName );
			System.out.println( "resourceType  : " + resourceType );
			
			//open the resource script
			PrintWriter out = null;
			try {
				out = new PrintWriter(new FileWriter( resourceScript, true ));
			} catch ( IOException e ) {
				throw new BuildException( "Error - couldn't open the resource script" );
			}

			//put a line in for each chunk
			for ( int i=0; i<noChunks; i++ ){
				out.println(
					resourceName + "_" + (i+1) + " " + resourceType + " \"" + resource.getName() + "." + i + "\""
					);
			}
			
			//close the resource script
  		   out.close();
		}
	}

   
	public void setResource(File resource) {
		this.resource = resource;
	}

	public void setResourceScript(File resourceScript) {
		this.resourceScript = resourceScript;
	}

	public void setResourceName(String resourceName) {
		this.resourceName = resourceName;
	}
	public void setResourceType(String resourceType) {
		this.resourceType = resourceType;
	}

	public void setOutputDir(File outputDir) {
		this.outputDir = outputDir;
	}

	public void setChunkSize(int chunkSize) {
		this.chunkSize = chunkSize;
	}

}
