//Finished and tested code
//It was created based on refinement from several attempts (notably obtaining positive changes in Test case 28)
//And feeding it back into earlier iteration
//All Programiz challenge test cases have passed

//ALL FORMATTED INDENTED CORRECTLY
//TERMS Matrix A and Matrix B will be used to discuss the pairing of the first and second matrix in transaction

/*
//**********USAGE*************************
BEFORE CONFIGURING TEST CASES REMEMBER THESE CRITERIA AS MINIMUM:

Numbers columms in Matrix A  = Number rows in Matrix B 
Jagged arrays supported under validation rules
//**********************************
*/

import java.util.*;

public class Solution {
    
    //current matrix
    static List<List<Integer>> matrix = new ArrayList<>();
    //next matrix
    static List<List <Integer>> nextMatrix;
    
    public static void main (String [] args)
    {
        //This holds the test cases. It is exactly same data type as given in Programiz
        List <List<List<Integer>>> testMatrix = new ArrayList<>(); 
        
        //TEST CASES
        //We have to ensure that the test case is a 3d array as oppose to a 2d array to contain all the matrixes
        
        //Integer [][][]test = new Integer[][][] {   {{1},{5}},{{9,88}}};
        
        //Only 1 matrix defined
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}}}; 
        
        //As per challenge  - Test Case 1
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{7,8},{9,10},{11,12}},  { {13,14}, {15,16} } }; 
        
        //As per challenge  - Test Case 2
        //Integer [][][]test = new Integer[][][] {   {{1,2,3,4}},{{5},{6},{7},{8}}};
        
        //As per challenge  - Test Case 3/4  (both same)
        //Integer [][][]test = new Integer[][][] {   {{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}, {{9, 10}, {11, 12}}  };
        
        //TEST CASES EXPLORING JAGGED ARRAYS (variants of TEST CASE 28 IN Document)
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{7,8},{10},{11,12}},  { {13,14}, {15,16} } };
        
        //TEST CASES EXPLORING JAGGED ARRAYS (variants of TEST CASE 28 IN Document) 
        //This relies on the matrixMultiplication initialisation
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{7,8},{10,11},{11,12}},  { {13,14,17}, {15,16} } }; 
       
        //TEST CASES EXPLORING JAGGED ARRAYS (variants of TEST CASE 28 IN Document) 
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5}},  {{7,8},{10,11},{11,12}},  { {13,14,17}, {15,16} } }; 
        
        //TEST CASES EXPLORING JAGGED ARRAYS (variants of TEST CASE 28 IN Document) 
        //Integer [][][]test = new Integer[][][] {   {{1,2},{4,5,6}},  {{7,8},{10,11},{11,12}},  { {13,14,17}, {15,16,17} } }; 
        
        //TEST CASES EXPLORING JAGGED ARRAYS (variants of TEST CASE 28 IN Document)
        //This will get picked up on area of code I had written towards bottom part of code
        //Integer [][][]test = new Integer[][][] {   {{},{4,5,6}},  {{7,8,6},{10,14},{11,12}},  { {13}, {15,16} } }; 
    
        //HERE!!!!!!!!!!!!!!!!!!!!!!!! - NEED TO CHECK THIS!!!!
        //Integer [][][]test = new Integer[][][] {   {{1,2},{3,4},{5,6}},  {{7,8},{10,14},{0}},  { {13}, {15,16} } }; 
        
        //With this test case it has not performed jump to new column (FAIL)
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{7,8},{9,10},{11,12}},  { {0}, {16,17},{5}} }; 
        
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{7,8},{9,10},{11}},  { {13,14}, {16,17} } }; 
        
        //TEST CASES EXPLORING JAGGED ARRAYS (variants of TEST CASE 28 IN Document) 
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{7,8},{9,2},{11,12}},  { {13,14}, {16,87},{3,4} } }; 
    
        //TEST CASES EXPLORING JAGGED ARRAYS (variants of TEST CASE 28 IN Document)
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{},{10,14},{11,12}},  { {13}, {15,16} } }; 
       
        //TEST CASES EXPLORING JAGGED ARRAYS (variants of TEST CASE 28 IN Document)
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{1,7},{25,14},{}},  { {13,15}, {15,16} } };
        
        //TEST CASES EXPLORING JAGGED ARRAYS (variants of TEST CASE 28 IN Document)
        //This will be handled validation in later part of code
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{}},  {{1,7},{25,14},{4,8}},  { {13,15}, {15,16} } }; 
       
        //-------------AMIT-------------------
        //TEST CASES EXPLORING JAGGED ARRAYS (variants of TEST CASE 28 IN Document
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{1,7},{25,14},{4,8}},  { {}, {15,16} } }; 
       
        //TEST CASES EXPLORING JAGGED ARRAYS (variants of TEST CASE 28 IN Document)
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{1,7},{25,14},{4,8}},  { {34,45}, {} } }; 
        
        //TEST CASES EXPLORING JAGGED ARRAYS (TEST CASE 28 IN Document exactly)
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{7,8,6},{10,14},{11,12}},  { {13,14}, {15,16} } }; 
       
        //TEST CASES EXPLORING JAGGED ARRAYS (TEST CASE 28 IN Document exactly)
        //But it is error free, so informed end user excess numbers
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6,9}},  {{7,8},{9,10},{11,12}},  { {13,14}, {15,16} } };
        
        //TEST CASES EXPLORING JAGGED ARRAYS BUT EXPLORING CHANGES IN MATRIX A (TEST CASE 28 IN Document exactly)
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4}},  {{7,8},{9,10},{11,12}},  { {13,14}, {15,16} } };
        
        //TEST CASES EXPLORING JAGGED ARRAYS BUT EXPLORING CHANGES IN MATRIX A (TEST CASE 28 IN Document exactly)
        //But it is error free, so informed end user excess numbers
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,7,2,6}},  {{7,8},{9,10},{11,12}},  { {13,14}, {15,16} } };
         
        //TEST CASES EXPLORING JAGGED ARRAYS (TEST CASE 28 IN Document exactly)
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{},{10,14},{11,12}},  { {13,14}, {15,16} } };
       
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{11,14},{},{19,12}},  { {13,14}, {15,16} } }; 
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{11,14},{44,55},{19,12}},  { {13,14}, {} } };
        
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{11,14},{44,55},{19,12}},  { {13,14}, {0} } }; 
       
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{11,14},{44,55},{19,12}},  { {13,14}, {0,5},{0} } }; 
        
        //TEST CASES EXPLORING JAGGED ARRAYS (TEST CASE 28 IN Document exactly)
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{7,8},{10,14},{11,12}},  { {13}, {15,16} } }; 
       
        //ADDITIONAL TEST CASES
        
        Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{7,8},{9,10},{11,12}},  { {13,14}, {15,16} },    { {17,18}, {19,20} },{ {17,18}, {19,20} }}; 
        
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6}},  {{7,8},{9,10},{11,12}},  { {13,14}, {15,16}},  { {17,18}, {19,20},{99,18}, {19,20}}, { {21,22,23,24}, {25,26,27,28},{29,30,31,32}} };
                                                                                            
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6},{7,8,9}},  {{10,11,12},{13,14,15},{16,17,18}},  { {19,20,21}, {22,23,24}} };

        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6},{7,8,9}},  {{10,11,12},{13,14,15},{16,17,18}} };
        
        //Integer [][][]test = new Integer[][][] {   {{},{4,5,6},{7,8,9}},  {{10,11,12},{13,14,15},{16,17,18}} };
        
        //We know the items are in test array are 3d array
        //so need to use know techniques to first get each matrix
        for (Integer [][] item: test)
        {
            //instantiates the matrix. Although this could also be outside of the for loop
            //I left it inside for more clarity
            matrix = new ArrayList<>();
            
            //processes each row in matrix    
            for (Integer [] row: item)
            {
                //it populates it into the matrix
                matrix.add(Arrays.asList(row));
            }
            //it adds entire matrix List<List<Integer>>  into    List<List<List<Integer>>> (stores collection of matrixes)
            testMatrix.add(matrix);
        }
        
        //the whole method signature satisfies that proposed in Programiz challenge
        //Method call to below
        System.out.println("\n\n***FINAL OUTCOME***: \n" + matrixMultiplication(testMatrix));
    }
    
    public static List<List<Integer>> matrixMultiplication(List<List<List<Integer>>> matrices) 
    {
        //keeps track of row of next matrix (counter+1)  relative to current matrix(counter)
        //NOTE: counter is stepping by two each time
        int rowCounterNextMatrix;
        
        //This is a multi-purpose variable
        //we know number rows in Matrix A should be equal to number columns in Matrix B
        //But during execution we might find that number columns in Matrix B exceeds that amount
        //Strictly speaking it is incorrect configuration.. But having too many elements in row in
        //Matrix B is less detrimental... seekPosition acknowledges this and assists with
        //generation of excessReport at end informing end user surplus elements in row in Matrix B
        int seekPosition=0;
        
        
        //This variable was introduced due to improvisations
        //notably because it does not skip to next column such as test case
        //Integer [][][]test = new Integer[][][] {   {{1,2,3},{4,5,6},{7,8,9}},  {{10,11,12},{13,14,15},{16,17,18}} };
        //I can not rely on the logic at bottom based on 
        //numWritesToLastIndexMultiplicationMatrix  since it is based on z which is related 
        //to column number.. So I have to use different dependency.
        //We know number writes to any index in multiplications matrix is equal to number rows in Matrix B (since we move downwards)
        //in Matrix B and across Matrix A
        int numWritesFirstIndexRowMultiplicationMatrix;
        
        StringJoiner matrixRowCalculations = new StringJoiner("");
        StringJoiner excessRowItems=new StringJoiner(",");
        
        //used in scenarios such as validation checks to show row examined in Matrix A
        String rowMatrix=null;
        
        //used as part of the validation checks to present detailed comment to end user
        //if the length row is outside expected parameters of multiplication matrix
        String currentEntry=null;
        String prevEntry=null;
        
        //These mantain reports of Matrix B so that information can be provided right at end of code execution.
        //this deals with situations in Matrix B where there might be too many row entries.
        //number rows Matrix B should be equal to number columns in Matrix A
        //it of course does not deal with less rows in Matrix B than columns in Matrix A. This would cause error.
        StringJoiner excessRowReport = new StringJoiner("\n");
        
        //These mantain reports of Matrix B so that information can be provided right at end of code execution.
        //This deals with Matrix A. It would look at situations where there are too many columns in certain rows.
        //It keeps this level of information since the matrix is still valid... But informs end user of rows with too many elements.
        //it of course does not deal with column number (Matrix A) which is less than rows Matrix B
        StringJoiner excessColReport = new StringJoiner("\n");
        
        //This is used to store the results of multiplications undertaken
        //It stores and presents entries until end of lifecycle of Matrix A x Matrix B
        StringJoiner [][] matrixMultiplicationCalculations=null;
        
        //This is used in conjunction with z variable (getting each variable on row in Matrix B) in which it reaches end of the
        //matrix multuplication array. It increments numWritesToLastIndexMultiplicationMatrix once it reached end each row.
        //We know that it there are two rows in the would have reached last index of matrixMultiplication same number of times
        //Since we know that number rows in Matrix B (effectively the size of the column) that determines the number times z has reached
        //length of (matrixMultiplication-1) due to zero indexing
        int numWritesToLastIndexMultiplicationMatrix;
        
        //This boolean will be set to true when numWritesToLastIndexMultiplicationMatrix is the same as number rows in
        //Matrix B. Since we know each element in column (whether 1 or more) governs a write to the matrixMultiplication[last index]
        boolean hasReachedEndRow=false;
        
        //Depending on its flag value, it can either be used to configure matrixMultiplication or provide summary matrix multiplied
        //it also is key flag to ensure matrixMultiplication is stored amongst other matrices.
        boolean hasStartedMultiplication=false;
        
        //This simply holds the value of multiplication undertaken between Matrix A (single element) x Matrix B (single element) 
        Integer multiplication;
        
        //zero index row counter Matrix A
        int rowCounterFirstMatrix=0;
        
        //used in several validation checks to see if rows on Matrix B (height of column) is equal Matrix A (elements in row)
        int rowsNextMatrix=0;
        
        //gets the number of rows which in effect is the seperate List<List<Integer>> which correspond seperate matrix
        int matricesSize=matrices.size();
        
        //used indexing across code. it performs steps in two to ensure Matrix A[0]x B[1], store result in Matrix C[2]..
        //and then perform Matrix C[2] x Matrix A[3]
        int counter=0;
        
        //refers to Matrix A. Number elements/size of column on Matrix B
        int numElementsInRow=0;
        
        //set to ensure the entire row has been processed from Matrix A
        boolean hasProcessed=false;
        
        //this is index in the row of Matrix A to ensure it traverses in conjunction with movement in column
        //in Matrix B
        int posPrevMatrixRowLevel=0;
        
        //simply counts number matrixes in matrices
        //it is used to display All matrix before the main code execution
        int numMatrixes=0;
        
        //core area of code.. It stores calculation for indexes from Matrix A (element in row) and 
        //Matrix B (element in column) 
        Integer [][]matrixMultiplication = null;
        
        //it has to convert the above matrixMultiplication into this format before it can be added back into
        //matrices (which is a collection of <List<Integer>>)
        List <List<Integer>> matrixMultiplicationList = new ArrayList<>();
        
        //used with Matrix A to demonstrate any discarded row elements (shorten column) in order to preserve compatability with
        //matrixMultiplication array
        String currentColumnEntry;
        
        //This keeps record of currentColumnEntry and also the discarded elements
        //presented at end of execution
        StringJoiner excessColItems=new StringJoiner(",");

        System.out.println("***ALL MATRIX*******: " + matrices.size());
        
        //Gets all rows for each matrix in matrices
        do
        {
            matrix=matrices.get(numMatrixes);
            
            System.out.println("\nMatrix" +"("+numMatrixes+"):");

            for (List<Integer> row: matrix)
            {
                System.out.println(row);
            }
            numMatrixes++;
            
        }while(numMatrixes<matrices.size());
        
        System.out.println("\n\n\n");
        numMatrixes=0;
        
        do
        {
            //ensures it ready to configure the matrixMultiplication
            hasProcessed=false;
            
            //loads matrix into List<List<Integer>>
            matrix=matrices.get(counter);
           
            //We would only provide summary of Matrix A x Matrix B
            //if counter is greater than 0 and has configured size
            //matrixMultiplication and se hasStartedMultiplication to true
            
            if (counter>0 && hasStartedMultiplication)
            {
                System.out.println("\n***SUMMARY****");
                System.out.println("Matrix multiplication: " + "Matrix ("+(counter-2)+") x Matrix ("+(counter-1)+")");
                
                //we know it has started multiplication so there is two or matrix entries
                //we also need to be careful and not add matrix C.
                //However in reality this if statement can be removed since even if there were two matrixes
                //counter would perform step by 2 and exceed matricesSize
                //I implemented this in early part of my coding to keep conditions stringent
                if (matrices.size()!=2)
                {
                    System.out.println("ADDED Multiplication Matrix into the chain at index: " + (counter));
                    matrices.add(counter,matrixMultiplicationList);
                    hasStartedMultiplication=false;
                    System.out.println("Matrix("+counter+")");
                    
                    //prints out multiplication matrix
                    for (Integer []m: matrixMultiplication)
                    {
                        System.out.println(Arrays.toString(m));
                        
                        matrixMultiplicationList.add(Arrays.asList(m));
                    }
                    
                    //All steps are stored in matrixMultiplicationCalculations
                    //we simply add results from row in array into StringJoiner
                    //This ensures end user sees the calculations in expected format such as
                    //***CALCULATION STEPS*******
                    //[(1x7 =7)+(2x9 =18)+(3x11 =33)] [(1x8 =8)+(2x10 =20)+(3x12 =36)]
                    //[(4x7 =28)+(5x9 =45)+(6x11 =66)] [(4x8 =32)+(5x10 =50)+(6x12 =72)]
                    
                    System.out.println("\n***CALCULATION STEPS*******");
                    
                    for (int q=0; q<matrixMultiplicationCalculations.length; q++)
                    {
                        matrixRowCalculations = new StringJoiner("");
                
                        for (int r=0; r<matrixMultiplicationCalculations[0].length; r++)
                        {
                            matrixRowCalculations.add(" ["+matrixMultiplicationCalculations[q][r]+"]");
                        }
                        System.out.println(matrixRowCalculations);
                    }
                    
                    //counter is equivalent to Matrix C
                    //It then references the next Matrix (taken to be Matrix A again for ease reference)
                    System.out.println("\nIt will perform: " + "Matrix("+counter+")   x  Matrix("+(counter+1)+")");
                    
                    //it presents Matrix A onto the screen
                    for (List<Integer> w: matrices.get((counter+1)))
                    {
                        System.out.println("\t\t\t\t"+String.valueOf(w));
                    }
                    
                    //crucial to update the size of matrices given addition of another
                    matricesSize=matrices.size();
                    //we now load Matrix C into matrix List 
                    matrix=matrices.get(counter);
                }
            } //end if statement
            System.out.println("\n\n------Matrix" +"("+counter+"):");
            
            //we perform this again since this is effectively main starting point in the loop
            //i.e getting matrix(0),  matrix(3)
            matrix=matrices.get(counter);
            
            //prints matrix onto screen
            for (List<Integer> row: matrix)
            {
                System.out.println(row);
            }
            
            //Create a new object reference since each is unique to formation
            //matrix C
            matrixMultiplicationList = new ArrayList<>();
            
            //if there is not a next matrix, there is only 1 matrix in matrices.
            //it will not be applicable in any other scenarios due to counter step 2
            //increments prior to do while termination
            try
            {
                nextMatrix=matrices.get(counter+1);
            }
            catch (IndexOutOfBoundsException e)
            {
                System.out.println("Single matrix only");
                matrix=matrices.get(counter);
                System.out.println("\n***CALCULATION STEPS*******");
            
                for (List<Integer> row: matrix)
                {
                    System.out.println(row);
                }
                System.exit(0);
            }
            
            System.out.println("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
            
            //The StringJoiner dimensions is exact replica of the matrixMultiplication
            //difference is the indexes in matrixMultiplication solely keeps running total
            matrixMultiplicationCalculations=new StringJoiner[nextMatrix.get(0).size()][matrix.size()];
            
            //Informs end user of the dimensions for storage multiplication matrix
            System.out.println("Size of Matrix multiplication rows: " + nextMatrix.get(0).size());
            System.out.println("Size of Matrix multiplication columns: " + matrix.size());
            
            System.out.println("*******Customising Storage Grid for Multiplication Matrix**********["+nextMatrix.get(0).size()+"]["+matrix.size()+"]***************");
            
            //it sets a StringJoiner with "+" to ensure each time entry added to the index, it can format outputs
            //corretly 
            for (int q=0; q<nextMatrix.get(0).size(); q++)
            {
                for (int r=0; r<matrix.size(); r++)
                {
                    System.out.println("Configuring for index: " + q + "," + r);
                    matrixMultiplicationCalculations[q][r] = new StringJoiner("+");
                }
            }
            
            //It processes the row in matrix.. The main code is now starting
            //This can be taken to be either Matrix A or Matrix C
            for (List<Integer> ee: matrix)
            {
                //catpures row to be used during validation messages
                //I have refrained from using this variable elsewhere in order to preserve
                //usage of ee for Collection
                //I had to keep this value since ee is not in scope during validation phases
                rowMatrix = String.valueOf(ee);
                
                //Displays data for the row
                System.out.println("THIS IS ROW COUNTER MATRIX("+counter+"): " + rowCounterFirstMatrix);
                System.out.println("------------------------------------------THIS IS ROW DATA MATRIX("+counter+"): " + ee);
                
                //adjusting to default values
                hasProcessed=false;
                numWritesToLastIndexMultiplicationMatrix=0;
                hasReachedEndRow=false;
                
                for (int k=0; k<ee.size(); k++)
                {
                    if(counter!=matricesSize-1)
                    {
                        if (nextMatrix.get(0).size()==1)
                        {
                            hasProcessed=false;
                        }
                        
                        if (!hasProcessed)
                        {
                            rowCounterNextMatrix=0;
            
                            if (!hasStartedMultiplication)
                            {
                                System.out.println("****************************CONFIGURING SIZE FOR BLANK MULTIPLICATION MATRIX*******************************************");
                                matrixMultiplication = new Integer[nextMatrix.get(0).size()][matrix.size()];
                                
                                System.out.println("Matrix (W=" + matrix.size()+")  x  (H=" + nextMatrix.get(0).size()+")" 
                                + " configured to store Matrix " + counter + " x  Matrix " + (counter+1));
                               
                                try
                                {
                                    for (int a = 0; a < matrix.size(); a++) 
                                    {
                                        for (int b = 0; b < nextMatrix.get(0).size(); b++) 
                                        {
                                            matrixMultiplication[a][b] = 0;
                                        }
                                    }
                                }
                                catch (ArrayIndexOutOfBoundsException e)
                                {
                                    System.out.println("\n3The current dimension of matrixMultiplication: " 
                                    + "["+nextMatrix.get(0).size()+"]"+"["+matrix.size()+"]");
                                }

                                hasStartedMultiplication=true;
                            }
                            
                            List<Integer> rowInfo = new ArrayList<>();
                            
                            if (nextMatrix.get(0).size()==0)
                            {
                                System.out.println("8The current dimension of matrixMultiplication: " 
                                + "["+nextMatrix.get(0).size()+"]"+"["+matrix.size()+"]");
                                System.out.println("It EXPECTS: " + matrix.size() + " elements per row");
                                System.out.println("matrix" + "("+(counter+1)+")" + " row:" + rowCounterNextMatrix +  " " 
                                + nextMatrix.get(0) + " size: " + nextMatrix.get(0).size() + " invalidates this");
                                System.out.println(matrices);
                                System.exit(0);
                            }
             
                            for (int z=0; z<nextMatrix.get(0).size(); z++)
                            {
                                System.out.println("\n*****************Column number: " + z);
                                
                                posPrevMatrixRowLevel=0;
                                numWritesFirstIndexRowMultiplicationMatrix=0;
                                
                                for (int y=0; y<nextMatrix.size();y++)
                                {
                                    if (y<nextMatrix.get(0).size())
                                    {
                                         
                                        for (int m=0; m<nextMatrix.size(); m++)
                                        {
                                            for (int j=0;j<=nextMatrix.get(m).size();j++)
                                            {    
                                                if (m==0)
                                                {
                                                    rowCounterNextMatrix=0;
                                                }
                                                if (numWritesFirstIndexRowMultiplicationMatrix==nextMatrix.size())
                                                {
                                                  break;
                                                }
                                                else
                                                {
                                                    System.out.println("retrieving row: " + rowCounterNextMatrix 
                                                    + " from matrix (" + (counter+1)+")");    
                                                }
                                                rowInfo=new ArrayList<>(nextMatrix.get(m));
                    
                                                if (!hasReachedEndRow)
                                                {
                                                    seekPosition=0;
                                                    excessRowItems = new StringJoiner(",");
                    
                                                    if (rowInfo.size()!=matrixMultiplication[0].length)
                                                    {
                                                        currentEntry = "Row length:" + rowInfo.size()+" (matrix" + "("+(counter+1)+") row:" 
                                                        +rowCounterNextMatrix+ "   " + nextMatrix.get(m)+") "  
                                                        + " inconsistent with length expectations" 
                                                        + "("+matrixMultiplication[0].length+") in multiplcation matrix";
                        
                                                        if (!currentEntry.equals(prevEntry))
                                                        {
                                                            System.out.println(currentEntry);
                                                            excessRowReport.add(currentEntry);
                                                
                                                            for (int x: nextMatrix.get(m))
                                                            {
                                                                seekPosition++;
                            
                                                                if (seekPosition>matrixMultiplication[0].length)
                                                                {
                                                                    excessRowItems.add(String.valueOf(x));
                                
                                                                }
                                                            }
                                                        }
                                                    }
                                                    prevEntry = currentEntry;
                    
                                                    if (seekPosition!=0)
                                                    {
                                                        System.out.println("["+excessRowItems+"] are exempt from multiplcation matrix");
                                                        excessRowReport.add("["+excessRowItems+"] are exempt from multiplcation matrix");
                                                        
                                                        if(excessRowItems.toString().length()==0)
                                                        {
                                                            System.out.println("99The current dimension of matrixMultiplication: " 
                                                            + "["+nextMatrix.get(0).size()+"]"+"["+matrix.size()+"]");
                                                            System.out.println("It EXPECTS: " + matrix.size() + " elements per row");
                                                
                                                            System.out.println("matrix" + "("+(counter+1)+")" + " row:" + rowCounterNextMatrix 
                                                            +  " " + "(content:"+nextMatrix.get(m) +")" + " size:" + nextMatrix.get(m).size() 
                                                            + " invalidates this");
                                                            System.out.println(matrices);
                                                            System.exit(0);
                                                        }
                                                    }
                                        
                                                    rowCounterNextMatrix++;
                                                    
                                                    try
                                                    {
                                                        System.out.println("Matrix["+(counter+1)+"] \trow element["+z+"]: " + rowInfo.get(z) +"\t\t" + nextMatrix.get(m));
                                                    }
                                                    catch (IndexOutOfBoundsException e)
                                                    {
                                                        System.out.println("\n24The current dimension of matrixMultiplication: " 
                                                        + "["+nextMatrix.get(0).size()+"]"+"["+matrix.size()+"]");
                                                        System.out.println("It EXPECTS: " + matrix.size() + " elements per row");
                                                        System.out.println("matrix" + "("+(counter+1)+")" + " row:" + rowCounterNextMatrix 
                                                        +  " " + nextMatrix.get(m) + " size: " + nextMatrix.get(m).size() + " invalidates this");
                                                        System.out.println(matrices);
                                                        System.exit(0);
                                                    }
                                        
                                                    try
                                                    {
                                                        System.out.println("Matrix["+counter+"] \trow element["+posPrevMatrixRowLevel+"]: " +ee.get(posPrevMatrixRowLevel) +"\t\t" + ee);
                                                    }
                                                    catch (ArrayIndexOutOfBoundsException e)
                                                    {
                                                        System.out.println("\n1The current dimension of matrixMultiplication: " 
                                                        + "["+matrixMultiplication.length+"]"+"["+matrixMultiplication[0].length+"]");
                                                            
                                                        if (rowInfo.size()>matrixMultiplication.length)
                                                        {
                                                            System.out.println("1Accessing matrix(" + counter+") row index: " 
                                                            + rowCounterNextMatrix + " from " + nextMatrix.get(m) + " invalidates this");
                                                            System.out.println("Remove " + nextMatrix.get(m) + " and rows beyond from matrix(" 
                                                            + (counter+1)+") row index: " + m);
                                                        }
                                
                                                        if (ee.size()<rowCounterNextMatrix)
                                                        {
                                                            System.out.println("2Accessing matrix(" + counter+") row index: " 
                                                            + rowCounterNextMatrix + " from " + ee + " invalidates this");
                                                            System.out.println("Remove " + nextMatrix.get(m) 
                                                            + " and rows beyond from matrix(" + (counter+1)+") row index: " + m);
                                                            System.out.println(matrices);
                                                            System.exit(0);
                                                        }
                                
                                                        if(ee.size()>matrixMultiplication.length)
                                                        {
                                                            System.out.println("It EXPECTS: " + matrix.size() + " elements per row");
                                                            System.out.println("matrix" + "("+(counter)+")" + " row:" + rowCounterFirstMatrix 
                                                            +  " " + matrix.get(rowCounterFirstMatrix) + " size: " 
                                                            + matrix.get(rowCounterFirstMatrix).size() + " invalidates this");
                                                        }
                                
                                                        if(nextMatrix.get(m).size()>matrixMultiplication[0].length)
                                                        {
                                                            System.out.println("It EXPECTS: " + matrix.size() + " elements per row");
                                                            System.out.println("matrix" + "("+(counter+1)+")" 
                                                            + " row:" + rowCounterNextMatrix +  " " + nextMatrix.get(m) + " size: " 
                                                            + nextMatrix.get(m).size() + " invalidates this");
                                                        }
                                                        
                                                        System.out.println(matrices);
                                                        System.exit(0);
                                                    }
                            
                                                    multiplication =  ee.get(posPrevMatrixRowLevel) *rowInfo.get(z);
                            
                                                    System.out.println(ee.get(posPrevMatrixRowLevel) + " X " + rowInfo.get(z) + "= " + multiplication);
                                                    
                                                    try
                                                    {
                                                        matrixMultiplication[rowCounterFirstMatrix][z] = matrixMultiplication[rowCounterFirstMatrix][z]  
                                                        + multiplication;
                                                    }
                                                    catch (ArrayIndexOutOfBoundsException e)
                                                    {
                                                        System.out.println("\n2The current dimension of matrixMultiplication: " 
                                                        + "["+nextMatrix.get(0).size()+"]"+"["+matrix.size()+"]");
                                                        System.out.println("It EXPECTS: " + matrix.size() + " elements per row");
                                                        System.out.println("matrix" + "("+(counter+1)+")" + " row:" + rowCounterNextMatrix +  " " 
                                                        + nextMatrix.get(m) + " size: " + nextMatrix.get(m).size() + " invalidates this");
                                                        System.out.println(matrices);
                                                        System.exit(0);
                                                    }
                                                    System.out.println("Value in multiplication matrix: " 
                                                    + matrixMultiplication[rowCounterFirstMatrix][z] + "\t\t" 
                                                    + "["+rowCounterFirstMatrix+"],["+z+"]" );
                                                    
                                                    numWritesFirstIndexRowMultiplicationMatrix++;
                            
                                                    
                                                    matrixMultiplicationCalculations[rowCounterFirstMatrix][z].add("(" + ee.get(posPrevMatrixRowLevel) 
                                                    + "x" +rowInfo.get(z) +" ="+String.valueOf(multiplication)+")");
                                        
                                                    System.out.println(matrixMultiplicationCalculations[rowCounterFirstMatrix][z]+"\n");
                            
                                                    if (z==(matrixMultiplication.length-1))
                                                    {
                                                        numWritesToLastIndexMultiplicationMatrix++;
                                                        
                                                        if (numWritesToLastIndexMultiplicationMatrix==nextMatrix.size())
                                                        {
                                                            hasReachedEndRow=true;
                                                        }
                                                    }
                                                    posPrevMatrixRowLevel++;
                                                    
                                                    break;
                                                }
                                                else
                                                {
                                                    System.out.println("---------------------------------------------------");
                                                    System.out.println("previous written to each index location of multiplication matrix: " 
                                                    + nextMatrix.size() + "  MAXIMUM times");
                                                    System.out.println("---------------------------------------------------");
                                                }
                                            }
                                        }
                                    }     
                                }
                            }
                            hasProcessed=true;
                        }
                        System.out.println("Processed matrix("+(counter+1)+")  column("+k+")"+  " AGAINST " + "MATRIX("+counter+")  row("+rowCounterFirstMatrix+"): " + ee);
                    }
                                   
                    numElementsInRow++;
                }
            
                if(counter!=(matricesSize-1))
                {
                    for (List<Integer> rows: matrices.get((counter+1)))
                    {
                        rowsNextMatrix++;
                    }
                    
                    //I have to make this slightly more strict
                    //Since we know if elements in row in Matrix A (row 2) is greater than matrix A (row 1)
                    //we can strictly contine with calculations similar to if in Matrix B (row 2) is greater length (row 1)
                    //But we would need to capture all information in a similar way
                    //And put information into excessColumnReport instead
                    // As long as these are fulfilled Numbers columms in Matrix A (taken from .get(0)  = Number rows in Matrix B (.size())
                    //we expect those to be accepted values in matrixMultiplication
                    
                    //I have also included numElementsInRow==0 as invalid configuration.
                    
                    if ((numElementsInRow!=rowsNextMatrix && numElementsInRow<matrix.get(counter).size()) || numElementsInRow==0)
                    {
                        System.out.println("INVALID VERIFICATION=>  columns " + "("+numElementsInRow+") in Matrix"  + "("+counter+")" 
                        + "(Row:" +rowCounterFirstMatrix + " content: " +  rowMatrix +  ") should match " 
                        +  rowsNextMatrix + " rows in matrix("+(counter+1)+")");
                        System.out.println(matrices);
                        System.exit(0);
                    }
                    else
                    {
                        System.out.println("VERIFICATION SUCCESSFUL(MATRIX("+counter+")  row("+rowCounterFirstMatrix+")) =>  ***COLUMNS" + "("+numElementsInRow+")\t   Matrix("+(counter+1)+") =>  ***ROWS("+rowsNextMatrix+")");
                        
                        excessColItems = new StringJoiner(",");
                        //we are using this since there are more columns than reference expected
                        //we could also use matrix.get(0) since this determines the properties for matrix multiplcation
                        //but we are not relying on prevEntry since I expect no duplications since these are issues with
                        //Matrix A as oppose to Matrix B
                        
                        if (numElementsInRow>matrixMultiplication[0].length)
                        {
                            currentColumnEntry = "Row length:" + matrix.get(rowCounterFirstMatrix).size()+" (matrix" + "("+(counter)+") row:"
                                                +rowCounterFirstMatrix+ "   " + matrix.get(rowCounterFirstMatrix)+") "  
                                                + " inconsistent with length expectations" 
                                                + "("+matrixMultiplication[0].length+") in multiplcation matrix"; 
                            
                            System.out.println(currentColumnEntry);
                                                        
                            for (int x: matrix.get(rowCounterFirstMatrix))
                            {
                                seekPosition++;
                                            
                                if (seekPosition>matrixMultiplication[0].length)
                                {
                                    excessColItems.add(String.valueOf(x));
                                }
                            }
                            
                            if (seekPosition!=0)
                            {
                                System.out.println("["+excessColItems+"] are exempt from multiplcation matrix");
                                
                                excessColReport.add(currentColumnEntry);
                                excessColReport.add("["+excessColItems+"] are exempt from multiplcation matrix"+"\n");
                            }
                            seekPosition=0;
                        }
                    }
                    rowsNextMatrix=0;
                }
                numElementsInRow=0;
                rowCounterFirstMatrix++;
            }
            rowCounterFirstMatrix=0;
                    
            counter=counter+2;
            rowsNextMatrix=0;
            //numMatrixes++;
        
        }while (counter<matricesSize);

        for (Integer []m: matrixMultiplication)
        {
            System.out.println(Arrays.toString(m));
        }
        
        System.out.println("\n***CALCULATION STEPS*******");
    
        for (int q=0; q<matrixMultiplicationCalculations.length; q++)
        {
            matrixRowCalculations = new StringJoiner("");
                
            for (int r=0; r<matrixMultiplicationCalculations[0].length; r++)
            {
                matrixRowCalculations.add(" ["+matrixMultiplicationCalculations[q][r]+"]");
                    
            }
            System.out.println(matrixRowCalculations);
        }
        
        for (Integer []m: matrixMultiplication)
        {
            matrixMultiplicationList.add(Arrays.asList(m));
        }
        
        System.out.println("\n-----MATRIX A   Analysis------");
        System.out.println(excessColReport);
        
        System.out.println("\n\n-----MATRIX B   Analysis------");
        System.out.println(excessRowReport);
        
        return matrixMultiplicationList;
    }
}