/*
 *    ServletRealmCheck.java
 *    Copyright (C) 2008 New Zealand Digital Library, http://www.nzdl.org
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
package org.greenstone.cli;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Properties;

import org.greenstone.util.ProtocolPortProperties;

/**
 * Commandline script that is used by gliserver.pl to authenticate a username and password and 
 * return the user's groups, while the derby server is running. Because 2 JVM instances can't
 * access the same embedded derby server at the same time, gliserver can't call usersDB2txt.java.
 * If a collection parameter is additionally provided, this script will check the user's groups
 * to see if any of these allow the user to edit that collection.
 *
 * Run as java org.greenstone.cli.ServletRealmCheck <GSDL3HOME> <un> <pwd> [-c colname] [-s servletname]
 *
 * >java -classpath "greenstone3\bin\java\gs3-cli.jar;greenstone3\web\WEB-INF\lib\gsdl3.jar;greenstone3\web\WEB-INF\lib\gutil.jar" 
 * 		org.greenstone.cli.ServletRealmCheck "greenstone3\web" <un> <pw> [-c colname] [-s servlet-name] 2>&1
 *
 * Tries URL: http://hostname:port/context/servletname?a=s&sa=authenticated-ping&excerptid=gs_content&un=<un>&pw=<pw>[&col=colname] 
 * The &excerptid=gs_content in the URL will return just the <div id="gs_content" /> part of the 
 * page that we're interested in.
 *
 * Result: either prints out an error message ("Authentication failed...") or a positive result, 
 * which is the user's groups. For the admin user example: administrator,all-collections-editor.
 * If no collection is specified, will print the user groups.
 * If a collection is specified, will only print user groups if the user has access to the collection.
 *
 * -s <servletname> to specify a specific servlet-name if different from default of "library".
 * This is probaly only meaningful if there is no library called "library" as all servlet-names
 * I think would respond identically to the ping regarding the groups a user belongs to.
*/
public class ServletRealmCheck
{
    private static void printUsageAndTerminate() {
	System.out.println("Run with: <GSDL3HOME> <un> <pwd> [-c collection-name] [-s servlet-name]");
	System.exit(0);
    }
    
    public static void main(String[] args) {
	
	if (args.length < 3 || args.length > 7){	    
	    printUsageAndTerminate();
	} else if(args.length % 2 == 0) { // for all args past the 3rd arg, need odd number of args:
	    // first 3 args + (2 args for each -flag-option value combination) = odd number of args
	    printUsageAndTerminate();
	}
	
	String gsdl3home = args[0];
	String username = args[1];
	String password = args[2];
	//String collection = (args.length > 3) ? args[3] : null;
	String collection = null;	
	String libservletname = "library"; // fallback to default library servlet
	
	for(int i = 3; i < args.length; i++) {	    
	    if(args[i].equals("-c")) {
		collection = args[++i];
	    }
	    else if(args[i].equals("-s")) {
		libservletname = args[++i];
	    }
	}

	
	//System.err.println("gsdl3srchome: " + gsdl3srchome);
	//System.err.println("username: " + username);
	//System.err.println("password: " + password);
	//System.err.println("collection: " + collection);
	
	
	// Load the global.properties file, get the GS3 server URL and send authenticated-ping and print the return result
	
	//http://www.mkyong.com/java/java-properties-file-examples/
	Properties globalProps = new Properties();
	InputStream input = null;
 
	try {
	    File globalPropsFile = new File(gsdl3home, "WEB-INF" +File.separatorChar+ "classes"+ File.separatorChar+"global.properties");
		input = new FileInputStream(globalPropsFile);
 
		// load a properties file
		globalProps.load(input);
 
		// get the property value and print it out
		String servername = globalProps.getProperty("tomcat.server");
		ProtocolPortProperties protocolPortProps = new ProtocolPortProperties(globalProps); // can throw Exception
		String protocol = protocolPortProps.getProtocol();
		String port = protocolPortProps.getPort();
		int portNum = Integer.parseInt(port);
		
		String context = globalProps.getProperty("tomcat.context");
		// Appending &excerptid=gs_content will get just the <div ... id="gs_content"/> from the final web page:
		String urlSuffix = "/"+context+"/"+libservletname+"?a=s&sa=authenticated-ping&excerptid=gs_content&un="+username+"&pw="+password;
		if(collection != null) {
			urlSuffix = urlSuffix + "&col="+collection;
		}
		URL authenticationUrl = new URL(protocol, servername, portNum, urlSuffix);
		
		HttpURLConnection conn = (HttpURLConnection)authenticationUrl.openConnection();		
		BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
		String result = "";
		String line = null;
		
		while((line = reader.readLine()) != null) {
			result += line;
		}

		// Beware: these stderr statements go into gliserver authenticate_user_gs3
		// results, messing up zip files by adding the debugging text into the zip headers
		//System.err.println("** Sent: " + authenticationUrl);
		//System.err.println("** Got result:\n" + result);
		
		// Parse out the content nested inside <div ... id="gs_content"> </div>
		int start = result.indexOf("id=\"gs_content\"");
		if(start != -1) {
			start = result.indexOf(">", start);
			int end = result.indexOf("<", start);
			result = result.substring(start+1, end);
			result = result.trim();
		}		
		
		// Now we finally have what we actually want to print out for the caller to use
		System.out.print(result + ","); // don't add newline to end
		
	} catch (Exception ex) {
	    System.err.println("Authentication failed: Java error: " + ex.getMessage());
	    ex.printStackTrace();
	} finally {
		if (input != null) {
			try {
				input.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
  }	
   
}
