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

//Note I am using the term beads to refer to number of dots on each line

//unfortunately I started to implement logic outside of the recursive method, which in reality should have remained inside.
//but I have just accepted it

//also consider removing the collection related code manually for higher recursion count.
//it is simply decorative code and serves no logical purpose

import java.util.*;

public class CentredHexagonalNumber
{
    static Map <Integer, Integer> mp = new HashMap<>();
    static StringJoiner[] sj;
    static int row;
    static StringJoiner sjDissector = new StringJoiner("");
    static String paddingAtFront="";
   
    static boolean hasExistingKeyinMap=false;
    static int nthValue;
    static long result=0;
    static int finalTotal=0;
    static boolean firstExecution=true;
    static int retrievedValueInteger;
    static boolean hasProcessedRow=false;
    
    public static void main(String[] args)
    {
        System.out.println("Welcome to Online IDE!! Happy Coding :)");
        
        int n=45;   //this is inputted end user to check if it is a central Hexagonal number 
        int N=9;  //inputted by end user
        int M;
        int R;
        int k=0;
       
        System.out.println("***CENTERED HEXAGONAL NUMBER***");
       
        for (int i=1;i<N;i++)
        {
            System.out.println("***************************************************");
           
            M=(i*2)-1;
               
            nthValue = nthValue+1;
            hasExistingKeyinMap=false;
            hasProcessedRow=false;
            result=0;
           
            System.out.println("\nThis is the Nth term: " + (nthValue));
            System.out.println("Middle disector (beads): " + M);
               
            R=i-1;
            System.out.println("Number rows above or below: " + R);
           
            sj = new StringJoiner[R];
         
            if (R==0)
            {
                finalTotal=1;
                System.out.println("******FINAL TOTAL: " + finalTotal);    
                System.out.println("***Hexagon Arrangement***");
                System.out.println("O");
       
                if (finalTotal==n && n!=0)
                {
                     System.out.println("A CENTRAL HEXAGON NUMBER: " + n);
                   
                     System.exit(0);
                }
            }
               
            if (k!=1)
            {
                for (k=R; k>=1;k--)
                {
                    paddingAtFront="";
                    System.out.println("CURRENT RUNNING TOTAL BEADS: " + result);
                    System.out.println("Total full count: " + CentredHexagonalNumber(mp,i,M,k,R,n));
                }
            }
        }
    }
   
    public static long CentredHexagonalNumber (Map mp, int i, int M, int k,int R,int n)
    {
        StringBuilder sb = new StringBuilder();
       
       //set this value if there is StackOverFlow manually
       //this could vary depending on the resources, so end user can take control
        if (nthValue==47)
        {
            System.out.println("*****Code will terminate due to recursion limits*******");
            System.exit(0);
        }
       
        if (k>=1)
        {
           
           
            System.out.println("BEADS in: " + (k) + " row above disector is: " + (M-k));
           
            //goes through each row
            for (int count=0;count<R;count++)
            {
                //clears stringjoiner and stringbuilder for the row
                sj[k-1]=new StringJoiner("");
               
               
                //we know that number of beads on each row is
                //disector - row number
                //we are also starting with row number furtherst away first
                //so that we can get the totals and use map...
                // for instance  row 2 has 3 beads (M-k  = 5-2)
               
                         //* * *
                        //* * * *
                       //* * * * *
                for (int space=0; space<(M-k);space++)
                {
                    sb.append("O ");
                }
               
                //we know in row 1, there is one space at front
                //in row 2, there are two spaces at front
                for (int space=0; space<k;space++)
                {
                    paddingAtFront=paddingAtFront + "-";
                    //System.out.println("TOTAL SPACE INSERTED: " + k);
                }
               
                //we expect both these to be identical
                System.out.println("************************8length sj: " + sj.length);
                System.out.println("R: " + R);
               
                System.out.println("This is front padding:" + paddingAtFront);
                System.out.println("This is length StringJoiner: " + sj.length);
                System.out.println("these are the beads on row" + "("+k+"):" + sb);
                System.out.println("StringJoiner to be filled => row: "  +"("+(k-1)+"): " + (paddingAtFront+sb));
               
                //this will add the padding and the stringbuilder into the String and store into row
               
                //if (sj[k-1].toString().equals(""))
                //{
                sj[k-1].add(paddingAtFront+sb);
                System.out.println("This has been written into StringJoiner index array" + "["+(k-1)+"]  =>" + sj[k-1]);
                //}
               
                //need to clear StringBuilder for next row execution or ready for the next N value
                sb=new StringBuilder();
                paddingAtFront="";
                break;
            }
           
            result=result + (M-k);
            System.out.println("CURRENT RUNNING TOTAL BEADS: " + result);
           
            if (R!=1)
            {
                retrievedValueInteger=M-k;
                //int key = retrievedValueInteger-1;
               
                System.out.println("Checking if key " + "("+k+")" + " in HashMap");
               
                if (mp.containsKey((k)))
                {
                    System.out.println("Current key: " + k + " already in HashMap. Retrieving value: " + mp.get(k));
                   
                    Object retrievedValue = mp.get(k);
                    retrievedValueInteger = Integer.parseInt(retrievedValue.toString());
                    hasExistingKeyinMap = true;
                   
                    finalTotal  = (int)(result*2)+M;
                     
                    System.out.println("2******FINAL TOTAL: " + finalTotal + "     (" + result + "x" + 2+")" + "+"+M);
       
                    if (finalTotal==n && n!=0)
                    {
                        System.out.println("A CENTRAL HEXAGON NUMBER: " + n);
                        System.exit(0);
                    }
                }
                hasProcessedRow=true;
               
                if (result!=0)
            {
                //System.out.println("Currently processed row " + retrievedValueInteger+": " + hasProcessedRow + "   with result: " + result);
                System.out.println("Has existing key" + "("+k+","+result+")" + " in map: " + hasExistingKeyinMap);
            }
           
            if(!hasExistingKeyinMap && hasProcessedRow)
            {
                System.out.println("No key entry"+"("+ k+")" + " in hashmap. To be added " + "("+k+","+result+")");
                mp.put(k,result);
               
                hasExistingKeyinMap=false;
                hasProcessedRow=false;
            }
               
System.out.println("Recursive loop to perform next row in hexagon: " + (k-1));
                result = retrievedValueInteger + (CentredHexagonalNumber (mp,i,M,(k-1),R,n));
               
                System.out.println("number provided: " + n);
                System.out.println("Final Total: " + finalTotal);
               
                if (finalTotal>n)
                {
                    System.out.println("INVALID - NOT A CENTRAL HEXAGON NUMBER: " + n);
                    System.exit(0);
                }
               
                if (finalTotal==n && n!=0)
                {
                     System.out.println("A CENTRAL HEXAGON NUMBER: " + n);
                     System.exit(0);
                }
               
                M=M+2;
               
                System.out.println("This is FinalTotal: " + finalTotal);
               
                finalTotal=0;
                nthValue=nthValue+1;
                hasExistingKeyinMap=false;
                hasProcessedRow=false;
                result=0;
               
                System.out.println("\nThis is the Nth term: " + (nthValue));
               
                sb = new StringBuilder();
               
                sjDissector = new StringJoiner("");
                firstExecution=true;
                R=nthValue-1;
                sj = new StringJoiner[R];
               
                //critical part, need to initialise each one separately upon creating instance variable
            //above
            for (int t=0;t<sj.length;t++)
            {
                sj[t]=new StringJoiner("");
            }
               
               
               
                System.out.println("Middle disector: " + M);
               
                result=0;
               
                k=R;
               
                if (k>=1)
                {  
                    if (firstExecution)
                    {
                        System.out.println("FIRST EXECUTION ONCE");
                        result = finalTotal+(CentredHexagonalNumber (mp,i,M,(k),R,n));
                        firstExecution=false;
                    }
                    else
                    {
                        result = finalTotal+(CentredHexagonalNumber (mp,i,M,(k-1),R,n));
                    }
                }
               
                if (k==0)
                {
                    return result;
                }
            }
            else
            {
                result = M-k;
            }
        }
       
        //if (!mp.containsKey(retrievedValueInteger))
        //{
            finalTotal  = (int)(result*2)+M;
       
            System.out.println("1******FINAL TOTAL: " + finalTotal + "     (" + result + "x" + 2+")" + "+"+M);
           
           
            System.out.println("***Hexagon Arrangement***");
           
            //we need to print contents of the StringJoiner
            //this would represent all the rows above the disector
            //we know when filling the sj, we procesed outer row first and stored it in first index
            //so its ok to iterate in the same order
            for (int m=sj.length-1;m>=0;m--)
            {
            System.out.println(sj[m]);
            }
           
            //we now need to create the disector
            //we know there are no leading padding
            for (int t=0; t<M;t++)
            {
            sjDissector.add("O ");
            }
           
            System.out.println(sjDissector);
            sjDissector=new StringJoiner("");
           
            //we know that smallest row will be in first index
            //so to get the bottom section of the hexagon, need to output
            //StringJoiner in reverse order
            for (int m=0; m<sj.length; m++)
            {
            System.out.println(sj[m]);
            }
           
       
            if (finalTotal==n && n!=0)
            {
                System.out.println("A CENTRAL HEXAGON NUMBER: " + n);
                System.exit(0);
            }
        //}
        return finalTotal;
    }
}

