/*****************************************************************************
* Anastasios Monachos - anastasiosm@gmail.com
* 
* Compile: javac TextFileLineSplitter.java
*
* Usage: java TextFileLineSplitter inputfile lines_to_split
*
* The program accepts as arguments the name of file and an integer value.  
* The first thing it does, is to determine the number of lines the file has got and in
* combination with the second passed argument it will calculate the number of smaller files
* that will be created.  Each new file will be named in the form inputfile.x.split.txt where x
* is the sequence id number, and each one will have at maximum lines_to_split lines. We say
* "at maximum" as the last-created file usually has got less lines than what the lines_to_split
* parameter specifies.
*****************************************************************************/
import java.io.*;
import java.lang.*;
import java.util.ArrayList;
import java.util.List;

public class TextFileLineSplitter
{
	private static final int UPPER_LIMIT = 2000000000;
	private static int TOTAL_LINES_IN_INPUT_FILE = 0;
	private static int iterations = 0;
	private static int numberOfSmallerFilesNeeded = 0;
	private static int splitToXLines = 0;
	private static int subcounter = 1;
	private static String inputFile = "";
	private static String outputFile = ".split.txt";
	private static List<String> lines = new ArrayList<String>();
	
public static void main(String args[])
{
	// Check the arguments
    if ((args.length!=2))
	{
		help();
	}
	else
	{   
		File f = new File(args[0]);
		inputFile = args[0];
		splitToXLines = Integer.parseInt(args[1]);
		
		if (f.exists())
		{		
			if (splitToXLines<UPPER_LIMIT && splitToXLines>0)
			{
				new TextFileLineSplitter(inputFile,splitToXLines);
				System.out.println("\nThe file "+inputFile+ " now is splitted to smaller chunks\n\n");
			}
			else moreLinesThanExpected();
		}
		else System.out.println("Input file cannot be found, check if its name is typed correctly and try again.\n");
		System.exit(0);
	}
}//end of main

public TextFileLineSplitter(String inputfile, int splitToXLines)
{
//first find how many lines the file has got
	count(inputfile);

//find how many smaller files will be needed
	numberOfSmallerFilesNeeded = (int)Math.floor( (double)(TOTAL_LINES_IN_INPUT_FILE / splitToXLines));
	if ((TOTAL_LINES_IN_INPUT_FILE % splitToXLines) == 0)
	{
		numberOfSmallerFilesNeeded = numberOfSmallerFilesNeeded;
	}
	else
	{
		numberOfSmallerFilesNeeded = numberOfSmallerFilesNeeded+1;
	}System.out.println("I will create in total: " +numberOfSmallerFilesNeeded+" files");


//Load all lines of file in ArrayList
	try
	{
        FileReader file = new FileReader(inputfile);
        BufferedReader buffer = new BufferedReader(file);
        
		String line = null;
		while ((line = buffer.readLine()) != null)
		{
			lines.add(line);
        }
        buffer.close();
	 }
	catch (Exception e)
	{
        System.out.println("Error: " + e.getMessage());
    }
	
//Create chunks and fill them with data	
	iterations = numberOfSmallerFilesNeeded;
	for (int k=0;k<iterations;k++)
	{
		if (TOTAL_LINES_IN_INPUT_FILE<=splitToXLines)//say file has got total lines= 100 and we have asked to split every 200 lines
		{
			try
			{
				File f = new File(inputfile+"."+k+outputFile);
				FileWriter fwriter = new FileWriter(f, true);//true, so to append
				BufferedWriter bwriter = new BufferedWriter(fwriter);
				for (int i=0; i<TOTAL_LINES_IN_INPUT_FILE; i++)
				{
					bwriter.write(lines.get(i));
					bwriter.newLine();
				}
		        bwriter.close();
			}
			catch(IOException e){System.out.println(e); }
		}//end of if
		else if (TOTAL_LINES_IN_INPUT_FILE>splitToXLines)//say file has got total lines= 100 and we have asked to split every 50 lines
		{
			try
			{
				File f = new File(inputfile+"."+k+outputFile);
				FileWriter fwriter = new FileWriter(f, true);//true, so to append
				BufferedWriter bwriter = new BufferedWriter(fwriter);
				
				for (int i=splitToXLines*k; i<splitToXLines*subcounter; i++)
				{
					if (i == TOTAL_LINES_IN_INPUT_FILE)//exit if we ve reached end of arraylist
					{
						break;
					}
					else
					{
						bwriter.write(lines.get(i));
						bwriter.newLine();
					}
				}
				subcounter++;
				//System.out.println("subcounter is :"+subcounter+ "   iteration is:"+k);
			    bwriter.close();
			}
			catch(IOException ie){System.out.println(ie);}
		}//end of else-if
		
		
		
	}//for (int k=0;k<iterations;k++)
}//end of constructor LineShuffler

private static void count(String fileName)
{
	BufferedReader in = null;
	try
	{
		FileReader fileReader = new FileReader(fileName);
		in = new BufferedReader(fileReader);
		String line;
		do {
			line = in.readLine();
			if (line != null)
			{
				TOTAL_LINES_IN_INPUT_FILE++;
				if ( ( TOTAL_LINES_IN_INPUT_FILE % 100 ) == 0 )
				{
					System.out.print(". ");//one dot for every 100 lines
				}	
			}
		}
		while (line != null);
		System.out.println("\nFile: " + fileName + "\t has got: " + TOTAL_LINES_IN_INPUT_FILE + " lines\t\n");
	}
	catch (IOException ioe)	{ioe.printStackTrace();}
	finally
	{
		if (in != null)
		{
			try
			{
				in.close();
			}
			catch (IOException ioe)	{ioe.printStackTrace();}
		}
	}
}//end of private static void count(String fileName)

private static void help()
{
	System.out.println("\n\tUsage: java TextFileLineSplitter input_file_name lines_to_split\n\n\t"+
			"For example: java TextFileLineSplitter names 1000\n"+
			"\t\t     will split the original file called names to smaller files of 1000 lines each\n\n"+
			"\tNote, that the input_file_name should have less than 2,000,000,000 lines in total\n\n");
			System.exit(0);
}//end of private static void help()

private static void moreLinesThanExpected()
{
	System.out.println("The program will exit, as input_file has got too many lines.");
	System.exit(0);
}//end of private static void moreLinesThanExpected()

}//end of public class LineShuffler
