import java.util.*;
public class Solution 
{
    public static void main (String[] args)
    {
        List<List<Object>> intervals = new ArrayList<>();
            
        List<Object> entries = new ArrayList<>();
        
            
        //TEST CASE 1 - No issues     PASS
        //entries.add("[1, 3]");
            
        //TEST CASE 2 - No issues     PASS
        //entries.add("[1, 3]");
        //entries.add("[4, 7]");
            
        //TEST CASE 3 - No issues     PASS
        //entries.add("[1, 3]");
        //entries.add("[2, 7]");
            
        //TEST CASE 4 - No issues     PASS
        //entries.add("[1, 3]");
        //entries.add("[4, 7]");
        //entries.add("[8, 9]");
            
        //TEST CASE 5 - No issues     PASS
        //entries.add("[1, 3]");
        //entries.add("[2, 7]");
        //entries.add("[8, 9]");
            
        // I CAN SEE, AS THE OBJECTS HIT 4, SIMILAR TO MY OTHER CODE, THE RESULTS WERE SKEWED....
            
        //TEST CASE 6 - No issues     PASS
        //entries.add("[1, 3]");
        //entries.add("[4, 7]");
        //entries.add("[8, 10]");
        //entries.add("[11, 25]");
            
        
        //TEST CASE 7 - No issues     PASS
        //entries.add("[1, 3]");
        //entries.add("[4, 7]");
        //entries.add("[8, 10]");
        //entries.add("[11, 25]");
        //entries.add("[27, 33]");
        //entries.add("[35, 38]");
        //entries.add("[42, 47]");
        
            
        //TEST CASE 8 -                 PASS
        //entries.add("[1, 3]");
        //entries.add("[2, 7]");
        //entries.add("[6, 10]");
        
        //TEST CASE 9 -                 PASS
        //entries.add("[1, 3]");
        //entries.add("[2, 7]");
        //entries.add("[6, 10]");
        //entries.add("[9, 25]");
        //entries.add("[24, 33]");
        //entries.add("[30, 38]");
        //entries.add("[34, 44]");
        
        //TEST CASE 10                  PASS 
        //entries.add("[1, 3]");
        //entries.add("[4, 7]");
        //entries.add("[6, 9]");
        //entries.add("[8, 25]");
        
        //TEST CASE 11                PASS
        //entries.add("[1, 3]");
        //entries.add("[2, 7]");
        //entries.add("[8, 9]");
        //entries.add("[19, 45]");
        //entries.add("[40, 52]");
        //entries.add("[58, 61]");
        
        //TEST CASE 12 - Invalid data   (same interval first two objects) - - seems satisfactory output
        //entries.add("[1, 3]");
        //entries.add("[3, 9]");
        //entries.add("[8, 9]");
            
        //TEST CASE 13 - Invalid data   (same interval first two objects) - seems satisfactory output
        //entries.add("[1, 3]");
        //entries.add("[3, 9]");
        //entries.add("[8, 12]");
        //entries.add("[12, 15]");
        
        //TEST CASE 14 - Invalid data  - seems semantically correct
        //entries.add("[1, 3]");
        //entries.add("[4, 9]");
        //entries.add("[8, 2]");
        //entries.add("[9, 2]");
        
        //TEST CASE 15 - undocumented  (same ranges) - seems satisfactory output
        //entries.add("[1, 3]");
        //entries.add("[1, 3]");
        
        //I am now using my improved code to try more strategic scenarios
        //I am aiming to push my code to reach these notations
        //M=merged (it would be due to  [2,2],  [2,2])
        //]  = no merge (just stored)
        //A = ascending merge   [5,9],  [6,12]  or   [5,9],[9,9] or  [5,9],[8,9]
        //D = descending merge  [9,5], [4,3]    or    [9,5],[5,4] or  [9,5],[4,5]   
        
        //TEST CASE 16 => using a repeat entry   
        //this keeps both entries intact, not performed a merge
        //entries.add("[2, 2]");
        //entries.add("[2, 2]");
        
        //TEST CASE 17 => using ascending
        //entries.add("[2, 2]");
        //entries.add("[2, 7]");
        
        //TEST CASE 17 => using ascending
        //entries.add("[2, 2]");
        //entries.add("[2, 7]");
        //entries.add("[7, 3]");
        
          //TEST CASE 17 => using ascending
        //entries.add("[2, 2]");
        //entries.add("[2, 7]");
        //entries.add("[7, 3]");
        //entries.add("[3, 3]");
        
         //TEST CASE 18 => using ascending
        //entries.add("[2, 2]");
        //entries.add("[2, 7]");
        //entries.add("[7, 3]");
        //entries.add("[3, 3]");
        //entries.add("[2, 9]");
        
             //TEST CASE 18 => using ascending
        entries.add("[2, 2]");
        entries.add("[2, 1]");
        
        
        //TEST CASE 17 => using a non-descending scenario - I will add no notations at the end....
        //entries.add("[8, 5]");
        //entries.add("[7, 3]"); 
        
        //TEST CASE 18 => using a ascending scenario - I will add reference into the item
        //not sure if it will always be ascending passing through this area....
        //entries.add("[3, 7]");
        //entries.add("[5, 8]");  //asc
        
        //TEST CASE 19 => using ascending and descending
        //entries.add("[3, 7]");  
        //entries.add("[5, 8]");  //ascending
        //entries.add("[6, 4]");  //descending
        
        //TEST CASE 20 => using ascending and descending but matching intervals (FAIL)
        //entries.add("[3, 7]");  
        //entries.add("[5, 5]");  
        //entries.add("[4, 3]");  
        
        
        //TEST CASE 21 => using ascending and descending
        //entries.add("[6, 5]");  
        //entries.add("[5, 8]");  //ascending
        //entries.add("[6, 4]");  //no merge
        
        //TEST CASE 22 => using ascending and descending
        //entries.add("[6, 5]");  
        //entries.add("[5, 4]");  //desc
        //entries.add("[3, 2]");  //desc
        //entries.add("[1, 1]");  //desc
        
        
         //TEST CASE 23 => using ascending and descending
        //entries.add("[6, 5]");  
        //entries.add("[4, 5]");  //desc
        //entries.add("[3, 2]");  //desc
        //entries.add("[1, 5]");  //no merge
        
            
        intervals.add(entries);
            
        System.out.println("Final outer list: " + mergeIntervals(intervals));
    }
    
    public static List<List<Object>> mergeIntervals(List<List<Object>> intervals) 
    {
        String startInterval="";
        
        List<List<Object>> outerList = new ArrayList<>();

        List<Object> innerList = new ArrayList<>();  

        int counter=0;
        
        String mergeDirection="";
        
        String newInterval="";
        
        int numberObjects=0;
        String range;
                
        String startIntervalFirstRange="";
        String endIntervalFirstRange="";
        
        String startIntervalSecondRange="";
        String endIntervalSecondRange="";
        
        String endInterval="";
        
        Iterator<List<Object>> it = intervals.iterator();

        for (List <Object> tt: intervals)
        {  
              for (Object s:tt)
            {
                numberObjects++;
            }
            
            for (Object s:tt)
            {
                counter++;
                System.out.println("\nTHIS IS OBJECT: " + s +  " Counter: " + counter);
                    
                range = String.valueOf(s);
                
                if (numberObjects==1)
                {
                    startIntervalFirstRange = range.substring(1, range.indexOf(","));
                    
                    endIntervalFirstRange = range.substring(range.indexOf(" ")+1,range.indexOf("]"));
                    
                    newInterval = "["+startIntervalFirstRange+","+ " " + endIntervalFirstRange+"]";
                    innerList.add(newInterval);
                    System.out.println("1Added into innerlist: " + innerList);
                }
                
                if (counter>2)
                {   
                    String endNewInterval = newInterval.substring(newInterval.indexOf(" ")+1, newInterval.indexOf("]"));
                    
                    startIntervalFirstRange = range.substring(1, range.indexOf(","));
                    System.out.println("start interval first range:" + startIntervalFirstRange);
                    
                    endIntervalFirstRange = range.substring(range.indexOf(" ")+1,range.indexOf("]"));
                    
                    System.out.println("2end interval first range:" + endIntervalFirstRange);
                   
                    System.out.println("2end new Interval :" + endNewInterval);
                    
                                //[4,9],    [8,2]              8>9
                    //I believe the whole if/else can be collapsed into a single if
                      //This area of code requires a big overhaul
                      //we are in this section because the counter >2
                        //here we are concerned with exact reasons for removing an entry
                        //from the list and also adding the merged one... (this can be perspective of going descending or ascending)
                        //OR if it satisfies neither conditions, it would add the range and state it as NOT MERGED
                        
                        //if last item in innerlist is  [4,9] and new object is [8,2], we know straight away
                        //that it would need to be added into the List based on no merge...
                        //but unfortunately it can only be concluded via a process of elimination...
                        //ie ascertaining if the merge overlap is due to ascending or descending first......
                        
                        //But if we focus on the positions of the digits  
                        //[startIntervalSecondRange = 4,  endIntervalSecondRange=9]
                        //[startIntervalFirstRange =8,  endIntervalFirstRange=2]
                        
                        //we know that there is already overlap hence in this loop
                        //also need to remember that startInterval refers to last item in the innerlist
                        //SO USE THIS WITH PRECEDENCE IN ORDER TO AVOID ISSUES since this value is also duplicated with start interval second range
                        
                     //this ascertains an overlap           
                    if (Integer.valueOf(startIntervalFirstRange)<=Integer.valueOf(endNewInterval))
                    {
                        //    2>=4                       &&    9>4
                        //if (endIntervalFirstRange>=startInterval  && endIntervalSecondRange>=startInterval)
                        //{
                            Object lastItemInnerList = innerList.get(innerList.size()-1);
                            System.out.println("Last item inner list: " + lastItemInnerList);
                        
                        startInterval = String.valueOf(lastItemInnerList).substring(1,String.valueOf(lastItemInnerList).indexOf(","));
                        endInterval = String.valueOf(lastItemInnerList).substring(String.valueOf(lastItemInnerList).indexOf(" ")+1,String.valueOf(lastItemInnerList).indexOf("]"));
                        
                        System.out.println("start interval: " + startInterval);
                        System.out.println("end interval: " + endInterval);
                        System.out.println("start interval second range: " + startIntervalSecondRange);
                        System.out.println("end interval second range: " + endIntervalSecondRange);
                       
                        System.out.println("start interval first range: " + startIntervalFirstRange);
                        System.out.println("end interval first range: " + endIntervalFirstRange);
                        
                        if (startInterval=="" || endIntervalSecondRange=="")
                        {
                            startInterval=startIntervalFirstRange;
                            endInterval=endIntervalFirstRange;
                            
                        //     System.out.println("populated start interval second range: " + startIntervalSecondRange);
                        //System.out.println("populated end interval second range: " + endIntervalSecondRange);
                        }
                        
               System.out.println("NEW LOGIC1***************************************************************************************");  
               
                        //This classifies as a removal from ascending perspective     or descending perspective
                          //8                                         
    if ((Integer.valueOf(endIntervalFirstRange)>=Integer.valueOf(endInterval)  && Integer.valueOf(endIntervalFirstRange)>=Integer.valueOf(startInterval))  
    ||  (Integer.valueOf(endIntervalFirstRange)<=Integer.valueOf(endInterval)  && Integer.valueOf(endIntervalFirstRange)<=Integer.valueOf(startInterval)))
                        {
                            
                            mergeDirection="";
                                                      //2                                        7                            
                            if (Integer.valueOf(endIntervalFirstRange)>Integer.valueOf(endIntervalSecondRange)  && (endIntervalFirstRange!=startIntervalFirstRange))
                            {
                                mergeDirection="A";
                            }
                            
                            if (Integer.valueOf(endIntervalFirstRange)<Integer.valueOf(endIntervalSecondRange)&& (endIntervalFirstRange!=startIntervalFirstRange))
                            {
                                mergeDirection="D";
                            }
                            
                            
                            
                        System.out.println("1Removed last item from innerList: " + innerList.get(innerList.size()-1));
                        
                        innerList.remove(innerList.size()-1);
                        
                        newInterval = "["+startInterval+","+ " " + endIntervalFirstRange+"]"+mergeDirection;
                        innerList.add(newInterval);
                        System.out.println("3Added into Inner List: " + newInterval);
                        System.out.println("This is innerlist: " + innerList);
                        
                        }
                        
                        //}
                        //it would simply have no merging even though the ranges overlap
                        else
                        {
                        newInterval = "["+startIntervalFirstRange+","+ " " + endIntervalFirstRange+"]";
                        innerList.add(newInterval);
                        System.out.println("2Added into Inner List: " + newInterval);
                        }
                    }
                    else
                    {
                        //need to add object here, it is here simply because there is no overlap whatsoever.... 
                        newInterval = "["+startIntervalFirstRange+","+ " " + endIntervalFirstRange+"]";
                        innerList.add(newInterval);
                        System.out.println("11Added into Inner List: " + newInterval);
                    }
                }
                if (counter<=2)
                {
                    if (counter==1)
                    {
                        startIntervalFirstRange = range.substring(1, range.indexOf(","));
                        
                        endIntervalFirstRange = range.substring(range.indexOf(" ")+1,range.indexOf("]"));
                        
                    }
                
                    if (counter==2)
                    {
                        startIntervalSecondRange = range.substring(1, range.indexOf(","));
                        
                        endIntervalSecondRange = range.substring(range.indexOf(" ")+1,range.indexOf("]"));
                        
                        if (Integer.valueOf(endIntervalFirstRange)>Integer.valueOf(startIntervalSecondRange))
                        {
                            //***REPEAT CODE***  required to ascertain direction.....
                            
                            //**REPEAT CODE //***********
                         //These are permitted
                         //A = ascending merge   [5,9],  [6,12]  or   [5,9],[9,9] or  [5,9],[8,9]
                         //need to check if endIntervalSecondRange>=endIntervalFirstRange  && endIntervalSecondRange>=startIntervalFirstRange
                         
                        //D = descending merge  [9,5], [4,3]    or    [9,5],[5,4] or  [9,5],[4,5]
                        //need to check if endIntervalSecondRange<=endIntervalFirstRange  && endIntervalSecondRange<=startIntervalFirstRange
                        
                        //[8,5], [7,3]
            System.out.println("NEW LOGIC2***************************************************************************************"); 
            System.out.println("start interval: " + startInterval);
            System.out.println("end interval: " + endInterval);
            System.out.println("start interval second range: " + startIntervalSecondRange);
            System.out.println("end interval second range: " + endIntervalSecondRange);
            System.out.println("start interval first range: " + startIntervalFirstRange);
            System.out.println("end interval first range: " + endIntervalFirstRange);
            
                        //This classifies as a removal from ascending perspective     or descending perspective
    if ((Integer.valueOf(endIntervalSecondRange)>=Integer.valueOf(endIntervalFirstRange)  && Integer.valueOf(endIntervalSecondRange)>=Integer.valueOf(startIntervalFirstRange))  
    ||  (Integer.valueOf(endIntervalSecondRange)<=Integer.valueOf(endIntervalFirstRange)  && Integer.valueOf(endIntervalSecondRange)<=Integer.valueOf(startIntervalFirstRange)))
                        {
                            mergeDirection="";
                            
                            if (Integer.valueOf(endIntervalFirstRange)>Integer.valueOf(endIntervalSecondRange)  && (endIntervalFirstRange!=startIntervalFirstRange))
                            {
                                mergeDirection="A";
                            }
                            
                            if (Integer.valueOf(endIntervalFirstRange)<Integer.valueOf(endIntervalSecondRange)&& (endIntervalFirstRange!=startIntervalFirstRange))
                            {
                                mergeDirection="D";
                            }
                            
                            
                            
                        if (innerList.size()>0)
                        {
                        System.out.println("2Removed last item from innerList: " + innerList.get(innerList.size()-1));
                        
                        innerList.remove(innerList.size()-1);
                        }
                        
                        newInterval = "["+startIntervalFirstRange+","+ " " + endIntervalSecondRange+"]"+mergeDirection;
                        innerList.add(newInterval);
                        System.out.println("3Added into Inner List: " + newInterval);
                        System.out.println("This is innerlist: " + innerList);
                        
                        }
                        //*************************************
                            
                            else
                            {
                            newInterval = "["+startIntervalFirstRange+","+ " " + endIntervalSecondRange+"]A";
                            innerList.add(newInterval);
                            System.out.println("4Added into Inner List: " + newInterval);
                            System.out.println("4*****THE INNERLIST: " + innerList);
                            }
                    
                            startIntervalFirstRange="";
                            endIntervalFirstRange="";
                            startIntervalSecondRange="";
                            endIntervalSecondRange="";
                        }
                        
                        else   //it is in right section since no overlap found
                        {
                            System.out.println(startIntervalFirstRange);
                            System.out.println(endIntervalFirstRange);
                            
                            System.out.println(startIntervalSecondRange);
                            System.out.println(endIntervalSecondRange);
                            
                            System.out.println(startInterval);
                            System.out.println(endInterval);
                            
                            //this just double checks there is no overlap, not required in practice
                            if (Integer.valueOf(endIntervalFirstRange)<=Integer.valueOf(startIntervalSecondRange))
                            {
                            
                            innerList.add("["+startIntervalFirstRange+","+ " " + endIntervalFirstRange+"]");
                            System.out.println("5Added into Inner List: " + "["+startIntervalFirstRange+","+ " " + endIntervalFirstRange+"]");
                            
                            //this section of code would need to undergo same process as above to ascertain if it can overlap
                            //with the above item added into innerList
                            //this is slightly frustrating since it will enforce first part of repeat code...
                            //but need to use startIntervalSecondRange instead of startInterval
                            //since startInterval is only initialised when counter>2 code above.....
                            
                            //**REPEAT CODE //***********
                        System.out.println("start interval: " + startInterval);
                        System.out.println("end interval: " + endInterval);
                        System.out.println("start interval second range: " + startIntervalSecondRange);
                        System.out.println("end interval second range: " + endIntervalSecondRange);
                        System.out.println("start interval first range: " + startIntervalFirstRange);
                        System.out.println("end interval first range: " + endIntervalFirstRange);
                            
                            
                        /*    
                        if ((Integer.valueOf(endIntervalSecondRange)>=Integer.valueOf(endIntervalFirstRange)  && Integer.valueOf(endIntervalSecondRange)>=Integer.valueOf(startIntervalFirstRange))  
    ||  (Integer.valueOf(endIntervalSecondRange)<=Integer.valueOf(endIntervalFirstRange)  && Integer.valueOf(endIntervalSecondRange)<=Integer.valueOf(startIntervalFirstRange)))
                        {
                            mergeDirection="";
                            
                           if (Integer.valueOf(endIntervalFirstRange)>Integer.valueOf(endIntervalSecondRange)  && (endIntervalFirstRange!=startIntervalFirstRange))
                            {
                                mergeDirection="A";
                            }
                            
                            if (Integer.valueOf(endIntervalFirstRange)<Integer.valueOf(endIntervalSecondRange)&& (endIntervalFirstRange!=startIntervalFirstRange))
                            {
                                mergeDirection="D";
                            }
                          */   
                            
                        //if (innerList.size()>0)
                    //    {
                     //   System.out.println("22Removed last item from innerList: " + innerList.get(innerList.size()-1));
                        
                      //  innerList.remove(innerList.size()-1);
                    //    }
                        
                        //newInterval = "["+startIntervalFirstRange+","+ " " + endIntervalSecondRange+"]"+mergeDirection;
                        //innerList.add(newInterval);
                        //System.out.println("9Added into Inner List: " + newInterval);
                        //System.out.println("This is innerlist: " + innerList);
                        
                        //}
                        
                            
                            
                         //else
                         //{
                         
                         mergeDirection="";
                         
                         
                          if (Integer.valueOf(endIntervalSecondRange)>Integer.valueOf(endIntervalFirstRange)  && (endIntervalSecondRange!=startIntervalSecondRange))
                           {
                                mergeDirection="A";
                                
                                
                                if (innerList.size()>0)
                        {
                        System.out.println("23Removed last item from innerList: " + innerList.get(innerList.size()-1));
                        
                        innerList.remove(innerList.size()-1);
                        }
                                
                                
                                
                            }
                            
                            if (Integer.valueOf(endIntervalSecondRange)<Integer.valueOf(endIntervalFirstRange)&& (endIntervalSecondRange!=startIntervalSecondRange))
                            {
                                mergeDirection="D";
                                
                                
                                if (innerList.size()>0)
                        {
                        System.out.println("24Removed last item from innerList: " + innerList.get(innerList.size()-1));
                        
                        innerList.remove(innerList.size()-1);
                        }
                                
                            }
                            
                 
                        innerList.add("["+startIntervalSecondRange+","+ " " + endIntervalSecondRange+"]"+mergeDirection);
                        System.out.println("6Added into Inner List: " + "["+startIntervalSecondRange+","+ " " + endIntervalSecondRange+"]"+mergeDirection);
                            
                        System.out.println("*****THE INNERLIST: " + innerList);
                        newInterval = "["+startIntervalSecondRange+","+ " " + endIntervalSecondRange+"]";
                         //}
                            
                            
                            
                        }
                    }
                    }
                }
                
                
            }
        }
        
        outerList.add(innerList);
        
        return outerList;
    }
}

