/* 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();
	}
}
public class User extends Generics {
	// Class data
	public static KeyTypes key = KeyType.title;  // static initializer
	public static void setOrder(KeyTypes key) { User.key = key; }
	public enum KeyType implements KeyTypes {title, uid, password, name, points}

	// Instance data
    private final String uid;  // user / person id
    private final String password;
    private final String name;
    private final int points;

	/* constructor
	 *
	 */
	public User(String uid, String password, String name, int points)
	{
		super.setType("User");
		this.uid = uid;
		this.password = password;
		this.name = name;
        this.points = points;
	}

	/* 'Generics' requires getKey to help enforce KeyTypes usage */
	@Override
	protected KeyTypes getKey() { return User.key; }
	
	/* 'Generics' requires toString override
	 * toString provides data based off of Static Key setting
	 */
	@Override
	public String toString()
	{
		String output="";
		if (KeyType.uid.equals(this.getKey())) {
			output += this.uid;
		} else if (KeyType.password.equals(this.getKey())) {
			output += this.password;
		} else if (KeyType.name.equals(this.getKey())) {
			output += this.name;
        } else if (KeyType.points.equals(this.getKey())) {
			output += this.points;
		} else {
			output += super.getType() + ": " + this.uid + ", " + this.password + ", " + this.name + ", " + this.points;
		}
		return output;
		
	}

	// Test data initializer
	public static User[] Users() {
		return new User[]{
				new User("1", "CyberPatriot1!", "William", 20),
				new User("2", "Password1!", "Aidan", 5)
		};
	}
	
	/* main to test User class
	 * 
	 */
	public static void main(String[] args)
	{
		// Inheritance Hierarchy
		User[] objs = Users();

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

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

}
User.main(null);
class [LREPL.$JShell$15B$User; 2
Generic: User listed by title
User: 1, CyberPatriot1!, William, 20
User: 2, Password1!, Aidan, 5

class [LREPL.$JShell$15B$User; 2
Generic: User listed by name
William
Aidan

Challenge 2

// Create iterable Queue of Integers
Queue<Object> queue1 = new LinkedList<>();
queue1.add(1);
queue1.add(4);
queue1.add(5);
queue1.add(8);
Queue<Object> queue2 = new LinkedList<>();
queue2.add(2);
queue2.add(3);
queue2.add(6);
queue2.add(7);
System.out.println("Queue 1");
System.out.println(queue1);
System.out.println("Queue 2");
System.out.println(queue2);

Queue<Object> mergedQueue = new LinkedList<>();
while (!queue1.isEmpty() && !queue2.isEmpty()) {
    Object num1 = queue1.peek();
    Object num2 = queue2.peek();
    if ((int) num1 < (int) num2) {
        mergedQueue.add(num1);
        queue1.remove();
    } else {
        mergedQueue.add(num2);
        queue2.remove();
    }
}
while (!queue1.isEmpty()) {
    mergedQueue.add(queue1.peek());
    queue1.remove();
}
while (!queue2.isEmpty()) {
    mergedQueue.add(queue2.peek());
    queue2.remove();
}

System.out.println("Merged Queue");
System.out.println(mergedQueue);
Queue 1
[1, 4, 5, 8]
Queue 2
[2, 3, 6, 7]
Merged Queue
[1, 2, 3, 4, 5, 6, 7, 8]