using System;
using Plumtree.Remote.PRC;

using Plumtree.Remote.PRC.Collaboration;
using Plumtree.Remote.PRC.Collaboration.Project;
using System.Collections;
using System.Text;



namespace TestProject
{
	/**
	 * Simple command line example which demonstrates creating a project,
	 * searching for a project, removing a project, and setting some project properties
	 */
	public class ProjectCommandLineExample
	{

		//constants for endpoint, username, password and other command line args
		public static readonly String ENDPOINT = "-endpoint";
		public static readonly String USERNAME = "-username";
		public static readonly String PASSWORD = "-password";
		public static readonly String PROJECT_NAME = "-n";
		public static readonly String PROJECT_DESCRIPTION = "-d";
		public static readonly String PROJECT_ID = "-id";
		public static readonly String CREATE = "-c";
		public static readonly String REMOVE = "-r";
		public static readonly String SEARCH = "-s";
		public static readonly String SEARCH_QUERY = "-q";


		public static void Main(String[] args)
		{
			//make the arguments into a hashtable
			Hashtable argsMap = parseParameters(args);

			//get a remote session using the soap endpoint, username, and password
			System.Uri endpoint = (Uri) argsMap[ENDPOINT];
			String username = (String) argsMap[USERNAME];
			String password = (String) argsMap[PASSWORD];
			IRemoteSession session =
				RemoteSessionFactory.GetExplicitLoginContext(endpoint,
				username,
				password);

			//get a collab factory and a project manager
			ICollaborationFactory collabFactory = session.GetCollaborationFactory();
			IProjectManager projectManager = collabFactory.GetProjectManager();

			//create, remove, search as specified by the client.
			if (argsMap.ContainsKey(CREATE))
			{
				createProject(projectManager, argsMap);
				return;
			}
			else if (argsMap.ContainsKey(REMOVE))
			{
				//get the id- squawk if it does not exist
				String projectStr = (String)argsMap[PROJECT_ID];
				int projectInteger = Int32.Parse(projectStr);
				if (projectInteger <= 0)
				{
					Console.WriteLine("Project cannot be removed without a project ID");
					return;
				}
				removeProject(projectManager, projectInteger);
				return;
			}
			else if (argsMap.ContainsKey(SEARCH))
			{
				String query = (String) argsMap[SEARCH_QUERY];
				query = (null == query) ? "" : query;
				searchProjects(projectManager, query);

			}

		}

		//creates a project
		public static void createProject(IProjectManager projectManager, Hashtable argsMap)
		{
			//see if we have a name and description
			String name = (String) argsMap[PROJECT_NAME];
			//set to a default value if there is no name
			name = (null == name) ? "ExampleProject" : name;
			String description = (String) argsMap[PROJECT_DESCRIPTION];
			description = (null == description) ? "ExampleProjectDescription" : description;

			//create the project
			IProject project =
				projectManager.CreateProject(name, description);

			//if you want to set additional properties, make sure that store() is called or the changes will not be persisted.
			//for example:
			/*
			project.SetStatus(ProjectStatus.NotStarted);
			project.SetStartDate(new Date());
			*/
			//store the project to get the ID
			project.Store();

			Console.WriteLine("ID of newly created project is " + project.ID);
		}

		//removes a project
		public static void removeProject(IProjectManager projectManager, int projectID) 
		{
			//retrieve the project
			IProject project = projectManager.GetProject(projectID);
			//squawk if the project could not be retrieved
			if (null == project)
			{
				Console.WriteLine("Unable to retrieve project with ID of " + projectID);
				return;
			}
			//remove
			projectManager.RemoveProject(project);
			Console.WriteLine("Project with id of " + projectID + " removed.");
		}


		//search for projects and iterate through the names and ids
		public static void searchProjects(IProjectManager projectManager, String searchQuery) 
		{
			IProjectFilter projectFilter = projectManager.CreateProjectFilter();

			//hard-code the max results to 10
			projectFilter.MaximumResults = 10;

			//set the query
			projectFilter.NameSearchText = searchQuery;

			//execute the search and print out the results
			IProject[] projects = projectManager.QueryProjects(projectFilter);
			if (projects.Length > 0)
			{
				for (int i = 0; i < projects.Length; i++)
				{
					IProject project = projects[i];
					Console.WriteLine("Project name is " + project.Name + " and project ID is " + project.ID + "\n");
				}
			}
			else
			{
				Console.WriteLine("No projects found using search query of " + searchQuery);
			}


		}

		//helper method to parse command line parameters
		public static Hashtable parseParameters(String[] args) 
		{
			Hashtable map = new Hashtable();
			//make the args into a list for easier processing
			ArrayList argsList = new ArrayList();
			for (int i = 0; i < args.Length; i++)
			{
				argsList.Add(args[i]);
			}
			//put the args into the map
			getArg(map, argsList, ENDPOINT, "Endpoint not specified", true);
			getArg(map, argsList, USERNAME, "Username not specified", true);
			getArg(map, argsList, PASSWORD, "Password not specified", true);
			getArg(map, argsList, PASSWORD, "Password not specified", true);
			getArg(map, argsList, PROJECT_NAME, null, false);
			getArg(map, argsList, PROJECT_DESCRIPTION, null, false);
			getArg(map, argsList, PROJECT_ID, null, false);
			getArg(map, argsList, CREATE, null, false);
			getArg(map, argsList, REMOVE, null, false);
			getArg(map, argsList, SEARCH, null, false);
			getArg(map, argsList, SEARCH_QUERY, null, false);
			return map;
		}

		//helper method to get parameters
		public static void getArg(Hashtable map, ArrayList argsList, String arg, String errorMessage, bool required) 
		{
			//get the position of the argument
        
			int position = argsList.IndexOf(arg);

			//if not found and required, squawk and quit
			if (position == -1)
			{
				if (required)
				{
					errorUsage(errorMessage);
				}
			}
			else
			{
				//special case for create, remove, and search
				Object value = null;
				if (arg.Equals(CREATE) || arg.Equals(REMOVE) || arg.Equals(SEARCH))
				{
					value = "true";
				}
				else
				{
					//check for index out of bounds exceptions
					if (position + 1 == argsList.Count)
					{
						if (required)
						{
							errorUsage("Unable to find corresponding argument for " + arg);
						}
					}
					value = argsList[position + 1];
				}
				//special case for endpoint and project id
				if (arg.Equals(ENDPOINT))
				{
					value = new Uri((String) value);
				}
				else if (arg.Equals(PROJECT_ID))
				{
					value =  (String) value;
				}
				//only add things once
				if (!map.ContainsKey(arg))
				{
					map.Add(arg, value);
				}
			}
		}

		//method to print out an error message, usage, and exit
		public static void errorUsage(String errorMessage)
		{
			Console.WriteLine(errorMessage);
			Console.WriteLine("\n");
			printUsage();
		    Environment.Exit(2);
		}

		//prints usage
		public static void printUsage()
		{
			StringBuilder usage = new StringBuilder();
			usage.Append("Usage: java ProjectCommandLineExample \n")
				.Append(ENDPOINT)
				.Append(" http://myserver:8080/ptapi/services/QueryInterfaceAPI \n")
				.Append(USERNAME)
				.Append(" administrator -password \"\"\n")
				.Append("To create a project, add ")
				.Append(CREATE)
				.Append("\nto optionally add a name and description, add ")
				.Append(PROJECT_NAME)
				.Append(" project_name ")
				.Append(PROJECT_DESCRIPTION)
				.Append(" project_description.\n")
				.Append("to remove a project, type ")
				.Append(REMOVE)
				.Append(" as well as ")
				.Append(PROJECT_ID)
				.Append(" and the project ID\n")
				.Append("to query for projects, type ")
				.Append(SEARCH)
				.Append(" and optionally add a search query using ")
				.Append(SEARCH_QUERY)
				.Append(" followed by the query.\n");

			Console.WriteLine(usage.ToString());
		}


	}

}
