/**
 *############################################################################
 * A component of the Greenstone Librarian Interface, part of the Greenstone
 * digital library suite from the New Zealand Digital Library Project at the
 * University of Waikato, New Zealand.
 *
 * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
 *
 * Copyright (C) 2004 New Zealand Digital Library Project
 *
 * 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.gatherer;


import java.io.*;
import java.lang.*;
import java.net.*;
import javax.swing.*;
import org.greenstone.gatherer.util.GSDLSiteConfig;


public class LocalLibraryServer
{
    static final private String ADD_COMMAND = "?a=config&cmd=add-collection&c=";
    static final private String RELEASE_COMMAND = "?a=config&cmd=release-collection&c=";
    static final private String QUIT_COMMAND = "?a=config&cmd=kill";

    static private GSDLSiteConfig gsdlsite_cfg_file = null;
    static private File local_library_server_file = null;

    static private boolean running = false;

    static public void addCollection(String collection_name)
    {
	config(ADD_COMMAND + collection_name);
	// This is very important -- it ensures that the above command has finished
	config("");
    }


    // Used to send messages to the local library
    // Warning: this has a lot of potential for nasty race conditions
    // The response code is returned immediately -- but this does not mean the local
    //   library action has finished!
    static private void config(String command)
    {
	if (Configuration.library_url == null) {
	    System.err.println("Error: Trying to configure local library with null Configuration.library_url!");
	    return;
	}

	try {
	    URL url = new URL(Configuration.library_url.toString() + command);
	    HttpURLConnection library_connection = (HttpURLConnection) url.openConnection();
	    int response_code = library_connection.getResponseCode();
	    if (response_code >= HttpURLConnection.HTTP_OK && response_code < HttpURLConnection.HTTP_MULT_CHOICE) {
		DebugStream.println("200 - Complete.");
	    }
	    else {
		DebugStream.println("404 - Failed.");
	    }
	}
	catch (Exception ex) {
	    DebugStream.printStackTrace(ex);
	}
    }


    static public boolean isRunning()
    {
	if (!running) return false;
	gsdlsite_cfg_file.load();
	if (gsdlsite_cfg_file.getURL() == null)  return false;
	return true;
    }

    static public void releaseCollection(String collection_name)
    {
	config(RELEASE_COMMAND + collection_name);
	// This is very important -- it ensures that the above command has finished
	config("");

	// !! HACK: Wait a couple of seconds, in the hope that this will reduce the "could not delete index" errors
	new OneSecondWait();
	new OneSecondWait();
    }


    static public void start(String gsdl_path, String local_library_server_file_path)
    {
	// Check the local library server.exe file exists
	local_library_server_file = new File(local_library_server_file_path);
	if (!local_library_server_file.exists()) {
	    DebugStream.println("No local library at given file path.");

	    local_library_server_file = new File(gsdl_path + "server.exe");
	    if (!local_library_server_file.exists()) {
		DebugStream.println("No local library at all.");
		return;
	    }
	}

	// Check if the server is already running
	gsdlsite_cfg_file = new GSDLSiteConfig(local_library_server_file);
	String url = gsdlsite_cfg_file.getURL();
	if (url != null) {
	    // If it is already running then set the Greenstone web server address and we're done
	    try {
		Configuration.library_url = new URL(url);
		running = true;
		return;
	    }
	    catch (MalformedURLException exception) {
		DebugStream.printStackTrace(exception);
	    }
	}

	// Configure the server for immediate entry
	gsdlsite_cfg_file.set();

	// Spawn local library server process
	String local_library_server_command = local_library_server_file.getAbsolutePath() + " " + gsdlsite_cfg_file.getSiteConfigFilename();
	Gatherer.spawnApplication(local_library_server_command);

	// Wait until program has started, by reloading and checking the URL field
	gsdlsite_cfg_file.load();
	int attempt_count = 0;
	while (gsdlsite_cfg_file.getURL() == null) {
	    new OneSecondWait();  // Wait one second (give or take)
	    gsdlsite_cfg_file.load();
	    attempt_count++;

	    // After waiting a minute ask the user whether they want to wait another minute
	    if (attempt_count == 60) {
		int try_again = JOptionPane.showConfirmDialog(Gatherer.g_man, Dictionary.get("Server.QuitTimeOut"), Dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION);
		if (try_again == JOptionPane.NO_OPTION) {
		    return;
		}
		attempt_count = 0;
	    }
	}

	// Ta-da. Now the url should be available
	try {
	    Configuration.library_url = new URL(gsdlsite_cfg_file.getURL());
	}
	catch (MalformedURLException exception) {
	    DebugStream.printStackTrace(exception);
	}

	// A quick test involves opening a connection to get the home page for this collection
	try {
	    DebugStream.println("Try connecting to server on config url: '" + Configuration.library_url+ "'");
	    URLConnection connection = Configuration.library_url.openConnection();
	    connection.getContent();
	}
	catch (IOException bad_url_connection) {
	    try {
		// If this fails then we try changing the url to be localhost
		Configuration.library_url = new URL(gsdlsite_cfg_file.getLocalHostURL());
		DebugStream.println("Try connecting to server on local host: '" + Configuration.library_url + "'");
		URLConnection connection = Configuration.library_url.openConnection();
		connection.getContent();
	    }
	    catch (IOException worse_url_connection) {
		DebugStream.println("Can't connect to server on either address.");
		Configuration.library_url = null;
		return;
	    }
	}

	running = true;
    }


    static public void stop()
    {
	if (running == false) {
	    return;
	}

	// Send the command for it to exit.
	config(QUIT_COMMAND);

	// Wait until program has stopped, by reloading and checking the URL field
	gsdlsite_cfg_file.load();
	int attempt_count = 0;
	while (gsdlsite_cfg_file.getURL() != null) {
	    new OneSecondWait();  // Wait one second (give or take)
	    gsdlsite_cfg_file.load();
	    attempt_count++;

	    // After waiting a minute ask the user whether they want to wait another minute
	    if (attempt_count == 60) {
		int try_again = JOptionPane.showConfirmDialog(Gatherer.g_man, Dictionary.get("Server.QuitTimeOut"), Dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION);
		if (try_again == JOptionPane.NO_OPTION) {
		    return;
		}
		attempt_count = 0;
	    }
	}

	// Restore the gsdlsite_cfg.
	gsdlsite_cfg_file.restore();

	// If the local server is still running then our changed values will get overwritten.
	if (gsdlsite_cfg_file.getURL() != null) {
	    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("Server.QuitManual"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
	}

	running = false;
    }
    
    static public void checkServerRunning() {
	if (!running) return; // don't worry about it if its not supposed to be running 
	gsdlsite_cfg_file.load();
	if (gsdlsite_cfg_file.getURL() == null) {
	    // need to restart the server again
	    gsdlsite_cfg_file.set();

	    // Spawn local library server process
	    String local_library_server_command = local_library_server_file.getAbsolutePath() + " " + gsdlsite_cfg_file.getSiteConfigFilename();
	    Gatherer.spawnApplication(local_library_server_command);

	}
    }
    static private class OneSecondWait
    {
	public OneSecondWait()
	{
	    synchronized(this) {
		try {
		    wait(1000);
		}
		catch (InterruptedException exception) {
		}
	    }
	}
    }
}
