import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.FileReader;
import java.util.ArrayList; 
import java.util.Scanner; 
 
// Report on characters that make up contents of text file (argument 1 [inputfile.txt])
public class FindOccurrences { 

    // Case Insensitive letter issue
    public static String upLow(String incha, Boolean caseConcern) {
    	if (!caseConcern && 
    		         !incha.toLowerCase().equals(incha.toUpperCase())) {
    		        return incha.toLowerCase() + " or " + incha.toUpperCase();
    	}
    	return incha;
    }

    // Return number of words within string
    public static int withinStringNumWord(String instrng, Integer wordChars) {
       Integer wcount = 0, ich, withinword=0;
       for (ich=0; ich<instrng.length(); ich++) {
         if (instrng.substring(ich, (ich+1)).compareTo(" ") > 0) {
           if (withinword == 0) wcount++;
           withinword = 1;
           wordChars++;
         } else {
           withinword = 0;
         }
       }
       return wcount;
    }

    // Return number of occurrences of character within string
    public static int withinStringNumLetter(String instrng, String inchar) {
       Integer ccount = 0, ich;
       for (ich=0; ich<instrng.length(); ich++) {
         if (instrng.substring(ich, (ich+1)).equals(inchar)) ccount++;
       }
       return ccount;
    }
    
    // Read text file with optional header record defining number of records
    public static void readTextFile(String filenm, 
               Boolean caseSensitive,
               ArrayList<String> oura, 
               ArrayList<Integer> ouri) throws IOException  {
     try {
      String nonh = "";
	  BufferedReader ourreader = new BufferedReader(new FileReader(filenm));
	  String linerec = null;
	  Integer numfrecs = 0, irec=0, j, thisk, numchar=0, other=0, wordcount=0, wChars=0;
	  Boolean firstNumLook = true;
	  while ((linerec = ourreader.readLine()) != null) {
    		if (firstNumLook) {
    		   try {
    		     numfrecs = Integer.valueOf(linerec);
    		     nonh = " non-header";
    		   } catch (Exception err) {
    		     firstNumLook = false;
    		     numfrecs = -1;
    		   }
    		} 
    		if (!firstNumLook && numfrecs != 0) {
    		   numchar += linerec.length();
    		   irec++;
    		   wordcount += withinStringNumWord(linerec, wChars);
    		   for (j=0; j<oura.size(); j++) {
    		    if (!caseSensitive && 
    		         !oura.get(j).toLowerCase().equals(oura.get(j).toUpperCase())) {
    		        thisk = withinStringNumLetter(linerec, oura.get(j).toLowerCase());
    		        thisk += withinStringNumLetter(linerec, oura.get(j).toUpperCase());
    		    } else {
    		        thisk = withinStringNumLetter(linerec, oura.get(j));
    		    }
                System.out.printf("Record %d has %d occurrences of character %s ... %s\n",
                   irec, thisk, upLow(oura.get(j), caseSensitive), linerec);
    		      ouri.set(j, ouri.get(j) + thisk);
    		   }    		   
    		   numfrecs--;
    		}
    		firstNumLook = false;
	  }
	  ourreader.close();
	  other = numchar;
	  if (numchar == 0) numchar = 1;
	  if (wChars == 0) wChars = 1;
      for (j=0; j<oura.size(); j++) {
       other -= ouri.get(j);
       System.out.printf("Character %s appears %d times (%.1f%s) in %d%s lines of %s.\n",
         upLow(oura.get(j), caseSensitive), ouri.get(j), 
         (double)((ouri.get(j) * 100.0) / (double)numchar),
         "%", irec, nonh, filenm);
      }    		   
      System.out.printf("Other characters occur %d times (%.1f%s) in %d%s lines of %s.\n",
         other, 
         (double)((other * 100.0) / (double)numchar),
         "%", irec, nonh, filenm);
      System.out.printf("There were %d characters, %d words (%.1f) in%s lines of %s.\n",
         numchar, wordcount, (double)((wChars * 100.0) / (double)wordcount), 
         nonh, filenm);
     } catch (IOException e) {
      System.out.println("Unable to open " + filenm);
     }
	}
 	
 	// Report on characters that make up the contents of a text file (via argument 1)
    public static void main(String[] args) { 

        // Initialize ArrayList and other variables
        ArrayList<String> ourLetter = new ArrayList<String>();         // characters
        ArrayList<Integer> ourLetterCount = new ArrayList<Integer>();  // occurence
        Boolean caseWorry = false;
        String filnm = "inputfile.txt";
        String spares = "Enter input filename";
        String charOfInterest = "-+()':;?!=$.@#&%0123456789abcdefghijklmnopqrstuvwxyz ";
        String up, low;
        Integer ipos;
        Scanner input = new Scanner(System.in);                    
        
        // Check for argument 1 filename
        if (args.length > 0) {
          filnm = args[0]; 
        } else {
          System.out.printf("%s [%s] ... prefix * for case sensitivity\n", spares, filnm);
          spares = input.nextLine(); 
          if (spares.indexOf("*") >= 0) caseWorry = true; 
          if (spares.replace("*", "").length() > 0) filnm = spares.replace("*", "");        
        }
        
        // Populate ArrayList
        for (ipos=0; ipos<charOfInterest.length(); ipos++) {
    	  if (caseWorry) {
    	    low = charOfInterest.substring(ipos, (ipos+1)).toLowerCase();
    	    up = charOfInterest.substring(ipos, (ipos+1)).toUpperCase();
    		if (up.equals(low)) {
              ourLetter.add(charOfInterest.substring(ipos, (ipos+1)));
              ourLetterCount.add(0);
    		} else {
              ourLetter.add(low);
              ourLetterCount.add(0);
              ourLetter.add(up);
              ourLetterCount.add(0);
    		}
    	  } else {
            ourLetter.add(charOfInterest.substring(ipos, (ipos+1)));
            ourLetterCount.add(0);
          }
        }
        
        // Analyze text file and report
        try {
 		  readTextFile(filnm, caseWorry, ourLetter, ourLetterCount);
 		} catch (IOException e) {
          System.out.println("Unable to open " + filnm);
        }
 		
   }
} 
 