/*
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

import java.util.*;

public class CentredHexagonalNumber
{
    static int R;
    static StringJoiner[] sj;
    static StringJoiner[] sj1;
    static int count;
    static StringJoiner sjDissector = new StringJoiner("");
    static String paddingAtFront="";
    
    
    static boolean hasExistingKeyinMap=false;
    static int nthTerm;
    static int k;
    static long result=0;
    static int finalTotal=0;
    static boolean firstExecution=true;
    static int retrievedValueInteger;
    static boolean hasProcessedRow=false;
    static Map <Integer, Integer> mp = new HashMap<>();
    
    
    public static void main(String[] args) 
    {
        System.out.println("Welcome to Online IDE!! Happy Coding :)");
        int n=999179;
        int H=0;
        int N=1000;
        int M;
        
        System.out.println("***CENTERED HEXAGONAL NUMBER***");
        
        for (int i=1;i<N;i++)
        {
            System.out.println("***************************************************");
            
            M=(i*2)-1;
                
            nthTerm = nthTerm+1;
            hasExistingKeyinMap=false;
            hasProcessedRow=false;
            result=0;
            
            System.out.println("\nThis is the Nth term: " + (nthTerm));
            System.out.println("Middle disector (beads): " + M);
                
            R=i-1;
            System.out.println("Number rows above or below: " + R);
            
            sj = new StringJoiner[R];
            
           
            
            
            //sj1 = new StringJoiner[R];
            
         
            if (k==0)
            {
                finalTotal=1;
		System.out.println("******FINAL TOTAL: " + finalTotal);             
       
                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();
        
        if (nthTerm==47)
        {
            System.out.println("*****Code will terminate due to recursion limits*******");
            System.exit(0);
        }
        
        if (k>=1)
        {
            if (result!=0)
            {
                System.out.println("Currently processed row " + retrievedValueInteger+": " + hasProcessedRow + "   with result: " + result);
                System.out.println("Has existing key" + "("+retrievedValueInteger+","+result+")" + " in map: " + hasExistingKeyinMap);
            }
            
            if(!hasExistingKeyinMap && hasProcessedRow)
            {
                System.out.println("No key entry"+"("+ retrievedValueInteger+")" + " in hashmap. To be added " + "("+result+")");
                mp.put(retrievedValueInteger,result);
                
                hasExistingKeyinMap=true;
                hasProcessedRow=false;
            }
            
            
            System.out.println("BEADS in: " + (k) + " row above disector is: " + (M-k));
            
            //goes through each row
            
            do
            {
            
            
            //for (int count=0;count<R;count++)
            //{
                
                //clears stringjoiner and stringbuilder for the row
                sj[count]=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 the disector (should be blank): " + sjDissector.toString());
                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 on row: " + (count));
                System.out.println("value count: " + count);
                //System.out.println("value row: " + row);
                
                sj[count] = new StringJoiner("");
                
                //int location = count + row;
                
                //this will add the padding and the stringbuilder into the String and store into row
                sj[count].add(paddingAtFront+sb);
                
                //need to clear StringBuilder for next row execution or ready for the next N value
                sb=new StringBuilder();
                paddingAtFront="";
                
                count++;
                
            }while (count<R);
            
            
            result=result + (M-k);
            
            System.out.println("CURRENT RUNNING TOTAL BEADS: " + result);
            
            if (R!=1)
            {
                retrievedValueInteger=M-k;
                
                System.out.println("Checking if key " + "("+retrievedValueInteger+")" + " in HashMap");
                
                if (mp.containsKey(retrievedValueInteger))
                {
                    System.out.println("Current key: " + retrievedValueInteger + " already in HashMap. Retrieving value: " + mp.get(retrievedValueInteger));
                    
                    Object retrievedValue = mp.get(retrievedValueInteger);
                    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;
                
                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("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;
                nthTerm=nthTerm+1;
                hasExistingKeyinMap=false;
                hasProcessedRow=false;
                result=0;
                
                System.out.println("\nThis is the Nth term: " + (nthTerm));
                
                sb = new StringBuilder();
                
                //sjDissector = new StringJoiner("");
                firstExecution=true;
                R=nthTerm-1;
                sj = new StringJoiner[R];
                sj1 = new StringJoiner[R];
                count=0;
                
                 //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;
    }
}