/* This is wrapper class...
 Objective would be to push more functionality into this Class to enforce consistent definition
 */
public abstract class Generics {
	public final String masterType = "Generic";
	private String type;	// extender should define their data type

	// generic enumerated interface
	public interface KeyTypes {
		String name();
	}
	protected abstract KeyTypes getKey();  	// this method helps force usage of KeyTypes

	// getter
	public String getMasterType() {
		return masterType;
	}

	// getter
	public String getType() {
		return type;
	}

	// setter
	public void setType(String type) {
		this.type = type;
	}
	
	// this method is used to establish key order
	public abstract String toString();

	// static print method used by extended classes
	public static void print(Generics[] objs) {
		// print 'Object' properties
		System.out.println(objs.getClass() + " " + objs.length);

		// print 'Generics' properties
		if (objs.length > 0) {
			Generics obj = objs[0];	// Look at properties of 1st element
			System.out.println(
					obj.getMasterType() + ": " + 
					obj.getType() +
					" listed by " +
					obj.getKey());
		}

		// print "Generics: Objects'
		for(Object o : objs)	// observe that type is Opaque
			System.out.println(o);

		System.out.println();
	}
}
/*
 * Animal class extends Generics and defines abstract methods
 */
public class FRQ extends Generics {
	// Class data
	public static KeyTypes key = KeyType.title;  // static initializer
	public static void setOrder(KeyTypes key) { FRQ.key = key; }
	public enum KeyType implements KeyTypes {title, year, problem, subject, difficulty,}

	// Instance data
	private final int year;
	private final int problem;
	private final String subject;
	private final String difficulty;

	/* constructor
	 *
	 */
	public FRQ(int year, int problem, String subject, String difficulty)
	{
		super.setType("FRQ");
		this.year = year;
		this.problem = problem;
		this.subject = subject;
		this.difficulty = difficulty;
	}

	/* 'Generics' requires getKey to help enforce KeyTypes usage */
	@Override
	protected KeyTypes getKey() { return FRQ.key; }
	
	/* 'Generics' requires toString override
	 * toString provides data based off of Static Key setting
	 */
	@Override
	public String toString()
	{
		String output="";
		if (KeyType.year.equals(this.getKey())) {
			output += this.year;
			// output = output.substring(output.length() - 2);
		} else if (KeyType.problem.equals(this.getKey())) {
			output += this.problem;
		} else if (KeyType.subject.equals(this.getKey())) {
			output += this.subject;
		} else if (KeyType.difficulty.equals(this.getKey())) {
			output += this.difficulty;
		} else {
			output += super.getType() + ": " + this.year + ", " + this.problem + ", " + this.subject + ", " + this.difficulty;
		}
		return output;
		
	}

	// Test data initializer
	public static FRQ[] FRQs() {
		return new FRQ[]{
				new FRQ(2010, 1, "Control Structures", "Medium"),
				new FRQ(2015, 1, "Arrays", "Easy"),
				new FRQ(2017, 4, "2D Arrays", "Easy"),
				new FRQ(2021, 3, "Writing Classes", "Hard"),

		};
	}
	
	/* main to test Animal class
	 * 
	 */
	public static void main(String[] args)
	{
		// Inheritance Hierarchy
		FRQ[] objs = FRQs();

		// print with title
		FRQ.setOrder(KeyType.title);
		FRQ.print(objs);

		// print name only
		FRQ.setOrder(KeyType.year);
		FRQ.print(objs);
	}

}
FRQ.main(null);
class [LREPL.$JShell$15J$FRQ; 4
Generic: FRQ listed by title
FRQ: 2010, 1, Control Structures, Medium
FRQ: 2015, 1, Arrays, Easy
FRQ: 2017, 4, 2D Arrays, Easy
FRQ: 2021, 3, Writing Classes, Hard

class [LREPL.$JShell$15J$FRQ; 4
Generic: FRQ listed by year
2010
2015
2017
2021

/*
 * Animal class extends Generics and defines abstract methods
 */
public class Review extends Generics {
	// Class data
	public static KeyTypes key = KeyType.title;  // static initializer
	public static void setOrder(KeyTypes key) { Review.key = key; }
	public enum KeyType implements KeyTypes {title, year, problem, rating, interactivity, questions}

	// Instance data
	private final int year;
	private final int problem;
	private final int rating;
	private final String interactivity;
    private final String questions;


	/* constructor
	 *
	 */
	public Review(int year, int problem, int rating, String interactivity, String questions)
	{
		super.setType("Review");
		this.year = year;
		this.problem = problem;
		this.rating = rating;
		this.interactivity = interactivity;
        this.questions = questions;
	}

	/* 'Generics' requires getKey to help enforce KeyTypes usage */
	@Override
	protected KeyTypes getKey() { return Review.key; }
	
	/* 'Generics' requires toString override
	 * toString provides data based off of Static Key setting
	 */
	@Override
	public String toString()
	{
		String output="";
		if (KeyType.year.equals(this.getKey())) {
			output += this.year;
			// output = output.substring(output.length() - 2);
		} else if (KeyType.problem.equals(this.getKey())) {
			output += this.problem;
		} else if (KeyType.rating.equals(this.getKey())) {
			output += this.rating;
		} else if (KeyType.interactivity.equals(this.getKey())) {
			output += this.interactivity;
        } else if (KeyType.questions.equals(this.getKey())) {
			output += this.questions;
		} else {
			output += super.getType() + ": " + this.year + ", " + this.problem + ", " + this.rating + ", " + this.interactivity + ", " + this.questions;
		}
		return output;
		
	}

	// Test data initializer
	public static Review[] reviews() {
		return new Review[]{
				new Review(2010, 1, 4, "Good", "Why is this considered a control structures question?"),
				new Review(2015, 1, 2, "Poor", "How does this array work?"),
				new Review(2017, 4, 5, "Excellent", "Why would a normal array not work here?"),
				new Review(2017, 3, 3, "Good", "Would this not be categorized as methods and control structures?"),

		};
	}
	
	/* main to test Animal class
	 * 
	 */
	public static void main(String[] args)
	{
		// Inheritance Hierarchy
		Review[] objs = reviews();

		// print with title
		Review.setOrder(KeyType.title);
		Review.print(objs);

		// print name only
		Review.setOrder(KeyType.interactivity);
		Review.print(objs);
	}

}
Review.main(null);
class [LREPL.$JShell$20$Review; 4
Generic: Review listed by title
Review: 2010, 1, 4, Good, Why is this considered a control structures question?
Review: 2015, 1, 2, Poor, How does this array work?
Review: 2017, 4, 5, Excellent, Why would a normal array not work here?
Review: 2017, 3, 3, Good, Would this not be categorized as methods and control structures?

class [LREPL.$JShell$20$Review; 4
Generic: Review listed by interactivity
Good
Poor
Excellent
Good

/**
 * Queue Manager
 * 1. "has a" Queue
 * 2. support management of Queue tasks (aka: titling, adding a list, printing)
 */
class QueueManager<T> {
    // queue data
    private final String name; // name of queue
    private int count = 0; // number of objects in queue
    public final Queue<T> queue = new Queue<>(); // queue object

    /**
     *  Queue constructor
     *  Title with empty queue
     */
    public QueueManager(String name) {
        this.name = name;
    }

    /**
     *  Queue constructor
     *  Title with series of Arrays of Objects
     */
    public QueueManager(String name, T[]... seriesOfObjects) {
        this.name = name;
        this.addList(seriesOfObjects);
    }

    /**
     * Add a list of objects to queue
     */
    public void addList(T[]... seriesOfObjects) {  //accepts multiple generic T lists
        for (T[] objects: seriesOfObjects)
            for (T data : objects) {
                this.queue.add(data);
                this.count++;
            }
    }

    /**
     * Print any array objects from queue
     */
    public void printQueue() {
        System.out.println(this.name + " count: " + count);
        System.out.print(this.name + " data: ");
        for (T data : queue)
            System.out.print(data + " ");
        System.out.println();
    }
}