/*
 * ItemImport.java
 *
 * Version: $Revision: 1.27 $
 *
 * Date: $Date: 2005/11/16 21:40:51 $
 *
 * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
 * Institute of Technology.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * - Neither the name of the Hewlett-Packard Company nor the name of the
 * Massachusetts Institute of Technology nor the names of their
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */
package edu.duke.dspace.commandline;

import java.io.File;
import java.io.FileReader;
import java.sql.SQLException;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.dspace.authorize.AuthorizeException;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;

import au.com.bytecode.opencsv.CSVReader;

/**
 * Import Epeople into DSpace. Based off of ItemImport.
 * The conventional webui method required hand entering every new user.
 * We wanted to batch create a large number of EPeople, stored in a
 * CSV file, and add them to a new group all at once.
 * <P>
 * Created out of ItemImport by Seth Shaw, Duke University Archives 07/07
 */
public class EpeopleImport
{

    static boolean isTest = false;
    static boolean isVerbose = false;

    public static void main(String[] argv) throws Exception
    {
        // create an options object and populate it
        CommandLineParser parser = new PosixParser();

        Options options = new Options();

        options.addOption("a", "add", false,
        		"add Epeople listed in source to DSpace");
        options.addOption("d", "delete", false,
                "delete Epeople listed in source");
        options.addOption("s", "source", true, "CSV file with EPeople to create");
        options.addOption("g", "groups", true,
                "Groups to add Epeople to (will be created if it does not exist)"
        		+" or remove them from");
        options.addOption("e", "eperson", true,
                "email of eperson doing importing");
        options.addOption("t", "test", false,
                "test run - do not actually import or delete items");
        options.addOption("v", "verbose", false, 
                "tell me everything");

        options.addOption("h", "help", false, "help");

        CommandLine line = parser.parse(options, argv);

        String command = null; // add replace remove, etc
        String sourcefile = null;
        String eperson = null; // db ID or email
        String[] groups = null; // db ID or name


        if (line.hasOption('h'))
        {
            HelpFormatter myhelp = new HelpFormatter();
            myhelp.printHelp("ItemImport\n", options);
            System.out
                    .println("\nadding Epeople:    ItemImport -a -e eperson -s sourcefile -g groups");
            System.out
                    .println("deleting Epeople:  ItemImport -d -e eperson -s sourcefile [-g groups]");
            System.out
                    .println("** If a group is indicated while deleting the Epeople will only be \n"
                    		+"   removed from those groups listed and not entirely from the system.");

            System.exit(0);
        }

        if (line.hasOption('a'))
        {
            command = "add";
        }

        if (line.hasOption('d'))
        {
            command = "delete";
        }

        if (line.hasOption('t'))
        {
            isTest = true;
            System.out.println("**Test Run** - not actually importing or deleting items.");
        }

        if (line.hasOption('v'))
            isVerbose = true;
        
        if (line.hasOption('s')) // sourcefile
        {
            sourcefile = line.getOptionValue('s');
        }

        if (line.hasOption('e')) // eperson
        {
            eperson = line.getOptionValue('e');
        }

        if (line.hasOption('g')) // groups
        {
            groups = line.getOptionValues('g');
        }

        // now validate
        // must have a command set
        if (command == null)
        {
            System.out
                    .println("Error - must run with either add or delete (run with -h flag for details)");
            System.exit(1);
        }
        else if (command.equals("add"))
        {
            if (sourcefile == null)
            {
                System.out
                        .println("Error - a map file to hold importing results must be specified");
                System.out.println(" (run with -h flag for details)");
                System.exit(1);
            }

            if (eperson == null)
            {
                System.out
                        .println("Error - an eperson to do the importing must be specified");
                System.out.println(" (run with -h flag for details)");
                System.exit(1);
            }

            if (groups == null)
            {
                System.out
                        .println("Error - at least one group must be specified");
                System.out.println(" (run with -h flag for details)");
                System.exit(1);
            }
        }
        else if (command.equals("delete"))
        {
            if (eperson == null)
            {
                System.out
                        .println("Error - an eperson to do the importing must be specified");
                System.exit(1);
            }

            if (sourcefile == null)
            {
                System.out.println("Error - a source file must be specified");
                System.out.println(" (run with -h flag for details)");
                System.exit(1);
            }
        }

        EpeopleImport myloader = new EpeopleImport();
        // create a context
        Context c = new Context();

        // find the EPerson, assign to context
        EPerson myEPerson = EPerson.findByEmail(c, eperson);

        if (myEPerson == null)
        {
            System.out.println("Error, eperson cannot be found: " + eperson);
            System.exit(1);
        }

        c.setCurrentUser(myEPerson);


        Group[] mygroups = null;
        if (groups != null){
            // find groups
            if (isVerbose)
                System.out.println("Effected Groups:");

            mygroups = new Group[groups.length];
            // validate each group arg to see if it's a real group
            for (int i = 0; i < groups.length; i++)
            {
                mygroups[i] = Group.findByName(c, groups[i]);
    /*            if (mygroups[i] == null)
                {
                    try { // try and treat it as an integer group database ID
                        mygroups[i] = Group.find(c, Integer.parseInt(groups[i]));
                    }
                    catch(NumberFormatException nfe){
                        //Apparently not an integer (thus: not a dbid)
                        mygroups[i] = null;
                    }
                } */
                if (mygroups[i] == null) //Still null, create the group
                {
                    mygroups[i] = Group.create(c);
                    mygroups[i].setName( groups[i] );
                    mygroups[i].update();
                    System.out.println("Created Group: " + mygroups[i].getName()
                            + " (" + mygroups[i].getID() + ")");
                }
                else if (isVerbose) {
                    System.out.println("Existing Group: " + mygroups[i].getName()
                            + " (" + mygroups[i].getID() + ")");
                }
            }
            // end of validating groups            
        }


        try
        {
            c.setIgnoreAuthorization(true);

            if (command.equals("add"))
            {
                myloader.addEpeople(c, mygroups, sourcefile);
            }
            else if (command.equals("delete"))
            {
                myloader.deleteEPeople(c, mygroups, sourcefile);
            }

            if (!isTest)
            {
                // complete all transactions
                c.complete();
            }
            else
            {
            	c.abort();
                System.out.println("***End of Test Run***");
            }
        }
        catch (Exception e)
        {
            // abort all operations
            c.abort();
            e.printStackTrace();
            System.out.println(e);
        }
    }

    private void deleteEPeople(Context c, Group[] mygroups, String sourceFile)
      throws Exception
    {
        if (isVerbose){
            System.out.println("Removing Epeople listed in source file: " 
                    + sourceFile);
        }

        // open and process the source directory
        File f = new java.io.File(sourceFile);

        if (f == null)
        {
            System.out.println("Error, cannot open source file "
                    + sourceFile);
            System.exit(1);
        }

        CSVReader reader = new CSVReader(new FileReader(f));
        String [] nextLine;
        while ((nextLine = reader.readNext()) != null)
        {
        	deleteEPerson(c, nextLine[0], mygroups);
        }
        if(mygroups != null){
            for (int i = 0; i < mygroups.length; i++)
            {
                mygroups[i].update();
            }            
        }

	}

	private void deleteEPerson(Context c, String email, Group[] mygroups)
	  throws Exception
	{
	    try
	    {
	       EPerson e = EPerson.findByEmail(c, email );
	       if ( (mygroups != null) && (mygroups.length > 0) )
	       {
	    	   for (int i = 0; i < mygroups.length; i++)
	    	   {
	    		   Group g = mygroups[i];
	    		   g.removeMember(e);
	    		   if (i == 0)
	    		   {
	    		       if (isVerbose) {
	    		           System.out.println("Group(s) from which Eperson, " + email
	    	    			   + " ("+e.getFullName()+"), was removed:");
	    		       }
	    		   }
	    		   if (isVerbose) {
	    		       System.out.println("\t"+g.getName()
	    		               +" ("+g.getID()+")");
	    		   }
	    	   }
	       }
	       else if (e != null)
	       {
	    	   e.delete();
	    	   if (isVerbose){
	    	       System.out.println("Eperson, " + email
	    			   + " ("+e.getFullName()+") was removed from the system");
	    	   }
	       }

	       if (isVerbose){
	           System.out.println("Eperson with " + email + "exists: "+e.getFullName());
	       }
	    }
	    catch (AuthorizeException ae)
	    {
	    	System.out.println(c.getCurrentUser().getEmail()
	    			+" is not authorized to administer "
	    			+" user with email: "+email);
	    }

	}

	private void addEpeople(Context c, Group[] mygroups, String sourceFile)
      throws Exception
    {
	    if (isVerbose)
	        System.out.println("Adding Epeople from source file: " + sourceFile);

        // open and process the source directory
        File f = new java.io.File(sourceFile);

        if (f == null)
        {
            System.out.println("Error, cannot open source file "
                    + sourceFile);
            System.exit(1);
        }

        CSVReader reader = new CSVReader(new FileReader(f));
        String [] nextLine;
        while ((nextLine = reader.readNext()) != null)
        {
        	addEperson(c, nextLine[0], nextLine[1], nextLine[2], mygroups);
        }
        //Push all group changes to the database
        for (int i = 0; i < mygroups.length; i++)
        {
        	mygroups[i].update();
        }
    }

    /**
     * Doc this...
     */
    private void addEperson(Context c, String email, String givenName,
            String surname, Group[] mygroups) throws Exception
    {

	    EPerson e;
	    try {
	       e = EPerson.findByEmail(c, email );
	       // Out some message stating that the user exists and move on
           if (e != null){
    	       e.setCanLogIn(true);
    	       e.update();
    	       if (isVerbose)
    	           System.out.println("Eperson with " + email + " exists: "
    	                   +e.getFullName());
           }
           else {
    	       //No email was found, so let's create the user
     	      e = EPerson.create(c);
     	      e.setEmail( email );
     	      e.setFirstName( givenName );
     	      e.setLastName( surname );
     	      e.setCanLogIn(true);
     	      e.update();
     	     if (isVerbose)
     	         System.out.println("Created Eperson " + e.getEmail() + " : "
     	                 +e.getFullName());
           }

           for (int i = 0; i < mygroups.length; i++)
           {
           	mygroups[i].addMember(e);
/*           if (i == 0)
           		System.out.println(e.getFullName()+"'s group(s): ");
           	System.out.println("\t"+g.getName()
           			+" dbid: "+g.getID() );
*/
           }
           return;
	    }
	    catch (SQLException exception) {
	    	System.out.println("A SQL error occured for : "+email+" ... Moving on...");
	    }
	    catch (AuthorizeException ae) {
	    	System.out.println("You are not authorized to find or add this person ... Moving on ...");
	    }
    }
}