/* ************************************************************************
#
#  DivConq
#
#  http://divconq.com/
#
#  Copyright:
#    Copyright 2012 eTimeline, LLC. All rights reserved.
#
#  License:
#    See the license.txt file in the project's top-level directory for details.
#
#  Authors:
#    * Andy White
#
************************************************************************ */
package divconq.test;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Scanner;

import divconq.db.CustomResult;
import divconq.db.DatabaseResult;
import divconq.db.EchoRequest;
import divconq.db.IDatabaseCallback;
import divconq.db.IDatabaseRequest;
import divconq.db.ObjectCallback;
import divconq.db.ObjectResult;
import divconq.db.PingRequest;
import divconq.db.QueryRequest;
import divconq.db.common.AddGroupRequest;
import divconq.db.common.AddUserRequest;
import divconq.db.common.InitiateRecoveryRequest;
import divconq.db.common.SignOffRequest;
import divconq.db.common.SignOnRequest;
import divconq.db.common.StartSessionRequest;
import divconq.db.common.UpdateGroupRequest;
import divconq.db.common.UpdateUserRequest;
import divconq.db.common.UserNameLookupRequest;
import divconq.db.common.VerifySessionRequest;
import divconq.db.query.CollectorField;
import divconq.db.query.LoadRecordRequest;
import divconq.db.query.SelectComposer;
import divconq.db.query.SelectDirectRequest;
import divconq.db.query.SelectField;
import divconq.db.query.SelectFields;
import divconq.db.query.SelectForeignField;
import divconq.db.query.SelectRequest;
import divconq.db.query.SelectReverseForeignField;
import divconq.db.update.DynamicListField;
import divconq.db.update.RetireRecordRequest;
import divconq.db.update.ReviveRecordRequest;
import divconq.db.update.UpdateRecordRequest;
import divconq.lang.BigDateTime;
import divconq.lang.Hub;
import divconq.lang.HubResources;
import divconq.lang.OperationResult;
import divconq.lang.TaskContext;
import divconq.log.DebugLevel;
import divconq.log.Logger;
import divconq.struct.CompositeStruct;
import divconq.struct.ListStruct;
import divconq.struct.RecordStruct;
import divconq.struct.builder.BuilderStateException;
import divconq.struct.builder.JsonStreamBuilder;
import divconq.struct.builder.YamlStreamBuilder;
import divconq.util.StringUtil;

public class TestDb {
	public static void main(String[] args) {
		HubResources resources = new HubResources("00101", true);
		resources.setDebugLevel(DebugLevel.Info);
		OperationResult or = resources.init();
		
		if (or.hasErrors()) {
			Logger.error("Unable to continue, hub resources not properly configured");
			return;
		}
	
		Hub.instance.start(resources);
		
		TaskContext tc = TaskContext.useNewRoot();
		
		/* TODO clean up
		LoadRecordRequest lrr = new LoadRecordRequest(
				"dcUser", 
				"997753311", 
				new SelectFields(
						new SelectField("SSN"),
						new SelectField("Sex", "Tr", "Gender"),
						new SelectSubquery(
								"Department", 
								new SelectField("Name"),
								new SelectField("Area", null, "Gender")
						)
				), 
				"dcUserFilter", 
				new RecordStruct(new FieldStruct("Mode", "ReadOnly"))
		);
		
		TestDb.printPretty(lrr.getDatabaseParams());
		*/
		
		Scanner scan = new Scanner(System.in);
		boolean running = true;
		
		while(running) {
			try {
				System.out.println();
				System.out.println("-----------------------------------------------");
				System.out.println("   Test dcDb Connector Menu");
				System.out.println("-----------------------------------------------");
				System.out.println("0)  Exit");
				System.out.println("1)  Ping");
				System.out.println("2)  Echo with user input");
				System.out.println("3)  Echo with hardcoded international chars");
				System.out.println("4)  Load stored proc results (testProc1)");
				System.out.println("5)  Check validity of toy list (testProc2)");
				System.out.println("6)  Check validity of toy list (testProc3)");
				System.out.println("7)  Switch Locale");
				System.out.println("8)  Toy Database Example");
				System.out.println("9)  Test Result Fail");
				System.out.println("10) Test Connection Fail");
				System.out.println("11) Test Connection Reset");
				System.out.println("12) Test Connection Hang Up");
				System.out.println("13) User Functions");
				System.out.println("14) Group Functions");

				String opt = scan.nextLine();
				
				Long mopt = StringUtil.parseInt(opt);
				
				if (mopt == null)
					continue;
				
				switch (mopt.intValue()) {
				case 0:
					running = false;
					break;
					
				case 1:
					PingRequest p = new PingRequest();
					Hub.instance.getDatabase().submit(p, new TestCallback(p));
					
					break;
				case 2:
					System.out.print("Enter text to echo: ");
					opt = scan.nextLine();
					
					EchoRequest er = new EchoRequest(opt);
					Hub.instance.getDatabase().submit(er, new TestCallback(er));
					
					break;
				case 3:
					EchoRequest er2 = new EchoRequest("Hello there! - à¤ à¥€ á‰» âŒ† ï¨¬");
					Hub.instance.getDatabase().submit(er2, new TestCallback(er2));
					
					break;
					
				case 4:
					QueryRequest tp1 = new QueryRequest("testProc1", null);
					Hub.instance.getDatabase().submit(tp1, new TestCallback(tp1));
					
					break;
					
				case 5:
					ListStruct toys = new ListStruct();
					
					System.out.println("Enter toys, one per line.  Empty to finish.");
					opt = scan.nextLine();
					
					while (StringUtil.isNotEmpty(opt)) {
						toys.addItem(opt);
						opt = scan.nextLine();
					}
					
					QueryRequest tp2 = new QueryRequest("testProc2", toys);
					
					Hub.instance.getDatabase().submit(tp2, new TestCallback(tp2));
					
					break;
					
				case 6:
					ListStruct toys3 = new ListStruct();
					
					System.out.println("Enter toys, one per line.  Empty to finish.");
					opt = scan.nextLine();
					
					while (StringUtil.isNotEmpty(opt)) {
						toys3.addItem(opt);
						opt = scan.nextLine();
					}
					
					QueryRequest tp3 = new QueryRequest("testProc3", toys3);
					
					Hub.instance.getDatabase().submit(tp3, new TestCallback(tp3));
					
					break;
					
				case 7:
					System.out.print("Enter new locale: ");
					opt = scan.nextLine();
					tc.setLocale(opt);
					break;
					
				case 8:
					TestDb.toyDb(tc, scan);
					break;
					
				case 9:
					QueryRequest tp9 = new QueryRequest("dcFailResultTest", null);
					Hub.instance.getDatabase().submit(tp9, new TestCallback(tp9));
					break;
					
				case 10:
					QueryRequest tp10 = new QueryRequest("dcFailCallTest", null);
					Hub.instance.getDatabase().submit(tp10, new TestCallback(tp10));					
					break;
					
				case 11:
					Hub.instance.getDatabase().resetConnections();					
					break;
					
				case 12:
					QueryRequest tp12 = new QueryRequest("dcFailHungUpTest", null);
					Hub.instance.getDatabase().submit(tp12, new TestCallback(tp12));					
					break;
					
				case 13:
					TestDb.userStuff(scan);
					break;
					
				case 14:
					TestDb.groupStuff(scan);
					break;
				}
			}
			catch(Exception x) {
				System.out.println("CLI error: " + x);
			}
		}		
				
		Hub.instance.stop();
	}
	
	public static void toyDb(TaskContext tc, Scanner scan) {
		System.out.println("-----------------------------------------------");
		System.out.println("   Toy Database Instructions");
		System.out.println("-----------------------------------------------");
		System.out.println("To run this example please run setup^dctToyTest first.");
		System.out.println("The call to setup populates some data for this example.");
		System.out.println("When done with the example you may run cleanup^dcToyTest.");
		System.out.println();
		
		boolean running = true;
		
		while(running) {
			try {
				System.out.println();
				System.out.println("-----------------------------------------------");
				System.out.println("   Toy Database Menu");
				System.out.println("-----------------------------------------------");
				System.out.println("0)  Main Menu");
				System.out.println("1)  List People Names");
				System.out.println("2)  List Toys");
				System.out.println("3)  List People in Tabular");
				System.out.println("4)  List People in Complex");
				System.out.println("5)  List People directly to file (Json)");
				System.out.println("6)  List People directly to file (Yaml)");
				System.out.println("7)  Add Person");

				String opt = scan.nextLine();
				
				Long mopt = StringUtil.parseInt(opt);
				
				if (mopt == null)
					continue;
				
				switch (mopt.intValue()) {
				case 0:
					running = false;
					break;
					
				case 1:	
					RecordStruct ages = new RecordStruct();
					
					System.out.print("MinAge filter [empty for no filter]: ");
					
					opt = scan.nextLine();					
					if (StringUtil.isNotEmpty(opt))
						ages.setField("MinAge", opt);
					
					System.out.print("MaxAge filter [empty for no filter]: ");
					
					opt = scan.nextLine();					
					if (StringUtil.isNotEmpty(opt))
						ages.setField("MaxAge", opt);
					
					QueryRequest lpr = new QueryRequest("dctListPeople", ages);
					
					Hub.instance.getDatabase().submit(lpr, new TestCallback(lpr));
					
					break;
					
				case 2:	
					RecordStruct searchp = new RecordStruct();
					
					System.out.print("Search filter [empty for no filter]: ");
					searchp.setField("Search", scan.nextLine());
					
					searchp.setField("X", StringUtil.buildSecurityCode(4000 - 3) + "zzz");
					
					QueryRequest ltr = new QueryRequest("dctListToys", searchp);
					
					Hub.instance.getDatabase().submit(ltr, new TestCallback(ltr));
					
					break;
					
				case 3:	
					QueryRequest tpr = new QueryRequest("dctTablePeople", null);
					
					Hub.instance.getDatabase().submit(tpr, new TestCallback(tpr));
					
					break;
					
				case 4:	
					QueryRequest gpr = new QueryRequest("dctGetPeople", null);
					
					Hub.instance.getDatabase().submit(gpr, new TestCallback(gpr));
					
					break;
					
				case 5:	
					QueryRequest gpr2 = new QueryRequest("dctGetPeople", null);
					
					new File("./files").mkdirs(); 
					
					final FileOutputStream fos = new FileOutputStream("./files/people.json");
					
					JsonStreamBuilder jsb = new JsonStreamBuilder(new PrintStream(fos), true);
					CustomResult json = new CustomResult(jsb);
					
					Hub.instance.getDatabase().submit(gpr2, json, new IDatabaseCallback() {
						@Override
						public void process(DatabaseResult res) {
							if (res.hasErrors()) {
								System.out.println(" People save error:");
								TestDb.printPretty(res.getMessages());
							}
							else  {
								System.out.println(" People saved to file: ./files/people.json");
							}
							
							try {
								fos.flush();
								fos.close();
							} 
							catch (IOException x) {
								System.out.println("Error closing file: " + x);
							}
						}
					});
					
					break;
					
				case 6:	
					QueryRequest gpr3 = new QueryRequest("dctGetPeople", null);
					
					final FileOutputStream fos3 = new FileOutputStream("./files/people.yaml");
					
					YamlStreamBuilder jsb3 = new YamlStreamBuilder(new PrintStream(fos3));
					CustomResult yaml = new CustomResult(jsb3);
					
					Hub.instance.getDatabase().submit(gpr3, yaml, new IDatabaseCallback() {
						@Override
						public void process(DatabaseResult res) {
							if (res.hasErrors()) {
								System.out.println(" People save error:");
								TestDb.printPretty(res.getMessages());
							}
							else  {
								System.out.println(" People saved to file: ./files/people.yaml");
							}
							
							try {
								fos3.flush();
								fos3.close();
							} 
							catch (IOException x) {
								System.out.println("Error closing file: " + x);
							}
						}
					});
					
					break;
					
				case 7:
					RecordStruct person = new RecordStruct();
					
					System.out.print("Name: ");
					person.setField("Name", scan.nextLine());
					
					System.out.print("Age: ");
					person.setField("Age", scan.nextLine());
					
					// add toys
					ListStruct toys3 = new ListStruct();
					
					System.out.println("Enter toys, one per line.  Empty to finish.");
					opt = scan.nextLine();
					
					while (StringUtil.isNotEmpty(opt)) {
						toys3.addItem(opt);
						opt = scan.nextLine();
					}
					
					person.setField("Toys", toys3);
					
					// add fiends
					ListStruct friends = new ListStruct();
					
					System.out.println("Enter the ids of friends, one per line.  Empty to finish.");
					opt = scan.nextLine();
					
					while (StringUtil.isNotEmpty(opt)) {
						friends.addItem(opt);
						opt = scan.nextLine();
					}
					
					person.setField("Friends", friends);
					
					// submit request
					QueryRequest tp3 = new QueryRequest("dctAddPerson", person);
					
					Hub.instance.getDatabase().submit(tp3, new TestCallback(tp3));
					
					break;
				}
						
			}
			catch(Exception x) {
				System.out.println("CLI error: " + x);
			}
		}		
	}
	
	static public void userStuff(Scanner in) {
		boolean running = true;
		
		while(running) {
			System.out.println();
			System.out.println("-----------------------------------------------");
			System.out.println("   User Menu");
			System.out.println("-----------------------------------------------");
			System.out.println("0)  Return to main menu");
			System.out.println("1)  Add User Account");
			System.out.println("2)  Update User Account");
			System.out.println("3)  View User Account");
			System.out.println("4)  Retire User Account");
			System.out.println("5)  Revive User Account");
			System.out.println("6)  List Users");
			System.out.println("7)  Test Sign On");
			System.out.println("8)  Test Sign Off");
			System.out.println("9)  Verify Session");
			System.out.println("10) Request Password Assistance");
			System.out.println("11) Lookup User Name");
			System.out.println("12) Start Session, bypass Authentication");

			String opt = in.nextLine();
			
			Long mopt = StringUtil.parseInt(opt);
			
			if (mopt == null)
				continue;
			
			switch (mopt.intValue()) {
			case 0:
				running = false;
				break;
				
			case 1: {
				RecordStruct record = new RecordStruct();				
				
				System.out.print("First Name: ");
				String fname = in.nextLine();
				record.setField("dcFirstName", fname);
				
				System.out.print("Last Name: ");
				String lname = in.nextLine();
				record.setField("dcLastName", lname);
				
				System.out.print("Email: ");
				String email = in.nextLine();
				record.setField("dcEmail", email);
				record.setField("dcUserName", email);
				
				System.out.print("Password: ");
				String pass = in.nextLine();
				record.setField("dcPassword", pass);
				
				System.out.print("Locale [optional]: ");
				String locale = in.nextLine();
				
				if (!locale.isEmpty())
					record.setField("dcLocale", locale);
				
				System.out.print("ISO TimeZone [optional]: ");
				String tzone = in.nextLine();
				
				if (!tzone.isEmpty())
					record.setField("dcChronology", "/" + tzone);
				
				ListStruct atags = new ListStruct();
				
				System.out.println("Add Authorization Tags");
				System.out.println("(empty entry to finish)");
				
				while (true) {
					System.out.print("Tag (Admin, SysAdmin, etc): ");
					String tag = in.nextLine();
					
					if (StringUtil.isEmpty(tag))
						break;
					
					atags.addItem(tag);
				}
				
				if (atags.getSize() > 0)
					record.setField("dcAuthorizationTag", atags);				
				
				AddUserRequest req = new AddUserRequest(record);
				req.setConfirmed(true);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));
				
				break;
			}
			
			case 2: {
				RecordStruct record = new RecordStruct();				
				
				System.out.print("User Id: ");
				String uid = in.nextLine();
				
				if (StringUtil.isEmpty(uid))
					break;

				System.out.println();
				System.out.println("For any of the following prompts, entering a * means skip this value.");
				
				System.out.print("First Name: ");
				String fname = in.nextLine();
				
				if (!"*".equals(fname))
					record.setField("dcFirstName", fname);
				
				System.out.print("Last Name: ");
				String lname = in.nextLine();
				
				if (!"*".equals(lname))
					record.setField("dcLastName", lname);
				
				System.out.print("Email: ");
				String email = in.nextLine();
				
				if (!"*".equals(email)) {
					record.setField("dcEmail", email);
					record.setField("dcUserName", email);
				}
				
				System.out.print("Password: ");
				String pass = in.nextLine();
				
				if (!"*".equals(pass))
					record.setField("dcPassword", pass);
				
				System.out.print("Locale: ");
				String locale = in.nextLine();
				
				if (!"*".equals(locale))
					record.setField("dcLocale", locale);
				
				System.out.print("ISO Time Zone: ");
				String tzone = in.nextLine();
				
				if (!"*".equals(tzone))
					record.setField("dcChronology", StringUtil.isNotEmpty(tzone) ?  "/" + tzone : null);
				
				ListStruct atags = new ListStruct();
				
				System.out.println("Add Authorization Tags");
				System.out.println("(empty entry to finish, no way to remove tags on this prompt)");
				
				while (true) {
					System.out.print("Tag (Admin, SysAdmin, etc): ");
					String tag = in.nextLine();
					
					if (StringUtil.isEmpty(tag))
						break;
					
					atags.addItem(tag);
				}
				
				if (atags.getSize() > 0)
					record.setField("dcAuthorizationTag", atags);				
				
				UpdateUserRequest req = new UpdateUserRequest(uid, record);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));
				
				break;
			}
			
			case 3: {
				System.out.print("User Id: ");
				String uid = in.nextLine();
				
				if (StringUtil.isEmpty(uid))
					break;
				
				LoadRecordRequest req = new LoadRecordRequest("dcUser", uid,  
						new SelectFields(
								new SelectField("Id"),
								new SelectField("dcUserName", "UserName"),
								new SelectField("dcFirstName", "FirstName"),
								new SelectField("dcLastName", "LastName"),
								new SelectForeignField("dcGroup", "dcName", "Groups"),
								new SelectField("dcEmail", "Email"),
								new SelectField("dcLocale", "Locale"),
								new SelectField("dcChronology", "Chronology"),
								new SelectComposer("dcAuthorizationTags", "AuthorizationTags")
						)
				);
				
				req.setCompact(true);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));						
				break;
			}
			
			case 4: {
				System.out.print("User Id: ");
				String uid = in.nextLine();
				
				if (StringUtil.isEmpty(uid))
					break;
				
				RetireRecordRequest req = new RetireRecordRequest("dcUser", uid);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));						
				break;
			}
			
			case 5: {
				System.out.print("User Id: ");
				String uid = in.nextLine();
				
				if (StringUtil.isEmpty(uid))
					break;
				
				ReviveRecordRequest req = new ReviveRecordRequest("dcUser", uid);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));						
				break;
			}
			
			case 6:	{
				SelectFields selt = new SelectFields(
						new SelectField("Id"),
						new SelectField("dcUserName", "UserName"),
						new SelectField("dcFirstName", "FirstName"),
						new SelectField("dcLastName", "LastName"),
						new SelectField("dcEmail", "Email"),
						new SelectComposer("dcAuthorizationTags", "AuthorizationTags")
				);
				
				SelectDirectRequest req = new SelectDirectRequest("dcUser", selt);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));						
				
				break;
			}
			
			case 7: {
				System.out.println("Enter User Name plus:");
				System.out.println("1) Password for regular sign on ");
				System.out.println("2) Password and confirm code for first sign on ");
				System.out.println("3) Recovery code for recovery sign on");
				System.out.println();
				
				System.out.print("User Name: ");
				String uname = in.nextLine();
				
				System.out.print("Password: ");
				String pwd = in.nextLine();
				
				System.out.print("Code: ");
				String code = in.nextLine();
				
				SignOnRequest req = new SignOnRequest(uname);
				
				if (StringUtil.isNotEmpty(pwd))
					req.setPassword(pwd);
				
				if (StringUtil.isNotEmpty(code))
					req.setCode(code);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));
				
				break;
			}
			
			case 8: {
				System.out.print("AuthToken: ");
				String token = in.nextLine();
				
				if (StringUtil.isEmpty(token))
					break;
				
				SignOffRequest req = new SignOffRequest(token);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));
				
				break;
			}
			
			case 9: {
				System.out.print("User Id: ");
				String uid = in.nextLine();
				
				if (StringUtil.isEmpty(uid))
					break;
				
				System.out.print("AuthToken: ");
				String token = in.nextLine();
				
				if (StringUtil.isEmpty(token))
					break;
				
				VerifySessionRequest req = new VerifySessionRequest(uid, token);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));
				
				break;
			}
			
			case 10: {
				System.out.print("User Name: ");
				String uname = in.nextLine();
				
				if (StringUtil.isEmpty(uname))
					break;
				
				final InitiateRecoveryRequest req = new InitiateRecoveryRequest(uname);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req) {
					@Override
					public void process(ObjectResult res) {
						super.process(res);
						
						if (!res.hasErrors()) {
							System.out.println();
							System.out.println("Recovery code: " + req.getCode());
						}
					}
				});
				
				break;
			}
			
			case 11: {
				System.out.print("User Name: ");
				String uname = in.nextLine();
				
				if (StringUtil.isEmpty(uname))
					break;
				
				UserNameLookupRequest req = new UserNameLookupRequest(uname);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));						
				break;
			}
			
			case 12: {
				System.out.print("User Name: ");
				String uname = in.nextLine();
				
				if (StringUtil.isEmpty(uname))
					break;
				
				StartSessionRequest req = new StartSessionRequest();
				req.setUserName(uname);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));						
				break;
			}
			
			}
		}		
	}
	
	static public void groupStuff(Scanner in) {
		boolean running = true;
		
		while(running) {
			System.out.println();
			System.out.println("-----------------------------------------------");
			System.out.println("   Group Menu");
			System.out.println("-----------------------------------------------");
			System.out.println("0)  Return to main menu");
			System.out.println("1)  Add Group");
			System.out.println("2)  Update Group");
			System.out.println("3)  View Group");
			System.out.println("4)  Retire Group");
			System.out.println("5)  Revive Group");
			System.out.println("6)  List Groups");
			System.out.println("7)  Add User to Group");
			System.out.println("8)  Remove User from Group");

			String opt = in.nextLine();
			
			Long mopt = StringUtil.parseInt(opt);
			
			if (mopt == null)
				continue;
			
			switch (mopt.intValue()) {
			case 0:
				running = false;
				break;
				
			case 1: {
				RecordStruct record = new RecordStruct();				
				
				System.out.print("Name: ");
				String name = in.nextLine();
				record.setField("dcName", name);
				
				ListStruct atags = new ListStruct();
				
				System.out.println("Add Authorization Tags");
				System.out.println("(empty entry to finish)");
				
				while (true) {
					System.out.print("Tag (Admin, SysAdmin, etc): ");
					String tag = in.nextLine();
					
					if (StringUtil.isEmpty(tag))
						break;
					
					atags.addItem(tag);
				}
				
				if (atags.getSize() > 0)
					record.setField("dcAuthorizationTag", atags);				
				
				AddGroupRequest req = new AddGroupRequest(record);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));
				
				break;
			}
			
			case 2: {
				RecordStruct record = new RecordStruct();				
				
				System.out.print("Group Id: ");
				String gid = in.nextLine();
				
				if (StringUtil.isEmpty(gid))
					break;

				System.out.println();
				System.out.println("For any of the following prompts, entering a * means skip this value.");
				
				System.out.print("Name: ");
				String name = in.nextLine();
				
				if (!"*".equals(name))
					record.setField("dcName", name);
				
				ListStruct atags = new ListStruct();
				
				System.out.println("Add Authorization Tags");
				System.out.println("(empty entry to finish, no way to remove tags on this prompt)");
				
				while (true) {
					System.out.print("Tag (Admin, SysAdmin, etc): ");
					String tag = in.nextLine();
					
					if (StringUtil.isEmpty(tag))
						break;
					
					atags.addItem(tag);
				}
				
				if (atags.getSize() > 0)
					record.setField("dcAuthorizationTag", atags);				
				
				UpdateGroupRequest req = new UpdateGroupRequest(gid, record);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));
				
				break;
			}
			
			case 3: {
				System.out.print("Group Id: ");
				String gid = in.nextLine();
				
				if (StringUtil.isEmpty(gid))
					break;
				
				LoadRecordRequest req = new LoadRecordRequest("dcGroup", gid,  
						new SelectFields(
								new SelectField("Id"),
								new SelectField("dcName", "Name"),
								new SelectReverseForeignField("dcUser", "dcGroup", "dcUserName", "Users"),
								new SelectField("dcAuthorizationTag", "AuthorizationTags")
						)
				);
				
				//req.setCompact(true);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));						
				break;
			}
			
			case 4: {
				System.out.print("Group Id: ");
				String gid = in.nextLine();
				
				if (StringUtil.isEmpty(gid))
					break;
				
				RetireRecordRequest req = new RetireRecordRequest("dcGroup", gid);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));						
				break;
			}
			
			case 5: {
				System.out.print("Group Id: ");
				String gid = in.nextLine();
				
				if (StringUtil.isEmpty(gid))
					break;
				
				ReviveRecordRequest req = new ReviveRecordRequest("dcGroup", gid);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));						
				break;
			}
			
			case 6:	{
				System.out.print("From Name: ");
				String from = in.nextLine();
				
				System.out.print("To Name: ");
				String to = in.nextLine();
				
				SelectFields selt = new SelectFields(
						new SelectField("Id"),
						new SelectField("dcName", "Name"),
						new SelectReverseForeignField("dcUser", "dcGroup", "dcUserName", "Users"),
						new SelectField("dcAuthorizationTag", "AuthorizationTags")
				);
				
				SelectRequest req = new SelectRequest("dcGroup", selt, null, null, new CollectorField("dcName", from, to));
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));						
				
				break;
			}
			
			case 7: {
				System.out.print("User Id: ");
				String uid = in.nextLine();
				
				if (StringUtil.isEmpty(uid))
					break;
				
				System.out.print("Group Id: ");
				String gid = in.nextLine();
				
				if (StringUtil.isEmpty(gid))
					break;
				
				UpdateRecordRequest req = new UpdateRecordRequest("dcUser", uid,
						new DynamicListField("dcGroup", gid, gid, BigDateTime.nowDateTime())
				);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));
				
				break;
			}
			
			case 8: {
				System.out.print("User Id: ");
				String uid = in.nextLine();
				
				if (StringUtil.isEmpty(uid))
					break;
				
				System.out.print("Group Id: ");
				String gid = in.nextLine();
				
				if (StringUtil.isEmpty(gid))
					break;
				
				UpdateRecordRequest req = new UpdateRecordRequest("dcUser", uid,
						new DynamicListField("dcGroup", gid)
				);
				
				Hub.instance.getDatabase().submit(req, new TestCallback(req));
				
				break;
			}
			
			}
		}		
	}
	
	static public void printPretty(CompositeStruct struct) {
		if (struct != null)
			try {
				struct.toBuilder(new JsonStreamBuilder(System.out, true));
			} 
			catch (BuilderStateException x) {
				System.out.println("Error printing structure: " + x);
			}
		else
			System.out.println("[null]");
		
		System.out.println();
	}
	
	static public class TestCallback extends ObjectCallback {
		protected String name = null;

		public TestCallback(IDatabaseRequest req) {
			this.name = req.getProcedure();
		}
		
		@Override
		public void process(ObjectResult res) {
			if (res.hasErrors()) {
				System.out.println(this.name + " Error:");
				TestDb.printPretty(res.getMessages());
			}
			else  {
				System.out.println(this.name + " Messages:");
				TestDb.printPretty(res.getMessages());
				System.out.println();
				System.out.println(this.name + " Response:");
				TestDb.printPretty(res.getResult());
			}
		}
	}
}
