//import IRemoteSession explicitly to avoid naming conflicts

import com.plumtree.remote.prc.IRemoteSession;
import com.plumtree.remote.prc.RemoteSessionFactory;
import com.plumtree.remote.prc.collaboration.ICollaborationFactory;
import com.plumtree.remote.prc.collaboration.project.IProject;
import com.plumtree.remote.prc.collaboration.project.IProjectFilter;
import com.plumtree.remote.prc.collaboration.project.IProjectManager;

import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 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 final String ENDPOINT = "-endpoint";
    public static final String USERNAME = "-username";
    public static final String PASSWORD = "-password";
    public static final String PROJECT_NAME = "-n";
    public static final String PROJECT_DESCRIPTION = "-d";
    public static final String PROJECT_ID = "-id";
    public static final String CREATE = "-c";
    public static final String REMOVE = "-r";
    public static final String SEARCH = "-s";
    public static final String SEARCH_QUERY = "-q";


    public static void main(String[] args) throws Exception
    {
        //make the arguments into a hashmap
        Map argsMap = parseParameters(args);

        //get a remote session using the soap endpoint, username, and password
        URL endpoint = (URL) argsMap.get(ENDPOINT);
        String username = (String) argsMap.get(USERNAME);
        String password = (String) argsMap.get(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
            Integer projectInteger = (Integer) argsMap.get(PROJECT_ID);
            if (null == projectInteger)
            {
                System.out.println("Project cannot be removed without a project ID");
                return;
            }
            removeProject(projectManager, projectInteger.intValue());
            return;
        }
        else if (argsMap.containsKey(SEARCH))
        {
            String query = (String) argsMap.get(SEARCH_QUERY);
            query = (null == query) ? "" : query;
            searchProjects(projectManager, query);

        }

    }

    //creates a project
    public static void createProject(IProjectManager projectManager, Map argsMap) throws Exception
    {
        //see if we have a name and description
        String name = (String) argsMap.get(PROJECT_NAME);
        //set to a default value if there is no name
        name = (null == name) ? "ExampleProject" : name;
        String description = (String) argsMap.get(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.NOT_STARTED);
        project.setStartDate(new Date());
        */
        //store the project to get the ID
        project.store();
        System.out.println("ID of newly created project is " + project.getID());
    }

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


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

        //hard-code the max results to 10
        projectFilter.setMaximumResults(10);

        //set the query
        projectFilter.setNameSearchText(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];
                System.out.println("Project name is " + project.getName() + " and project ID is " + project.getID() + "\n");
            }
        }
        else
        {
            System.out.println("No projects found using search query of " + searchQuery);
        }


    }

    //helper method to parse command line parameters
    public static Map parseParameters(String[] args) throws Exception
    {
        Map map = new HashMap();
        //make the args into a list for easier processing
        ArrayList argsList = new ArrayList(Arrays.asList(args));
        //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(Map map, ArrayList argsList, String arg, String errorMessage, boolean required) throws Exception
    {
        //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.size())
                {
                    if (required)
                    {
                        errorUsage("Unable to find corresponding argument for " + arg);
                    }
                }
                value = argsList.get(position + 1);
            }
            //special case for endpoint and project id
            if (arg.equals(ENDPOINT))
            {
                value = new URL((String) value);
            }
            else if (arg.equals(PROJECT_ID))
            {
                value = new Integer((String) value);
            }
            map.put(arg, value);
        }
    }

    //method to print out an error message, usage, and exit
    public static void errorUsage(String errorMessage)
    {
        System.out.println(errorMessage);
        System.out.println("\n");
        printUsage();
        System.exit(1);
    }

    //prints usage
    public static void printUsage()
    {
        StringBuffer usage = new StringBuffer();
        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");

        System.out.println(usage.toString());
    }


}
