wm: java

ref: fd5476ab0c29f10d063c9f829f0cb2c57692d38f
dir: /Main.java/

View raw version
//package BookProj;

// handle throws
// make whatever you can final

import java.util.HashMap;
import java.util.ArrayList;
import java.util.TreeMap;

import java.util.Scanner;

import java.util.NoSuchElementException;
import java.io.IOException;

import java.util.regex.Pattern;
import java.util.regex.Matcher;

import java.io.Console;
import java.io.File;
import java.io.FileWriter;

import java.time.LocalDateTime;

enum TakeErr
{
	Ok,

	NoBook, /* no such book has found */
	BookReserved, /* book is reserved by someone else */
	NoBookReserved, /* no book is revserved */

	NoUser, /* no such user has found */
	UserHasABook, /* User has already registered a book */
	Age; /* age doesn't match */
}

/* used in DelAdmin, DelUser and DelBook */
enum DelErr
{
	Ok,
	BookReserved, /* book we are trying to delete has been reserved by someone */
	UserHasABook, /* user we are trying to delete has a book */
	NoBook,
	NoUser;
}

enum Role
{
	Admin,
	User;
}
 
enum BookAttr
{
	ISBN,
	Status,
	Name,
	Author,
	AgeGroup,
	Abstract,
	Owner;
}

enum AdminAttr
{
	Username,
	role,
	Reserved,
	ID,
	RegTime,
	// Password,
	Active;
}

enum UserAttr
{
	Username,
	role,
	Reserved,
	ID,
	RegTime,
	Age,
	Active;
}

interface Library 
{
	Admin NewAdmin(String user, String pass);
	User NewUser(String user, int age);
	Book NewBook(String isbn, String name, String author, int agegroup, String abst);

	DelErr DelAdmin(Admin a);
	DelErr DelUser(User u);
	DelErr DelBook(Book b);

	boolean Login(Admin a, String pass);
	boolean Login(User u);

	void Logout(Admin a);
	void Logout(User u);

	boolean CheckAdmin(String a);
	boolean CheckUser(String u);
	boolean CheckBook(String isbn);

	Admin MatchAdmin(String un);
	User MatchUser(String un);
	Book MatchBook(String isbn);

	boolean FindAdmin(AdminAttr k, Pattern p);
	boolean FindUser(UserAttr k, Pattern p);
	boolean FindBook(BookAttr k, Pattern p);

	TakeErr TakeBook(String un, String isbn);
	TakeErr TakeBook(Admin u, Book b);
	TakeErr TakeBook(User u, Book b);

	TakeErr ReturnBook(User u);
	TakeErr ReturnBook(Admin u);

	void SaveLog(String fp, String in);

	/*
	String LoadLog(File fd, int n);
	void LoadState(File fd);
	void SaveState(File fd);
	*/

	interface UI
	{
		void Program();
		void LoginMenu();

		/* checks password with user, gets input from GetPassword */
		boolean AskPass(Admin u);
		// boolean AskPass(User u);

		/* different Menus, for different Users to handle */
		void Menu(Admin u);
		void Menu(User u);

		/* Gets a String, either console or scanner, checks if it's valid or not, and encrypt it */
		String GetUsername();
		String GetPassword();
		
		/* search foolan menu */
		void SearchAdmin();
		void SearchUser();
		void SearchBook();

		/* add foolan menu */
		void AddAdmin();
		void AddUser();
		void AddBook();

		/* remove foolan menu */
		void RemAdmin();
		void RemUser();
		void RemBook(); // maybe it's stolen

		/* list foolan menu */
		void ListAdmin();
		void ListUser();
		void ListBook();

		/* take and return book menus */
		void TakeMenu(Admin a);
		void TakeMenu(User u);
		void ReturnMenu(Admin a);
		void ReturnMenu(User u);

		/* handles result of Take/IO/Del Funcations */
		void Result(TakeErr res);
		void Result(DelErr res);
		void Result(IOErr res);
	}
}

/* i personally don't use it but here is a converter */
class Books
{
	HashMap<BookAttr, String> Book = new HashMap<BookAttr, String>();
	HashMap<String, HashMap> Booklist = new HashMap<String, HashMap>();

	HashMap<String, TreeMap> Mkbl(HashMap<String, Book> bl)
	{
		HashMap<String, TreeMap> list = new HashMap<String, TreeMap>();
		for(Book i: bl.values())
		{
			list.put(i.getISBN(), i.toMap());
		}
		return list;
	}
}

class Book
{
	/* book is untaken by default */
	private	boolean Status = false;
	private String Abstract, Author, Name, ISBN;
	private String Owner = ""; /* Username of user who reserved it */
	private int AgeGroup;

	Book(String isbn, String name, String author, int age, String abs)
	{
		/* joy of joys willy */
		this.ISBN = isbn;
		this.Name = name;
		this.Author = author;
		this.AgeGroup = age;
		this.Abstract = abs;
	}

	boolean AgeOk(int age)
	{
		if(this.AgeGroup <= age)
			return true;
		else
			return false;
	}

	boolean setOwner(String u)
	{
		if(!this.Owner.isEmpty())
			return false;

		this.Owner = u;
		return true;
	}

	void setStatus(boolean b)
	{
		if(this.Status == b)
			throw new IllegalStateException("Status already set!");

		this.Status = b;
	}

	boolean getStatus()
	{
		return Status;
	}

	String getAbstract()
	{
		return this.Abstract;
	}

	String getAuthor()
	{
		return this.Author;
	}

	String getName()
	{
		return this.Name;
	}

	String getISBN()
	{
		return this.ISBN;
	}

	int getAgeGroup()
	{
		return this.AgeGroup;
	}

	String getOwner()
	{
		return this.Owner;
	}

	TreeMap<BookAttr, String> toMap()
	{
		TreeMap<BookAttr, String> temp = new TreeMap<BookAttr, String>();

		temp.put(BookAttr.ISBN, this.ISBN);
		temp.put(BookAttr.Status, Boolean.toString(this.Status));
		temp.put(BookAttr.Name, this.Name);
		temp.put(BookAttr.Author, this.Author);

		temp.put(BookAttr.AgeGroup, Integer.toString(this.AgeGroup));
		temp.put(BookAttr.Abstract, this.Abstract);
		temp.put(BookAttr.Owner, this.Owner);
		return temp;
	}
}

abstract class BasicUser
{
	private Role role;
	private String Username;

	/* we will use isEmpty, even if it's not init-ed */
	private String Reserved = new String();
	private int ID;
	private LocalDateTime RegTime;
	public boolean Active = false;

	// abstract boolean IsReserved(String ISBN);

	BasicUser(Role r, String u, int id, LocalDateTime rt)
	{
		this.role = r;
		this.Username = u;
		this.ID = id;
		this.RegTime = rt;
	}

	Role getRole()
	{
		return this.role;
	}

	String getUsername()
	{
		return this.Username;
	}

	int getID()
	{
		return this.ID;
	}


	void clearReserved()
	{
		this.Reserved = "";
	}

	void setReserved(String isbn)
	{
		/* ensure he has no books */
		if(!this.getReserved().isEmpty() && !isbn.equals(""))
			throw new IllegalStateException("User already has a book!");

		this.Reserved = isbn;
	}

	String getReserved()
	{
		return this.Reserved;
	}

	LocalDateTime getRegTime()
	{
		return this.RegTime;
	}
}

class Admin extends BasicUser
{
	private String Password;
	Admin(String user)
	{
		super(Role.Admin, user, (int)(Math.random()*100), LocalDateTime.now());

	}
	Admin(String user, String Pass)
	{
		/* maybe check if password is too easy? */
		super(Role.Admin, user, (int)(Math.random()*100), LocalDateTime.now());
		this.setPassword(Pass);
	}

	boolean checkPass(String pass)
	{
		if(this.Password.equals(pass))
			return true;
		else
			return false;
	}

	/* passwords should be unchangeable... for now */
	private void setPassword(String pass)
	{
		this.Password = pass;
	}

	TreeMap<AdminAttr, String> toMap()
	{
		TreeMap<AdminAttr, String> temp = new TreeMap<AdminAttr, String>();

		temp.put(AdminAttr.Username, getUsername());
		temp.put(AdminAttr.role, getRole().toString());
		temp.put(AdminAttr.Reserved, getReserved());
		temp.put(AdminAttr.ID, Integer.toString(getID()));
		temp.put(AdminAttr.RegTime, getRegTime().toString());
		/*  temp.put(AdminAttr.Password, this.Password); secrect secrect secrect */
		temp.put(AdminAttr.Active, Boolean.toString(this.Active));

		return temp;
	}
}

class User extends BasicUser
{
	private int Age;
	User(String username, int age)
	{
		super(Role.User, username, (int)(Math.random()*1000+101), LocalDateTime.now());
		this.Age = age;
	}
	int getAge()
	{
		return this.Age;
	}

	boolean IsReserved(Book b)
	{
		return (this.getReserved().equals(b.getISBN()));
	}

	boolean IsReserved(String ISBN)
	{
		return (this.getReserved().equals(ISBN));
	}

	TreeMap<UserAttr, String> toMap()
	{
		TreeMap<UserAttr, String> temp = new TreeMap<UserAttr, String>();

		temp.put(UserAttr.Username, this.getUsername());
		temp.put(UserAttr.role, getRole().toString());
		temp.put(UserAttr.Reserved, getReserved());
		temp.put(UserAttr.ID, Integer.toString(getID()));
		temp.put(UserAttr.RegTime, getRegTime().toString());
		temp.put(UserAttr.Age, Integer.toString(this.Age));
		temp.put(UserAttr.Active, Boolean.toString(this.Active));

		return temp;
	}
}

class Lib implements Library
{
	/* Username, Admin/User, ISBN, Book */
	private HashMap<String, Admin> AdminList = new HashMap<String, Admin>();
	private HashMap<String, User> UserList = new HashMap<String, User>();
	private HashMap<String, Book> BookList = new HashMap<String, Book>();

	private ArrayList<Admin> AdminQuery = new ArrayList<Admin>();
	private ArrayList<User> UserQuery = new ArrayList<User>();
	private ArrayList<Book> BookQuery = new ArrayList<Book>();

	static Admin adm;
	static User usr;
	static String logfile = "Log.txt";
	int ResCount = 0;


	public boolean Login(Admin u, String pass)
	{
			/* clear null */
			adm = null;
			if(u.Active)
				throw new IllegalStateException("Admin is already active");

			/* maybe later i want to do more stuff here */
			if(u.checkPass(pass))
			{
				u.Active = true;
				this.adm = u;
				return true;
			}
			else
				return false;
			
	}

	public void Logout(Admin a)
	{
		if(!CheckAdmin(a.getUsername()))
			throw new NoSuchElementException("No such Admin exists.");

		if(!a.Active)
			throw new IllegalStateException("Admin is already inactive");

		a.Active = false;
	}

	public boolean Login(User u)
	{
		if(u.Active)
			throw new IllegalStateException("Admin is already active?");
		/* maybe later i want to do more stuff here */
		u.Active = true;
		usr = u;
		return true;
	}

	public void Logout(User u)
	{
		if(!CheckUser(u.getUsername()))
			throw new NoSuchElementException("No such User exists.");

		if(!u.Active)
			throw new IllegalStateException("User is already inactive.");

		u.Active = false;
	}

	public Admin NewAdmin(String user, String pass)
	{
		Admin a;
		if(CheckUser(user))
			throw new IllegalArgumentException("Admin already exists");

		/* if user is "admin", use defaults */
		if(user.equals("admin"))
		{
			pass = "pass";
			pass = Integer.toString(pass.hashCode());
		}
		a = new Admin(user, pass);

		this.AdminList.put(a.getUsername(), a);
		return a;
	}

	public DelErr DelAdmin(Admin u)
	{
		if(!u.getReserved().isEmpty())
			return DelErr.UserHasABook;

		this.AdminList.remove(u.getUsername(), u);
		return DelErr.Ok;
	}

	public User NewUser(String user, int age)
	{
		User u;
		if(CheckUser(user))
			throw new IllegalArgumentException("User already exists");

		u = new User(user, age);

		this.UserList.put(user, u);
		return u;
	}

	public DelErr DelUser(User u)
	{
		if(!u.getReserved().isEmpty())
			return DelErr.UserHasABook;
		this.UserList.remove(u.getUsername(), u);
		return DelErr.Ok;
	}

	public Book NewBook(String isbn, String name, String author, int agegroup, String abst)
	{
		Book b;
		if(CheckBook(isbn))
				throw new IllegalStateException("Book already exist");

		if(agegroup > 99)
			agegroup = 99;
		if(agegroup < 2)
			agegroup = 3;

		b = new Book(isbn, name, author, agegroup, abst);
		this.BookList.put(isbn, b);
		return b;
	}

	/* we shouldn't use MatchBook on UI, input is taken from user in string form */
	public DelErr DelBook(String isbn)
	{
		if(!CheckBook(isbn))
			return DelErr.NoBook;

		return DelBook(MatchBook(isbn));
	}

	public DelErr DelBook(Book b)
	{
		if(!b.getOwner().isEmpty())
			// System.err.println("User " + b.getOwner() + " have reserved this book.");
			// throw new IllegalStateException("Book is reserved.");
			return DelErr.UserHasABook;

		this.BookList.remove(b.getISBN());
		return DelErr.Ok;
	}

	public boolean CheckBook(String isbn)
	{
		boolean b = false;

		for(Book i : this.BookList.values())
		{
			if(i.getISBN().equals(isbn))
				b = true;
		}

		return b;
	}

	public Book MatchBook(String isbn)
	{
		Book b = null;

		for(Book i : this.BookList.values())
		{
			if(i.getISBN().equals(isbn))
				b = i;
		}

		if(b == null)
			throw new NoSuchElementException("No such book exists.");

		return b;
	}

/*
	public boolean FindBook(BookAttr k, Pattern p)
	{
		//
		this.BookQuery.clear();
		Matcher m;
		switch(k)
		{
			case AgeGroup:
				for(Book i : BookList.values())
				{
					m = p.matcher(Integer.toString(i.getAgeGroup()));
					if(m.find())
						this.BookQuery.add(i);
				}
				break;

			case Abstract:
				for(Book i : BookList.values())
				{
					m = p.matcher(i.getAbstract());
					if(m.find())
						this.BookQuery.add(i);
				}
				break;

			case Author:
				for(Book i : BookList.values())
				{
					m = p.matcher(i.getAuthor());
					if(m.find())
						this.BookQuery.add(i);
				}
				break;

			case Name:
				for(Book i : BookList.values())
				{
					m = p.matcher(i.getName());
					if(m.find())
						this.BookQuery.add(i);
				}
				break;

			case ISBN:
				for(Book i : BookList.values())
				{
					m = p.matcher(i.getISBN());
					if(m.find())
						this.BookQuery.add(i);
				}
				break;

			default:
				// XXX write stuff and nag in case of invalid stuff
				break;
		}
		if(this.BookQuery.size() == 0)
			return false;
		else 
			return true;
	}
*/

	public boolean FindBook(BookAttr k, Pattern p)
	{
		Matcher m;
		this.BookQuery.clear();
		for(Book i: this.BookList.values())
		{
			m = p.matcher(i.toMap().get(k));
			if(m.find())
				BookQuery.add(i);
		}
		if(this.BookQuery.size() == 0)
			return false;
		else
			return true;
	}

	public boolean CheckAdmin(String a)
	{
			for(Admin i : this.AdminList.values())
			{
				if(i.getUsername().equals(a))
				{
					return true;
				}
			}
			return false;
	}

	public Admin MatchAdmin(String un)
	{
		Admin a = null;

		for(Admin i : this.AdminList.values())
		{
			if(i.getUsername().equals(un))
				a = i;
		}

		if(a == null)
			throw new NoSuchElementException("No such Admin exists.");
		return a;
	}

	public boolean FindAdmin(AdminAttr k, Pattern p)
	{
		Matcher m;
		this.AdminQuery.clear();
		for(Admin i: this.AdminList.values())
		{
			m = p.matcher(i.toMap().get(k));
			if(m.find())
				AdminQuery.add(i);
		}
		if(this.AdminQuery.size() == 0)
			return false;
		else
			return true;
	}

	public boolean CheckUser(String u)
	{
			for(User i : this.UserList.values())
			{
				if(i.getUsername().equals(u))
				{
					return true;
				}
			}
			return false;
	}

	public User MatchUser(String un)
	{
		User u = null;

		for(User i : this.UserList.values())
		{
			if(i.getUsername().equals(un))
				u = i;
		}

		if(u == null)
		{
			throw new NoSuchElementException("No such User exists.");
		}
		return u;
	}

	public boolean FindUser(UserAttr k, Pattern p)
	{
		Matcher m;
		this.UserQuery.clear();
		for(User i: this.UserList.values())
		{
			m = p.matcher(i.toMap().get(k));
			if(m.find())
				UserQuery.add(i);
		}
		if(this.UserQuery.size() == 0)
			return false;
		else
			return true;
	}

	public boolean FindBook(boolean q)
	{
		/* flush last query */
		this.BookQuery.clear();
		for(Book i : BookList.values())
		{
			if(i.getStatus() == q)
				this.BookQuery.add(i);
		}
		if(this.BookQuery.size() == 0)
			return false;
		else 
			return true;
	}

	/* user/admin's ID, ISBN */
	public TakeErr TakeBook(String un, String isbn)
	{
		Book b = this.BookList.get(isbn);
		if(this.CheckUser(un))
			return TakeBook(MatchUser(un), b);
		else if(this.CheckAdmin(un))
			return TakeBook(MatchAdmin(un), b);
		else
			return TakeErr.NoUser;
	}

	/* they shouldn't be able to get a book, but still */
	public TakeErr TakeBook(Admin a, Book b)
	{
		/* check if book is taken */
		if(b.getStatus())
			return TakeErr.BookReserved;

		/* he has some book? blasmphy! */
		if(!a.getReserved().isEmpty())
			return TakeErr.UserHasABook;

		/* check if ages match admin has no age anyway
		if(!b.AgeOk(a.getAge()))
			return TakeErr.Age; */

		a.setReserved(b.getISBN());

		b.setOwner(a.getUsername());
		b.setStatus(true);

		this.ResCount++;
		SaveLog(logfile, "[Take] " + b.getISBN() + " by " + a.getUsername() + '\n');
		return TakeErr.Ok;
	}

	public TakeErr TakeBook(User u, Book b)
	{
		/* check if book is taken */
		if(b.getStatus())
			return TakeErr.BookReserved;

		/* he has some book? blasmphy! */
		if(!u.getReserved().isEmpty())
			return TakeErr.UserHasABook;

		/* check if ages match */
		if(!b.AgeOk(u.getAge()))
			return TakeErr.Age;

		u.setReserved(b.getISBN());

		b.setOwner(u.getUsername());
		b.setStatus(true);

		this.ResCount++;
		SaveLog(logfile, "[Take] " + b.getISBN() + " by " + u.getUsername() + '\n');
		return TakeErr.Ok;
	}

	public TakeErr ReturnBook(Admin a)
	{
		Book b;
		if(a.getReserved().isEmpty())
			return TakeErr.NoBookReserved;

		if(!CheckBook(a.getReserved()))
			return TakeErr.NoBook;

		b = MatchBook(a.getReserved());

		a.clearReserved();

		b.setOwner(null);
		b.setStatus(false);

		this.ResCount--;
		SaveLog(logfile, "[Return] " + b.getISBN() + " by " + a.getUsername() + '\n');
		return TakeErr.Ok;
	}

	public TakeErr ReturnBook(User u)
	{
		Book b;
		if(u.getReserved().isEmpty())
			return TakeErr.NoBookReserved;

		if(!CheckBook(u.getReserved()))
			return TakeErr.NoBook;

		b = MatchBook(u.getReserved());

		u.clearReserved();

		b.setOwner(null);
		b.setStatus(false);

		this.ResCount--;
		SaveLog(logfile, "[Return] " + b.getISBN() + " by " + u.getUsername() + '\n');
		return TakeErr.Ok;
	}

	/*
	public IOErr CheckFile(String fp) throws IOException
	{
		File fd = new File(fp);

		if(!fd.isFile())
			return IOErr.NotAFile;

		if(!fd.canWrite() || !fd.canRead())
			return IOErr.PermissionDenied;

		return IOErr.Ok;
	}


	public File OpenFile(String fp)
	{
		File fd = new File(fp);
		fd.createNewFile();
		return fd;
	}
	*/

	public void SaveLog(String fp, String in)
	{
		try
		{
			FileWriter fw = new FileWriter(fp, true);
			fw.append(in);
			fw.flush();
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
	}
/*
	public String LoadLog(File fd, int n) throws FileNotFoundException
	{
		int i = n;
		String temp;
		Scanner s = new Scanner(fd);

		while(s.hasNextLine() && i > 0)
		{
			temp += s.nextLine();
			i--;
		}
		return temp;
	}

	public void SaveState(File fd) throws IOException
	{
		FileWriter fw = new FileWriter(fd, false);

		for(Book i : BookList.values())
		{
			for(BookAttr a : i.toMap().keySet())
					fw.append(i.toMap().get(a) + '\n');
		}
		fw.flush();
	}

	public void LoadState(File fd) throws FileNotFoundException
	{
		int agegroup;
		String isbn, name, author, abs;
		Scanner s = new Scanner(fd);

		while(!s.hasNextLine())
		{
			isbn = s.nextLine();
			name = s.nextLine();
			author = s.nextLine();
			agegroup = s.nextInt();
			s.nextLine();
			abs = s.nextLine();
		}
		NewBook(isbn, name, author, agegroup, abs);
	}
*/

class conUI implements UI
{
	public void Program()
	{
		while(true)
		{
			/* there is no admin! */
			if(AdminList.size() == 0)
				AddAdmin();
			else
				this.LoginMenu();
		}
	}

	public void LoginMenu()
	{
		String un, pass;

		System.out.print("Login> ");
		un = GetUsername();

		if(CheckAdmin(un))
		{	
			pass = this.GetPassword();

			Admin a = MatchAdmin(un);
			if(Login(a, pass))
			{
				System.out.println("Auth as " + a.getUsername() + " sucessful");
				this.Menu(adm);
			}
			else
			{
				System.out.println("Auth fail");
				this.LoginMenu();
			}
		}
		else if(CheckUser(un))
		{
			User u = MatchUser(un);
			if(Login(u))
			{
				System.out.println("Login sucessful");
				this.Menu(usr);
			}
		}
		else
		{
			/* fool em! */
			this.GetPassword();
			System.out.println("Auth fail");
			this.LoginMenu();
		}
	}

	/* checks if password is valid, kinda like login */
	public boolean AskPass(Admin u)
	{
		String pass;
		System.out.println("Enter " + u.getUsername() + "'s password:");
		return u.checkPass(GetPassword());
	}

	public void Menu(Admin a)
	{
		int in;
		Scanner s = new Scanner(System.in);
		System.out.println("Welcome, " + a.getUsername() + "!");
		while(true)
		{
			System.out.print(
			"\n" +
			" 1) add admin\n" +
			" 2) add user\n" +
			" 3) add book\n\n" +

			" 4) search admin\n" +
			" 5) search user\n" +
			" 6) search book\n\n" +

			" 7) list admin\n" +
			" 8) list user\n" +
			" 9) list book\n\n" +

			"10) delete admin\n" +
			"11) delete user\n" +
			"12) delete book\n\n" +

			"13) take book\n" +
			"14) return book\n\n" +

			"15) logout\n");

			System.out.print("Admin Menu> ");
			while(!s.hasNextInt())
			{
				System.err.print("Please enter a valid input");
				s.nextLine();
				System.out.print("Admin Menu> ");
			}
			in = s.nextInt();
			s.nextLine();

			switch(in)
			{
				case 1:
					if(this.AskPass(adm))
						this.AddAdmin();
					else
						System.err.println("Incorrect Password.");
					break;
				case 2:
					if(this.AskPass(adm))
						this.AddUser();
					else
						System.err.println("Incorrect Password.");
					break;
				case 3:
					this.AddBook();
					break;
				case 4:
					this.SearchAdmin();
					break;
				case 5:
					this.SearchUser();
					break;
				case 6:
					this.SearchBook();
					break;
				case 7:
					this.ListAdmin();
					break;
				case 8:
					this.ListUser();
					break;
				case 9:
					this.ListBook();
					break;

				case 10:
					System.out.println("This action requires admin password");
					if(this.AskPass(adm)) /* current admin */
						this.RemAdmin();
					else
						System.err.println("Incorrect Password.");
					break;

				case 11:
					System.out.println("This action requires admin password");
					if(this.AskPass(adm)) /* current admin */
						this.RemUser();
					else
						System.err.println("Incorrect Password.");
					break;
				case 12:
					this.RemBook();
					break;

				case 13:
					this.TakeMenu(adm);
					break;
				case 14:
					this.ReturnMenu(adm);
					break;

				case 15:
					System.out.println("Logging out...");
					Logout(adm);
					return;
				/* quit */
				case 99:
						System.out.print("Quit> Are you sure? (y/N)> ");
						if(s.nextLine().equals("y"))
							System.exit(0);
						break;
				default:
					System.out.println("Invalid answer!, please try again.");
					break;
			}
		}
	}

	public void Menu(User u)
	{
		int in;
		Scanner s = new Scanner(System.in);
		System.out.println("Hello, " + u.getUsername() + "!");
		while(true)
		{
			System.out.print(
			"\n" +
			" 1) search book\n" +
			" 2) list book\n\n" +

			" 3) take book\n" +
			" 4) return book\n\n" +

			" 5) logout\n");

			System.out.print("User Menu> ");
			while(!s.hasNextInt())
			{
				System.err.println("Please enter a valid input");
				System.out.print("User Menu> ");
				s.nextLine();
			}
			in = s.nextInt();
			s.nextLine();

			switch(in)
			{
				case 1:
					this.SearchBook();
					break;
				case 2:
					this.ListBook();
					break;
				case 3:
					this.TakeMenu(usr);
					break;
				case 4:
					this.ReturnMenu(usr);
					break;
				case 5:
					System.out.println("Logging out...");
					Logout(usr);
					return;
				default:
					System.out.println("Invalid answer!, please try again.");
					break;
			}
		}
	}

	public String GetUsername()
	{
		Scanner s = new Scanner(System.in);
		String user;

		do
		{
			System.out.print("Username?> ");
			user = s.nextLine();
		}while(user.contains(" "));

		return user;
	}

	public String GetPassword()
	{
		String pass;

		if(System.console() != null)
		{
			Console c = System.console();
			do
			{
				pass = new String(c.readPassword("Password?> "));
			}while(pass.equals(""));
		}
		else
		{
			/* no console? */
			Scanner s = new Scanner(System.in);
			do
			{
				System.out.print("Password?> ");
				pass = s.nextLine();
			}while(pass.equals(""));
		}

		/* encrypt it! */
		return Integer.toString(pass.hashCode());
	}

	public void SearchAdmin()
	{
		String attr, patt;
		Pattern pattern;
		AdminAttr ua;
		Scanner s = new Scanner(System.in);

		System.out.println("Attr: Username, Reserved, ID, RegTime, Age, Active");
		System.out.print("Find Admin> What?> ");
		attr = s.nextLine();

		if(attr.equalsIgnoreCase("Username"))
			ua = AdminAttr.Username;
		else if(attr.equalsIgnoreCase("Reserved"))
			ua = AdminAttr.Reserved;
		else if(attr.equalsIgnoreCase("ID"))
			ua = AdminAttr.ID;
		else if(attr.equalsIgnoreCase("RegTime"))
			ua = AdminAttr.RegTime;
		else if(attr.equalsIgnoreCase("Active"))
			ua = AdminAttr.Active;
		else
		{
			System.err.println("Invalid Attr");
			return;
		}

		System.out.print("Find Admin> Pattern?> ");
		patt = s.nextLine();
		pattern = Pattern.compile(patt, Pattern.CASE_INSENSITIVE);


		if(FindAdmin(ua, pattern))
		{
				for(AdminAttr i : AdminAttr.values())
					System.out.print(i + " | ");
				System.out.println();

				for(Admin i : AdminQuery)
				{
					for(AdminAttr a : i.toMap().keySet())
						System.out.print(i.toMap().get(a) + " | ");
					System.out.println();
				}
		}
		else
			System.err.println("No match has found");
	}

	public void SearchUser()
	{
		String attr, patt;
		Pattern pattern;
		UserAttr ua;
		Scanner s = new Scanner(System.in);

		System.out.println("Attr: Username, Reserved, ID, RegTime, Age, Active");
		System.out.print("Find User> What?> ");
		attr = s.nextLine();

		if(attr.equalsIgnoreCase("Username"))
			ua = UserAttr.Username;
		else if(attr.equalsIgnoreCase("Reserved"))
			ua = UserAttr.Reserved;
		else if(attr.equalsIgnoreCase("ID"))
			ua = UserAttr.ID;
		else if(attr.equalsIgnoreCase("RegTime"))
			ua = UserAttr.RegTime;
		else if(attr.equalsIgnoreCase("Age"))
			ua = UserAttr.Age;
		else if(attr.equalsIgnoreCase("Active"))
			ua = UserAttr.Active;
		else
		{
			System.err.println("Invalid Attr");
			return;
		}

		System.out.print("Find User> Pattern> ");
		patt = s.nextLine();
		pattern = Pattern.compile(patt, Pattern.CASE_INSENSITIVE);


		if(FindUser(ua, pattern))
		{
				for(UserAttr i : UserAttr.values())
					System.out.print(i + " | ");
				System.out.println();

				for(User i : UserQuery)
				{
					for(UserAttr a : i.toMap().keySet())
						System.out.print(i.toMap().get(a) + " | ");
					System.out.println();
				}
		}
		else
			System.err.println("No match has found");
	}

	public void SearchBook()
	{
		String attr, patt;
		Pattern pattern;
		BookAttr ba;
		Scanner s = new Scanner(System.in);

		System.out.println("Attr: Status, Name, Abstract, ISBN, AgeGroup etc.");
		System.out.print("Find Book> What?> ");
		attr = s.nextLine();

		if(attr.equalsIgnoreCase("ISBN"))
			ba = BookAttr.ISBN;
		else if(attr.equalsIgnoreCase("Status"))
			ba = BookAttr.Status;
		else if(attr.equalsIgnoreCase("Name"))
			ba = BookAttr.Name;
		else if(attr.equalsIgnoreCase("Author"))
			ba = BookAttr.Author;
		else if(attr.equalsIgnoreCase("Abstract"))
			ba = BookAttr.Abstract;
		else if(attr.equalsIgnoreCase("AgeGroup"))
			ba = BookAttr.AgeGroup;
		else
		{
			System.err.println("Invalid Attr");
			return;
		}

		System.out.print("Find Book> Pattern?> ");
		patt = s.nextLine();
		pattern = Pattern.compile(patt, Pattern.CASE_INSENSITIVE);

		if(FindBook(ba, pattern))
		{
			for(BookAttr j : BookAttr.values())
				System.out.print(j + " | ");
			System.out.println();

			for(Book j : BookQuery)
			{
				for(BookAttr a : j.toMap().keySet())
					System.out.print(j.toMap().get(a) + " | ");
				System.out.println();
			}
		}
		else
			System.err.println("No match has found");
	}

	public void AddAdmin()
	{
		/* isn't java wonderful billy? */
		String user, pass;

		System.out.println("Setting up Admin:");

		/* ensure there is no admin with the same username */
		do
		{
			System.out.print("Add Admin> ");
			user = this.GetUsername();

			if(user.equals(""))
				return;
		}while(CheckUser(user) || CheckAdmin(user));

		pass = this.GetPassword();

		NewAdmin(user, pass);
	}

	public void AddUser()
	{
		int age;
		String user;
		Scanner s = new Scanner(System.in);

		System.out.println("Setting up User:");

		/* ensure there is no admin with the same username */
		do
		{
			System.out.print("Add User> ");
			user = this.GetUsername();

			if(user.equals(""))
				return;
		}while(CheckUser(user) || CheckAdmin(user));

		System.out.print("Add User> Age> ");
		while(!s.hasNextInt())
		{
				System.err.println("Please enter a valid input");
				System.out.print("Add User> Age> ");
				s.nextLine();
		}
		age = s.nextInt();

		NewUser(user, age);
	}


	/* make checks better, reject empty input etc,
		regex perhaps? */
	public void AddBook()
	{
		int agegroup;
		String name, isbn, author, abs;
		Scanner s = new Scanner(System.in);

		System.out.print("Book> ISBN?> ");
		isbn = s.nextLine();
		if(isbn.equals(""))
			return;

		System.out.print("Book> Name?> ");
		name = s.nextLine();
		if(name.equals(""))
			return;


		System.out.print("Book> Author?> ");
		author = s.nextLine();
		if(author.equals(""))
			return;

		// XXX on a related note, should i care about dealing with multiline stuff?
		System.out.print("Book> Abstract?> ");
		abs = s.nextLine();
		if(abs.equals(""))
			return;

		do
		{
			System.out.print("Book> Age Group?> ");
			while(!s.hasNextInt())
			{
				System.err.println("Please enter a valid input");
				System.out.print("Book> Age Group?> ");
				s.nextLine();
			}
			agegroup = s.nextInt();
		}while((agegroup > 99) || (agegroup < 2));
		/* ensure it's valid ^ */

		Book b = NewBook(isbn, name, author, agegroup, abs);
	}

	public void RemAdmin()
	{
		String un;
		Scanner s = new Scanner (System.in);

		System.out.print("Remove Admin> Username> ");
		un = s.nextLine();

		if(un.equals(""))
			return;

		if(!CheckAdmin(un))
		{
			System.err.println("No such Admin has found.");
			return;
		}

		if(adm.getUsername().equals(un))
		{
			System.err.println("You can't remove yourself.");
			return;
		}

		System.out.println("Remove Admin> Are you sure? (y/N)> ");
		if(!s.nextLine().equals("y"))
			return;

		Result(DelAdmin(MatchAdmin(un)));
	}

	public void RemUser()
	{
		String un;
		Scanner s = new Scanner (System.in);

		System.out.print("Remove User> Username> ");
		un = s.nextLine();

		if(un.equals(""))
			return;

		if(!CheckUser(un))
		{
			System.err.println("No such user has found.");
			return;
		}

		System.out.println("Remove User> Are you sure? (y/N)> ");
		if(!s.nextLine().equals("y"))
			return;

		Result(DelUser(MatchUser(un)));
	}

	public void RemBook()
	{
		String isbn;
		Scanner s = new Scanner (System.in);

		System.out.print("Remove Book> isbn> ");
		isbn = s.nextLine();

		if(isbn.equals(""))
			return;

		if(!CheckBook(isbn))
		{
			System.err.println("No such book has found.");
			return;
		}

		System.out.println("Remove Book> Are you sure? (y/N)> ");
		if(!s.nextLine().equals("y"))
			return;

		Result(DelBook(isbn));
	}

	public void ListAdmin()
	{
		for(AdminAttr i : AdminAttr.values())
			System.out.print(i + " | ");
		System.out.println();

		for(Admin i : AdminList.values())
		{
			for(AdminAttr a : i.toMap().keySet())
					System.out.print(i.toMap().get(a) + " | ");
			System.out.println();
		}
	}

	public void ListUser()
	{
		for(UserAttr i : UserAttr.values())
			System.out.print(i + " | ");
		System.out.println();

		for(User i : UserList.values())
		{
			for(UserAttr a : i.toMap().keySet())
					System.out.print(i.toMap().get(a) + " | ");
			System.out.println();
		}
	}

	public void ListBook()
	{
		for(BookAttr i : BookAttr.values())
			System.out.print(i + " | ");
		System.out.println();

		for(Book i : BookList.values())
		{
			for(BookAttr a : i.toMap().keySet())
					System.out.print(i.toMap().get(a) + " | ");
			System.out.println();
		}
	}

	public void TakeMenu(Admin a)
	{
		String isbn;
		Scanner s = new Scanner(System.in);

		if(!a.getReserved().isEmpty())
		{
			System.err.println("Current Admin has already has a book (ISBN: " + a.getReserved() + ").");
			return;
		}

		System.out.println("Which book do you want to take? (you may find it's ISBN by Search menu)");
		
		do
		{
			System.out.print("Take> ISBN?> ");
			isbn = s.nextLine();

			if(isbn.equals(""))
				return;

			if(!CheckBook(isbn))
				System.err.println("No such book found, please try again");

		}while(isbn.contains(" ") || !CheckBook(isbn));

		Result(TakeBook(a, MatchBook(isbn)));
	}

	public void TakeMenu(User u)
	{
		String isbn;
		Scanner s = new Scanner(System.in);

		if(!u.getReserved().isEmpty())
		{
			System.err.println("Current User has already has a book (ISBN: " + u.getReserved() + ").");
			return;
		}

		System.out.println("Which book do you want to take? (you may find it's ISBN by Search menu)");
		
		do
		{
			System.out.print("Take> ISBN?> ");
			isbn = s.nextLine();

			if(isbn.equals(""))
				return;

			if(!CheckBook(isbn))
				System.err.println("No such book found, please try again");

		}while(isbn.contains(" ") || !CheckBook(isbn));

		Result(TakeBook(u, MatchBook(isbn)));
	}

	public void ReturnMenu(Admin a)
	{
		Scanner s = new Scanner(System.in);

		if(a.getReserved().isEmpty())
		{
			System.err.println("You have no books reserved.");
			return;
		}

		System.out.print("Return> Are you sure? (y/N)> ");

		if(s.nextLine().equals("y"))
			Result(ReturnBook(a));
		else
			System.out.println("Thought so.");
	}

	public void ReturnMenu(User u)
	{
		Scanner s = new Scanner(System.in);

		if(u.getReserved().isEmpty())
		{
			System.err.println("You have no books reserved.");
			return;
		}

		System.out.print("Return> Are you sure (y/N)?> ");

		if(s.nextLine().equals("y"))
			Result(ReturnBook(u));
		else
			System.out.println("Thought so.");
	}

	public void Result(TakeErr res)
	{
		switch(res)
		{
			case NoBook:
				System.err.println("No such book has found");
				break;
			case BookReserved:
				System.err.println("This book is reserved by someone else");
				break;
			case NoBookReserved:
				System.err.println("No book is reserved");
				break;
			case NoUser:
				System.err.println("No such User has found");
				break;
			case UserHasABook:
				System.err.println("User has already reserved a book");
				break;
			case Age:
				System.err.println("Age doesn't match!");
				break;
			case Ok:
				System.out.println("Done!");
				break;
			default:
				throw new IllegalStateException("Invalid TakeErr");
		}
	}

	public void Result(DelErr res)
	{
		switch(res)
		{
			case UserHasABook:
				System.err.println("User has reserve a book, return it");
				break;
			case BookReserved:
				System.err.println("This book is reserved by someone else");
				break;
			case NoBook:
				System.err.println("No such book has found");
				break;
			case NoUser:
				System.err.println("No such user has found");
				break;
			case Ok:
				System.out.println("Done!");
				break;
			default:
				throw new IllegalStateException("Invalid DelErr");
		}
	}

	public void Result(IOErr res)
	{
		switch(res)
		{
			case NotAFile:
				System.err.println("Not a File");
				break;
			case PermissionDenied:
				System.err.println("Permission denied");
				break;
			case Ok:
				System.out.println("Done!");
				break;
			default:
				throw new IllegalStateException("Invalid TakeErr");
		}
	}

} /* end of conUI */
}

public class Main
{
	public static void main(String args[])
	{
		Lib l = new Lib();
		Lib.UI ui = l.new conUI();
		ui.Program();
	}
}