/home/caleb/ASDV-Java/Semester 2/Assignments/MP4_CalebFontenot/src/main/java/com/calebfontenot/mp4_calebfontenot/BikeStores.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.mp4_calebfontenot;

import java.util.ArrayList;
import java.util.Collection;

/**
 *
 * @author caleb
 */
public class BikeStores {

    ArrayList<ArrayList<Bicycle>> storesOfBikes = new ArrayList<ArrayList<Bicycle>>();

    /**
     * Add a bike at storeNumber ( i.e. the storeNumber indicates the store)
     *
     * @param storeNumber which store
     * @param b the bike to add
     * @return true if the bike added, false if the storeNumber is invalid or b is null.
     */
    public BikeStores() {
        for (int i = 0; i < 3; i++) {
            storesOfBikes.add(new ArrayList<Bicycle>());
        }
    }

    public boolean addBike(int storeNumber, Bicycle b) {
        if (storeNumber < 0 || storeNumber > this.storesOfBikes.size() - 1) {
            return false;
        }
        if (b == null) {
            return false;
        }
        System.out.println("Attempting to add " + b + " to store at index " + storeNumber);
        //Unpack array
        ArrayList<Bicycle> bikesInInventory = storesOfBikes.get(storeNumber);
        bikesInInventory.add(b);

        // Repack array
        storesOfBikes.set(storeNumber, bikesInInventory);
        System.out.println("success!");
        return true;
    }

    /**
     * Removes a bike at a specific store.
     *
     * @param storeNumber the store that has the bike
     * @param b the bike to be removed
     * @return true of the bike is removed, false if the bike does not exist, or bike is null.
     */
    public boolean removeBike(int storeNumber, Bicycle b) {
        if (storeNumber < 0 || storeNumber > this.storesOfBikes.size() - 1) {
            return false;
        }
        if (b == null) {
            return false;
        }
        System.out.println("Attempting to remove " + b + " to store at index " + storeNumber);
        // Remove bike from array.
        ArrayList<Bicycle> bikesInInventory = storesOfBikes.get(storeNumber);
        bikesInInventory.remove(b); //YEET
        System.out.println("success!");
        return true;
    }

    /**
     * Prints the indexes before each bike , one store per line
     *
     * @param stores stores of bikes
     */
    public static void print(ArrayList<ArrayList<Bicycle>> stores) {
        for (int i = 0; i < stores.size(); ++i) {
            System.out.println("---------- " + "printing row " + (i + 1) + " ----------");
            for (int j = 0; j < stores.get(i).size(); ++j) {
                System.out.println(stores.get(i).get(j) + " ");

            }
        }
    }

    public static void printSingle(ArrayList<Bicycle> stores) {
        System.out.println("----------" + "printSingle" + "----------");
        for (int j = 0; j < stores.size(); ++j) {
            System.out.println(stores.get(j) + " ");
        }

    }

    public static void printRank(ArrayList<Bicycle> stores) {
        System.out.println("----------" + "printRank" + "----------");
        for (int j = 0; j < stores.size(); ++j) {
            System.out.println(stores.get(j) + " " + stores.get(j).calculatedDetails().getRank());
        }

    }

    /**
     * Groups bikes by type ans sorts them by the ranking of Details. There will be three groups and each group stored in descending order by rank.
     *
     * @param stores the stores of bikes
     * @return a newly created ArrayList<ArrayList<Bicycle>> with the bikes sorted.
     */
    public static ArrayList<ArrayList<Bicycle>> sortBikesByType(final ArrayList<ArrayList<Bicycle>> stores) {
        ArrayList<ArrayList<Bicycle>> newStore = new ArrayList<ArrayList<Bicycle>>();
        // group arrayLists
        ArrayList<Bicycle> mountainBikes = new ArrayList<Bicycle>();
        ArrayList<Bicycle> speedBikes = new ArrayList<Bicycle>();
        ArrayList<Bicycle> childBikes = new ArrayList<Bicycle>();
        System.out.println("---------- " + "grouping by bike type... " + " ----------");
        for (int i = 0; i < stores.size(); ++i) {
            for (int j = 0; j < stores.get(i).size(); ++j) {
                // System.out.println(stores.get(i).get(j).calculatedDetails().getRank() + " ");
                Bicycle bike = stores.get(i).get(j);
                if (bike instanceof ChildBike) {
                    childBikes.add(bike);
                } else if (bike instanceof MountainBike) {
                    mountainBikes.add(bike);
                } else if (bike instanceof SpeedBike) {
                    speedBikes.add(bike);
                }
            }
        }
        //printRank(childBikes);
        //printRank(mountainBikes);
        //printRank(speedBikes);
        System.out.println("sorting...");
        sortType(childBikes);
        sortType(mountainBikes);
        sortType(speedBikes);
        System.out.println("sorted");
        //printRank(childBikes);
        //printRank(mountainBikes);
        //printRank(speedBikes);
        newStore.add(childBikes);
        newStore.add(mountainBikes);
        newStore.add(speedBikes);
        return newStore;
    }

    private static void sortType(ArrayList<Bicycle> arrList) {
        for (int x = 0; x < arrList.size(); ++x) {
            for (int i = 0; i < arrList.size(); ++i) {
                for (int j = i + 1; j < arrList.size(); ++j) {
                    int compare1 = arrList.get(i).calculatedDetails().getRank();
                    int compare2 = arrList.get(j).calculatedDetails().getRank();
                    if (compare1 < compare2) {
                        Bicycle tmp = arrList.get(i);
                        arrList.set(i, arrList.get(j));
                        arrList.set(j, tmp);
                    }
                }
            }
        }
    }

    public static void print(Object[] arr) {
        for (Object o : arr) {
            System.out.println(o);
        }
    }

    public static void print(Object[][] arr) {
        for (int i = 0; i < arr.length; i++) {
            System.out.println("---------- " + "printing row " + (i + 1) + " ----------");
            print(arr[i]);

        }
    }

    /**
     * Returns a 2D array containing all the bikes in the store in proper sequence (from first to last element). Store 0 with all its bikes, store 1 with all its bikes, and so on.
     *
     * @return a 2D array of all stores with bikes.
     */
    public Object[][] toArray() {
        Object[][] arr = new Object[storesOfBikes.size()][];
        for (int i = 0; i < storesOfBikes.size(); i++) {
            arr[i] = storesOfBikes.toArray();
        }
        return arr;
    }

    /**
     * Retains only the Bicycles in the stores that are contained in the specified collection. In other words, removes from this list all of bikes that are not contained in the specified location.
     *
     * @param c the bikes to be removed
     * @return true if any store changed as a result of the call.
     */
    public boolean retainAll(Collection<Bicycle> c) {
        boolean modified = false;
        for (int i = storesOfBikes.size() - 1; i >= 0; i--) {
            ArrayList<Bicycle> bikes = storesOfBikes.get(i);
            for (int j = bikes.size() - 1; j >= 0; j--) {
                Bicycle bike = bikes.get(j);
                if (!c.contains(bike)) {
                    bikes.remove(j);
                    System.out.println("Removing " + bike);
                    modified = true;
                }
            }
        }
        System.out.println("Bikes to remove:");
        printSingle((ArrayList<Bicycle>) c);
        return modified;
    }

    public static void main(String[] args) {
        BikeStores bikes = new BikeStores();
        //add 5 bikes to store 0 ( 2 speedBikes, 2 mountain 1 child)
        bikes.addBike(0, new SpeedBike(4, 3, 10, 40));
        bikes.addBike(0, new SpeedBike(1, 2, 10, 30));
        bikes.addBike(0, new MountainBike(1, 2, 3, 20));
        bikes.addBike(0, new MountainBike(3, 2, 10, 25));
        bikes.addBike(0, new ChildBike(false, 1, 1, 10));
        //add 5 bikes to store 1 (  3 speedbikes, 1 mountain 1 child)
        bikes.addBike(1, new SpeedBike(10, 4, 10, 20));
        bikes.addBike(1, new SpeedBike(0, 2, 10, 50));
        bikes.addBike(1, new SpeedBike(3, 2, 10, 38));
        bikes.addBike(1, new MountainBike(1, 3, 5, 44));
        bikes.addBike(1, new ChildBike(true, 1, 1, 15));
        //add 6 bikes to store 2 (  2 speedBikes, 2 mountain 2 child )
        bikes.addBike(2, new SpeedBike(7, 10, 20, 25));
        bikes.addBike(2, new SpeedBike(0, 8, 40, 55)); // retainAll should match this one
        bikes.addBike(2, new MountainBike(2, 3, 15, 33));
        bikes.addBike(2, new MountainBike(1, 3, 15, 24));
        bikes.addBike(2, new ChildBike(true, 1, 2, 20));  
        bikes.addBike(2, new ChildBike(false, 1, 1, 18));// retainAll should match this one
        //remove one child bike from store 2
        bikes.removeBike(2, new ChildBike(true, 1, 2, 20)); // Java reuses the object created earlier since it has the same values.
        //PRINT
        print(bikes.storesOfBikes);
        //SORT
        ArrayList<ArrayList<Bicycle>> sortedBikes = sortBikesByType(bikes.storesOfBikes);
        //PRINT what the method return
        System.out.println("SORTED BIKES");
        print(sortedBikes);
        //PRINT the original store
        System.out.println("ORIGINAL STORE ARRAYLIST");
        print(bikes.storesOfBikes);
        // ---------- TEST retainAll ----------
        System.out.println("Testing retainAll();...");
        Collection<Bicycle> c1 = new ArrayList<Bicycle>();
        c1.add(new SpeedBike(0, 8, 40, 55));
        c1.add(new ChildBike(false, 1, 1, 18));
        Bicycle b1 = bikes.storesOfBikes.get(2).get(1);
        Bicycle b2 = bikes.storesOfBikes.get(2).get(4);
        Bicycle b3 = ((ArrayList<Bicycle>) c1).get(0);
        Bicycle b4 = ((ArrayList<Bicycle>) c1).get(1);
        
        System.out.println(b1.equals(b3) + " " + b2.equals(b4));
        bikes.retainAll(c1);
        print(bikes.storesOfBikes);

    }

}

class NotABike {

}