/*
Online Java - IDE, Code Editor, Compiler

Online Java is a quick and easy tool that helps you to build, compile, test your programs online.
*/

import java.util.*;

public class FullyJustified
{
    public static void main(String[] args) 
    {
        System.out.println("Welcome to Online IDE!! Happy Coding :)");
        
        String text = "The quick brown fox jumps over the lazy dog";  // no issues.....
        //String text="";   // no issues
        //String text = " This is a test, but making it a bit longer!";  //no issues....
        //String text = "My";   //no issues
        //String text = "      My name is Amit Amlani. This is a sligthly longer test to see if the text can be spanned across multiple lines.";
        //String text = "  Some blank now            but there should be extreme amount on start second line";
        //String text = "This will be 16.";   //no issues.
        //String text = "This will be 16. Amit";  //no issues....
        //String text = "Thiswillbetesting  16 testing.";  //no issues
        //String text = "Java is a high-level, class-based";  // no issues...
        //String text="Java is a high-level, class-based, object-oriented programming language that is designed to have as few implementation dependencies as possible. It is a general-purpose programming language intended to let programmers write once, run anywhere (WORA),[16] meaning that compiled Java code can run on all platforms that support Java without the need to recompile.[17] Java applications are typically compiled to bytecode that can run on any Java virtual machine (JVM) regardless of the underlying computer architecture. The syntax of Java is similar to C and C++, but has fewer low-level facilities than either of them. The Java runtime provides dynamic capabilities (such as reflection and runtime code modification) that are typically not available in traditional compiled languages.";
        
        String lastLine="";
        int k=16;
        String tokentoString="";
        String line;
        int wordCount=0;
        int lineLength;
        String lineBeforeLastWord="";
        int lengthLineBeforeLastWord;
        String completeLine="";
        String totalExtraPaddingBetweenWords="";
        int extraPaddingBetweenWords=0;
        boolean conditionOncePerLine=true;
        int extraFrontPadding=0;
        String truncatedWord="";
        String delimiter=" ";
        int wordsIntoLineAfterTruncation=0;
        int buffer=0;
        int completeLinelength=0;
        int lengthLastLine=0;
        int newposText=0;
        String existingFrontalPadding="";
        String existingFrontalPaddingTest="*";
        int existingFrontalPaddingCount=0;
        String[] completedLineRepository = new String[1000];
        int num=0;
        String paddingTest = "Â·";
        StringJoiner sj = new StringJoiner(paddingTest);
        int tokenLength=0;
        StringTokenizer st = new StringTokenizer(text, delimiter);
        String temp="";
        StringTokenizer st1;
        String temp1;
        StringTokenizer st2;
        String temp2;
        StringBuilder sb=new StringBuilder();
        String alternateToken="";
        
        System.out.println("Original Text: " + text +"\n");
        
       for (int h=newposText; h<text.length(); h++)
       {
           if (text.charAt(h)==' ')
           {
               existingFrontalPadding = existingFrontalPadding + existingFrontalPaddingTest;
               existingFrontalPaddingCount++;  //keeps count of existing frontal paddig...
           }
           else
           {
               newposText=h;
               break;
           }
       }
       while (st.hasMoreTokens())  //checking text for tokens....
       {
            if (truncatedWord!="")
            {
                sb.append(truncatedWord);
                sj.add(sb);
                truncatedWord="";
                sb.delete(0,sb.length());
                wordsIntoLineAfterTruncation++;
            }
            temp=st.nextToken();
            tokentoString = temp.toString();
            tokenLength=tokentoString.length();
            
            if (wordCount==0)
            {
                sb.append(existingFrontalPadding);
                sb.append(tokentoString);
                alternateToken= existingFrontalPadding + tokentoString;
            }
            
            wordCount++;  //overall total number of words increases....
            
            if ((tokenLength + existingFrontalPaddingCount) >k)
            {
                System.out.println("The following word exceeds line limit of k" + "(" + k + "):" + (temp));
                System.exit(0);  //exit Java code....
            }
            sb.delete(0,sb.length());
            
            if (wordCount>0)
            {
                sb.append(tokentoString); 
            }
            
            lineBeforeLastWord = sj.toString(); 
            
            if (existingFrontalPadding=="")
            {
                sj.add(sb);  //  StringBuilder added into StringJoiner.... This is a continuous process with delimiter defined...
            }
            else
            {
                System.out.println("Your existing frontal padding:"+existingFrontalPadding);
                sj.add(alternateToken);
                System.out.println("This is the token chosen:" + alternateToken);
            }
            existingFrontalPadding="";
            sb.delete(0,sb.length());  //remove contents of StringBuffer ready for another token
            line = sj.toString();  
            lineLength=line.length();  //determines length of the line...
            wordsIntoLineAfterTruncation++;
            
            System.out.println("Your line getting bigger:" + line + "(" + lineLength + " chars inc white space)");
            System.out.println("Words after truncation: " + wordsIntoLineAfterTruncation);
                
            if (lineLength==k)
            {
                completeLine = line;   //note it is line here not lineBeforeLastWord since no truncation..
                completedLineRepository[num]=line;
                num++;  //counter for index...
                completeLinelength=completeLine.length();
                System.out.println("Completed line:" +line);
                sj=new StringJoiner(paddingTest);
                wordsIntoLineAfterTruncation=0;
                totalExtraPaddingBetweenWords="";
                sb.delete(0,sb.length());
                tokentoString="";
                temp="";
                
                System.out.println("NEW LENGTH of line:" + completeLinelength);
            }
            
            if (lineLength>k)
            {
                lengthLineBeforeLastWord= lineBeforeLastWord.length();
                System.out.println("Rolled back to(due to exceeding " + k +"):" + lineBeforeLastWord);
                System.out.println("Length rolled back line: " + lengthLineBeforeLastWord);
                truncatedWord=temp;
                System.out.println("This word getting truncated:" + truncatedWord);
                wordsIntoLineAfterTruncation--;
                buffer = k-lengthLineBeforeLastWord;
                System.out.println("The current buffer is: " + buffer);
                System.out.println("Number words to accomodate for: " + wordsIntoLineAfterTruncation + "("+ lineBeforeLastWord+")");
                System.out.println("Last word in tokenizer should be same as truncated word: " + temp);
                System.out.println("What is wordcount here: " + wordCount);
                System.out.println("What is truncated word count: " + wordsIntoLineAfterTruncation +"(" + lineBeforeLastWord +")  " + lengthLineBeforeLastWord + " chars" );
                System.out.println("Value of temp:" + temp);
                
                if (buffer>0)
                {
                    sj = new StringJoiner(paddingTest);  //resets StringJoiner....
                    completeLine="";
                try
                {
                    if (buffer%(wordsIntoLineAfterTruncation-1)==0 && wordsIntoLineAfterTruncation>1)
                    {
                        extraPaddingBetweenWords = buffer/(wordsIntoLineAfterTruncation-1);
                
                        System.out.println("CURRENT LENGTH of line: " + lengthLineBeforeLastWord);
                        System.out.println("Qualified for extra padding");
                        System.out.println(extraPaddingBetweenWords + " extra padding between:" + lineBeforeLastWord);
                    
                        for (int j=0; j<extraPaddingBetweenWords;j++)
                        {
                            totalExtraPaddingBetweenWords = totalExtraPaddingBetweenWords + paddingTest;
                        }
                        
                        System.out.println("It will now process truncated string with extra " + extraPaddingBetweenWords + " padding between the words:" + lineBeforeLastWord);
                        st1=new StringTokenizer(lineBeforeLastWord, paddingTest); 
                        sj = new StringJoiner(paddingTest+totalExtraPaddingBetweenWords); 
                    
                        while (st1.hasMoreTokens())
                        {
                            temp1=st1.nextToken();
                            sj.add(temp1);
                            System.out.println("Your line getting bigger:" + sj.toString() + "(" + sj.toString().length() + " chars inc white space)");
                            sb.append(sj);
                            completeLine=sb.toString();
                            sb.delete(0,sb.length()); //removes content from index 0 to sb.length()-1
                        }
                        System.out.println("NEW LENGTH of line after formatting: " + completeLinelength);
                    }
                    else
                    {
                        if (temp!="")
                        {
                            extraFrontPadding=buffer;
                            System.out.println(lineBeforeLastWord + "   =>qualifies for " + extraFrontPadding + " padding at front since it has:" +  wordsIntoLineAfterTruncation + " words");
                            sb.append(lineBeforeLastWord);
                            System.out.println("CURRENT LENGTH of line: " + lengthLineBeforeLastWord);
                
                            for (int b=0; b<buffer; b++)
                            {
                                sb.insert(0, paddingTest);
                            }
                            completeLine = sb.toString();
                            completeLinelength=completeLine.length();
                            System.out.println("NEW LENGTH of line after formatting: " + completeLinelength);
                            sj.add(temp);
                        }
                    }
                }// end of try
                
                catch (ArithmeticException e)
                {
                    if (temp!="")
                    {
                        extraFrontPadding=buffer;
                        System.out.println(lineBeforeLastWord + "   =>qualifies for " + extraFrontPadding + " padding at end since it has:" +  wordsIntoLineAfterTruncation + " words");
                        sb.append(lineBeforeLastWord);
                        System.out.println("CURRENT LENGTH of line: " + lengthLineBeforeLastWord);
                        
                        for (int b=0; b<buffer; b++)
                        {
                            sb.insert((lengthLineBeforeLastWord),paddingTest);
                        }
                        completeLine = sb.toString();
                        completeLinelength=completeLine.length();
                        System.out.println("NEW LENGTH of line after formatting: " + completeLinelength);
                        sj.add(temp);
                
                    }//end of if  (temp!="")
                } //end of catch
                
                System.out.println("Completed line:" +completeLine);
                sj=new StringJoiner(paddingTest);
                wordsIntoLineAfterTruncation=0;
                totalExtraPaddingBetweenWords="";
                sb.delete(0,sb.length());
                completedLineRepository[num]=completeLine;
                num++;
                System.out.println("This word will be carried over to next line:" + temp +"\n");
                
                }  //end of if buffer is greater than 0
            }  //end of if linelength is greater than k
        }   //end while (has more tokens)
        
        lastLine=sj.toString();
        System.out.println("Last token processed:" + temp);
        System.out.println("******Currently in last line:" + lastLine);
        System.out.println("***************************");
        
        if (lastLine=="")
        {
            lastLine=temp;
        }
        
        System.out.println("Finally completing the last line:" + lastLine);
        lengthLastLine = lastLine.length(); 
        
        if (temp!="")
        {
            try
            {
                while (!st.hasMoreTokens())
                {
                    if (wordsIntoLineAfterTruncation==0 && wordCount>0)
                    {
                        wordsIntoLineAfterTruncation++;
                    }
                    
                    System.out.println("Left over StringJoiner: " + wordsIntoLineAfterTruncation + " word(s)=>   " +  lastLine + "  (" + lengthLastLine + " chars inc white space)");
                    System.out.println("Total running words: " + wordCount);
                    buffer=k-lengthLastLine;
                    System.out.println("Buffer is: " + buffer);
                    
                    if ((buffer%(wordsIntoLineAfterTruncation-1)==0 && wordsIntoLineAfterTruncation>1) )
                    {
                        extraPaddingBetweenWords = buffer/(wordsIntoLineAfterTruncation-1);
                        System.out.println("It will now process the string with extra: " + extraPaddingBetweenWords + " padding between words:" + lastLine);
                        
                        if (extraPaddingBetweenWords>0)
                        {
                            for (int j=0; j<extraPaddingBetweenWords;j++)
                            {
                                totalExtraPaddingBetweenWords = totalExtraPaddingBetweenWords + paddingTest;
                            }
                        }
                        
                        st2=new StringTokenizer(lastLine, paddingTest);
                        sj = new StringJoiner(paddingTest + totalExtraPaddingBetweenWords);
                    
                    while (st2.hasMoreTokens())
                    {
                        temp2=st2.nextToken();
                        sj.add(temp2);
                        System.out.println("your line getting bigger:" + sj.toString() + "(" + sj.toString().length() + " chars inc white space will NOT exceed " + k + ")");
                    }
                    
                    if (conditionOncePerLine)
                    {
                        sb.append(sj);
                        completeLine=sb.toString();
                        conditionOncePerLine=false;
                    }
                }   //end if checking if multiple words and buffer can be divided inter-word....
                
                else
                {
                    if (wordCount>0)
                    {
                        System.out.println("There is one word in last line:" + temp);
                        System.out.println("CURRENT LENGTH of line: " + tokenLength);
                        sb.append(lastLine);
                        System.out.println(lastLine + "   =>qualifies for " + buffer + " padding at end since it has:" +  wordsIntoLineAfterTruncation + " word(s)");
                
                        for (int b=0; b<buffer; b++)
                        {
                            sb.insert((lengthLastLine),paddingTest);
                        }
                        
                        completeLine = sb.toString();
                    }
                }//end of else statement....
                
          
                break; //breaking out of do while loop
                }//end of while loop
            }//end of try loop
            catch (ArithmeticException e)
            {
                System.out.println("Entering here most likely due to having one word in the line");
                System.out.println("So the StringBuilder should be empty: " + sb.toString());
        
                sb.append(temp);
                lengthLastLine=lastLine.length();   //length of the last line....
                buffer=k-lengthLastLine;  //buffer is remainder from k.
                System.out.println(lastLine + "   =>qualifies for " + buffer + " padding at end since it has:" +  wordsIntoLineAfterTruncation + " word(s)");
                
                for (int b=0; b<buffer; b++)
                {
                    sb.insert((lengthLastLine), paddingTest);
                }
                completeLine = sb.toString();
               
            }  //end of catch statement...
            
            completeLinelength = completeLine.length();
            System.out.println("completed line:" + completeLine);
            completedLineRepository[num]=completeLine;
            num++;
            System.out.println("NEW LENGTH of line:" + completeLinelength);
        }//end of if (temp!="")
        
        System.out.println("\n\n****THIS WILL PRINT ENTIRE TEXT**************");
        System.out.println("KEY: "  +  k + " line limit");
        System.out.println(paddingTest + "=Inter-word padding as per requirements");
        System.out.println(existingFrontalPaddingTest + "=existing frontal padding");
        System.out.println("In future, can provision for existing inter-word padding for instance multiple whitespaces..");
        System.out.println("BUT expect user to have single whitespace for the justification to look tidy" + "\n\n");
        
        for (String s: completedLineRepository)
        {
            if (s!=null)
            {
                System.out.println(s);
            }
        }
        System.out.println("*****************************");
        
    }  //end of main method.
}  //end of single class used......