/home/caleb/ASDV-Java/Semester 2/Assignments/MP5_CalebFontenot/src/main/java/com/calebfontenot/mp5_calebfontenot/Combinations.java
/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
 */
package com.calebfontenot.mp5_calebfontenot;

/**
 *
 * @author caleb
 */

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

class Combinations
{

    private static void findCombinations(String[] A, int i, int k,
            Set<List<String>> subarrays,
            List<String> out)
    {
        if (A.length == 0 || k > A.length)
        {
            return;
        }

        // base case: combination size is `k`
        if (k == 0)
        {
            subarrays.add(new ArrayList<>(out));
            return;
        }

        // start from the next index till the last index
        for (int j = i; j < A.length; j++)
        {
            // add current element `A[j]` to the solution and recur for next index
            // `j+1` with one less element `k-1`
            out.add(A[j]);
            findCombinations(A, j + 1, k - 1, subarrays, out);
            out.remove(out.size() - 1);         // backtrack
        }
    }

    private static Set<List<String>> findCombinations(String[] A, int k)
    {
        Set<List<String>> subarrays = new HashSet<>();
        findCombinations(A, 0, k, subarrays, new ArrayList<>());
        return subarrays;
    }

    private static Set<List<String>> findAllCombinations(String[] A)
    {
        Set<List<String>> subarrays = new HashSet<>();
        for (int k = 1; k <= A.length; ++k)
        {
            findCombinations(A, 0, k, subarrays, new ArrayList<>());
        }
        return subarrays;
    }
/** Finds all distinct combinations of all sizes for elements of array.
 * 
 * @param A the elements to find their combinations
 * @return all distinct combinations of the elements, sorted by length. ascending order.
 */
    public static ArrayList<String> allCombinations(String[] A)
    {
        Set<List<String>> set = findAllCombinations(A);
        ArrayList<String> all = new ArrayList<String>();
        Iterator it = set.iterator();
        while (it.hasNext())
        {
            List<String> list = (List<String>) it.next();
            String s1 = "";
            for (String s2 : list)
            {
                s1 += s2;
            }
            all.add(s1);
        }
                Collections.sort(all, new Comparator<String>(){
            @Override
            public int compare(String o1, String o2)
            {
                return o1.length() - o2.length();
            }
        });
        return all;
    }
/** Finds all distinct combinations of all sizes for chars of the String.
 * 
 * @param A the characters to find their combinations.
 * @return all distinct combinations of the characters sorted by length, ascending order.
 */
    public static ArrayList<String> allCombinations(String a)
    {
        String[] A = new String[a.length()];
        for (int i = 0; i < A.length; ++i)
        {
            A[i] = Character.toString(a.charAt(i));
        }
        Set<List<String>> set = findAllCombinations(A);
        ArrayList<String> all = new ArrayList<String>();
        Iterator it = set.iterator();
        while (it.hasNext())
        {
            List<String> list = (List<String>) it.next();
            String s1 = "";
            for (String s2 : list)
            {
                s1 += s2;
            }
            all.add(s1);
        }
        
        Collections.sort(all, new Comparator<String>(){
            @Override
            public int compare(String o1, String o2)
            {
                return o1.length() - o2.length();
            }
        });
        return all;
    }

    public static void main(String[] args)
    {
        String[] A =
        {
            "1", "2", "3", "4"
        };
        int k = 2;

        // process elements from left to right
        System.out.println(allCombinations(A));
        System.out.println(allCombinations("1234"));

    }
}