using System;

//import IRemoteSession explicitly to avoid naming conflicts
using IRemoteSession = Plumtree.Remote.PRC.IRemoteSession;

using Plumtree.Remote.PRC.Collaboration.Project;
using Plumtree.Remote.PRC.Collaboration.Tasklist;
using RemoteSessionFactory = Plumtree.Remote.PRC.RemoteSessionFactory;
using Plumtree.Remote.PRC.Collaboration;

using System.Collections;
using System.Text;

/**
* Simple command line example which demonstrates simple task list functionality, such as
* creating a task list, searching for a task list, removing a task list.
*/
public class TaskListCommandLineExample
{
	//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";

	private static IProjectManager projectManager;
	private static ITaskListManager tasklistManager;

	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();
		projectManager = collabFactory.GetProjectManager();
		tasklistManager = collabFactory.GetTaskListManager();

      
      // ----- CREATE functionality ----- 
      
      //create and store the containing project
      IProject project = CreateAndStoreProject("Sample Project", "Description for Sample Project");
      
      //create and store a task list
      ITaskList tasklist = CreateAndStoreTaskList(project, "Sample TaskList", "Description for Sample TaskList");

      //create and store a top-level task, with startTime set to 9/1/2004, endTime set to 9/8/2004
      ITask toplevelTask = CreateAndStoreTopLevelTask(tasklist, "Sample TopLevel Task 1", "Description for Sample TopLevel Task 1", new DateTime(2004, 9, 1), new DateTime(2004, 9, 8));
      
      //create and store a sub-task, with startTime set to 9/2/2004, endTime set to 9/4/2004
      ITask subTask = CreateAndStoreSubTask(toplevelTask, "Sample Sub Task", "Description for Sample Sub Task", new DateTime(2004, 9, 2), new DateTime(2004, 9, 4));
      
      //create and store another toplevel task, which is going to be added as a dependent task of subTask 
      ITask dependentTask = CreateAndStoreDependentTask(tasklist, "Dependent Task", "Task that depends on Toplevel Task 1", new DateTime(2004, 9, 8), new DateTime(2004, 9, 10), subTask);
      
      
      // ----- SEARCH functionality -----
      
      //search for all task lists in current project, should retrieve 1 task list
      SearchTaskLists(project);
      
      //search for all tasks in current task list, should retrieve 3 tasks
      //results will be sorted by NAME in ascending order
      SearchTasks(tasklist);
      
      // ----- COPY functionality -----
      
      //create a target project for copying task lists from source project 
      IProject targetProject = CreateAndStoreProject("Target Project for Copy", "Description for target Project");
      CopyTaskLists(project, targetProject, new ITaskList[] { tasklist } );
            
      // ----- REMOVE functionality -----
      
      //remove the toplevelTask from its containing task list
      removeTask(tasklist, toplevelTask);

      //remove the specified task list
      removeTasklist(tasklist);
      
  }

  //creates a project - please see Project Example for detailed documentation
  public static IProject CreateAndStoreProject(String name, String description)
  {    
      IProject project = projectManager.CreateProject(name, description);
      project.Store();
      return project;
  }
  
  //creates a task list
  public static ITaskList CreateAndStoreTaskList(IProject project, String name, String description)
  {
      ITaskList tasklist = tasklistManager.CreateTaskList(project, name, description);
     
      //store the task list to get the ID
      tasklist.Store();
      Console.WriteLine("\nCreated task list has name=" + tasklist.Name + ", ID=" +  tasklist.ID);
      return tasklist;
  }

  
  //creates a task
  public static ITask CreateAndStoreTopLevelTask(ITaskList tasklist, String name, String description, DateTime startTime, DateTime endTime)
  {
      //create the task
      ITask task = tasklist.CreateTask(name, description, startTime, endTime);
      
      // if you want to set additional properties, make sure that store() is 
      // called or the changes will not be persisted.
      task.Notes = "Notes for sample TopLevel Task";
      task.Risk = TaskRisks.Medium;
      task.Status = TaskStatuses.Pending;
     
      //store the task to get the ID
      task.Store();
      Console.WriteLine("\nCreated top-level task has name=" + task.Name + ", ID=" + task.ID + ", risk=" + task.Risk + ", status=" + task.Status + ", and notes=" + task.Notes);
      return task;
  }
  
  //creates a subtask
  public static ITask CreateAndStoreSubTask(ITask parentTask, String name, String description, DateTime startTime, DateTime endTime)
  {
      //create the subtask; createSubTask() will create a persisted task, so
      // store() does not need to be called to persist the task properties unless additional properties are set.
      ITask subtask = parentTask.CreateSubTask(name, description, startTime, endTime);
      
      // if you want to set additional properties, make sure that store() is 
      // called or the changes will not be persisted.
      subtask.Risk = TaskRisks.Low;
      subtask.Status = TaskStatuses.FiftyPercentCompleted;
     
      //store the subtask to get the ID
      subtask.Store();
      Console.WriteLine("\nCreated sub-task has name=" + subtask.Name + ", ID=" + subtask.ID + ", and parentTask=" + subtask.GetParentTask().Name);
      return subtask;
  }
  
  //creates a task, and then add the source task as its dependency
  public static ITask CreateAndStoreDependentTask(ITaskList tasklist, String name, String description, DateTime startTime, DateTime endTime, ITask sourceTask)
  {
      //create a toplevel task first
      ITask dependentTask = tasklist.CreateTask(name, description, startTime, endTime);
      
      //add the sourceTask as the current task's dependency, make sure that store() is 
      //called after addDependentTask(), similar to the other task properties,
      //otherwise the newly-added dependency will not be persisted.
      dependentTask.AddDependentTask(sourceTask);
     
      //store the task to persist the added dependency and get the ID
      dependentTask.Store();
      
      //Notice that upon adding a dependent task, the start time of the task will be set automatically to 
      //the end time of dependent source task.
      
      //retrieve all source tasks that this tasks depends on
      ITask[] taskDependency = dependentTask.GetTaskDependencies();      
      String taskDependencyName = taskDependency[0].Name;
      
      Console.WriteLine("\nCreated task has name=" + dependentTask.Name + ", ID=" + dependentTask.ID + ", which has a dependency on sourceTask=" + taskDependencyName);
      return dependentTask;
  }
  
  
  //queries task lists in a project
  public static ITaskList[] SearchTaskLists(IProject project)
  {
      ITaskListFilter taskListFilter = tasklistManager.CreateTaskListFilter();
            
      //set the query to search for all task list
      // different options can be set to search on task lists that contain only PENDING tasks, 
      // completed tasks, or overdue tasks.  See documentation in TaskListCompletionFilterType
      taskListFilter.CompletionType = TaskListCompletionFilterTypes.All;
      
      //limit the return results to be 10; setting this to 0 will return all results
      taskListFilter.MaximumResults = 10;
      
      //disable security checking on the returned objects against the user who performs this query, 
      //so that all objects will be returned
      taskListFilter.RestoreSecurity = false;
      
      //user TaskListQueryOrder to sort the query result; below TaskListQueryOrder shows sorting the returned task lists by NAME in ascending order
      TaskListQueryOrder taskListQueryOrder = new TaskListQueryOrder(TaskListAttributes.Name, true);
      taskListFilter.QueryOrders = new TaskListQueryOrder[] {taskListQueryOrder} ;
      
      //an array of ITaskList objects are returned from queryTaskLists(); if no result is retrieved, a zero-length array will be returned
      ITaskList[] retrievedTaskLists = tasklistManager.QueryTaskLists(project, taskListFilter);
      
      Console.WriteLine("\nSearching for task list in project with name=" + project.Name + ", and TaskListCompletionFilterTypes set to "+ TaskListCompletionFilterTypes.All + " gets back " + retrievedTaskLists.Length + " results.");
      for (int i = 0; i < retrievedTaskLists.Length; i++)
      {
          Console.WriteLine("Retrieved task list[" + i + "] has name=" + retrievedTaskLists[i].Name + ", ID=" + retrievedTaskLists[i].ID);
      }
      return retrievedTaskLists;
  }
  
  //queries tasks in a task list
  public static ITask[] SearchTasks(ITaskList tasklist)
  {
      ITaskFilter taskFilter = tasklistManager.CreateTaskFilter();
      
      //search on all tasks; other options include searching for COMPLETED tasks, OVERDUE tasks, or PENDING tasks
      taskFilter.CompletionType = TaskCompletionFilterTypes.All;
      
      //limit the return results to be 10; setting this to 0 will return all results
      taskFilter.MaximumResults = 10;
      
      //disable security checking on the returned objects against the user who performs this query, 
      //so that all objects will be returned
      taskFilter.RestoreSecurity = false;
      
      //user TaskQueryOrder to sort the query result; below TaskQueryOrder shows sorting the returned task lists by NAME in ascending order
      TaskQueryOrder taskQueryOrder = new TaskQueryOrder(TaskAttributes.Name, true);
      taskFilter.QueryOrders = new TaskQueryOrder[] {taskQueryOrder} ;
      
      //an array of ITask objects are returned from queryTasks(ITaskList); if no result is retrieved, a zero-length array will be returned
      ITask[] retrievedTasks = tasklistManager.QueryTasks(tasklist, taskFilter);
      
      Console.WriteLine("\nSearching for tasks in task list with name=" + tasklist.Name + ", and TaskListCompletionFilterTypes set to "+ TaskListCompletionFilterTypes.All + " gets back " + retrievedTasks.Length + " results.");
      for (int i = 0; i < retrievedTasks.Length; i++)
      {
          Console.WriteLine("Retrieved task[" + i + "] has name=" + retrievedTasks[i].Name + ", ID=" + retrievedTasks[i].ID);
      }
      return retrievedTasks;
  }
  
  //removes a task list
  public static void removeTasklist(ITaskList tasklist)
  {
      int tasklistID = tasklist.ID;
      Console.WriteLine("\nTrying to remove task list with name=" + tasklist.Name + ", ID=" + tasklistID);
      tasklistManager.RemoveTaskList(tasklist);
      
      // trying to retrieve the task list after removal, should retrieve nothing
      ITaskList taskListAfterRemoval = tasklistManager.GetTaskList(tasklistID);
      if (taskListAfterRemoval == null)
      {
          Console.WriteLine("Tasklist successfully removed.");
      }
      else
      {
          Console.WriteLine("Failed to remove task list.");
      }
  }

  //removes a task a task list
  public static void removeTask(ITaskList tasklist, ITask task)
  {
      int taskID = task.ID;
      Console.WriteLine("\nTrying to remove task with name=" + task.Name + ", ID=" + taskID);
      tasklist.RemoveTask(task);
      
      // trying to retrieve the task after removal, should retrieve nothing
      ITask taskAfterRemoval = tasklistManager.GetTask(taskID);
      if (taskAfterRemoval == null)
      {
          Console.WriteLine("Task successfully removed.");
      }
      else
      {
          Console.WriteLine("Failed to remove task.");
      }
  }
  
  //copy content of a task list into another task list
  public static void CopyTaskLists(IProject sourceProject, IProject targetProject, ITaskList[] tasklistsToCopy)
  {
      Console.WriteLine("\nTrying to copy " + tasklistsToCopy.Length + " task list(s) from source project.");
      
      //iterate through the task lists to copy from source project
      for (int i = 0; i < tasklistsToCopy.Length; i++)
      {
          Console.WriteLine("Tasklist to copy [" + i + "] has name=" + tasklistsToCopy[i].Name + ", ID=" + tasklistsToCopy[i].ID);          
      }
      tasklistManager.CopyTaskLists(sourceProject, targetProject, tasklistsToCopy);
      
      //check if the task lists are copied into the target project 
      ITaskListFilter tasklistFilter = tasklistManager.CreateTaskListFilter();
      
      ITaskList[] copiedTasklists = tasklistManager.QueryTaskLists(targetProject, tasklistFilter);
      
      Console.WriteLine("Copied " + copiedTasklists.Length + " task list(s) into target project.");

      //iterate through the task lists to copy from source project
      for (int i = 0; i < copiedTasklists.Length; i++)
      {
          Console.WriteLine("Successfully copied task list [" + i + "] has name=" + copiedTasklists[i].Name + ", ID=" + copiedTasklists[i].ID);          
      }   
  }

   
	//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");
		GetArg(map, argsList, USERNAME, "Username not specified");
		GetArg(map, argsList, PASSWORD, "Password not specified");
		return map;
	}

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

		//if not found and required, squawk and quit
		if (position == -1)
		{
			ErrorUsage(errorMessage);
		}
		else
		{
			//special case for create, remove, and search
			Object value = null;
			//check for index out of bounds exceptions
			if (position + 1 == argsList.Count)
			{
				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);
			}
			//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("\n\nUsage: TaskListCommandLineExample \n")
			.Append(ENDPOINT)
			.Append(" http://myserver:8080/ptapi/services/QueryInterfaceAPI \n")
			.Append(USERNAME)
			.Append(" administrator -password \"\"\n");

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


}
