
package org.openspml.browser;

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.List;

import org.openspml.message.*;
import org.openspml.client.*;


public class State extends WindowAdapter {

    public static String LIGHTHOUSE_URL = 
    "http://localhost:82/lighthouse/servlet/rpcrouter2";
    public static String LIGHTHOUSE_USER = "Configurator";
    public static String LIGHTHOUSE_PASSWORD = "configurator";

    BrowserFrame _frame;
    String _url;
    String _user;
    String _password;
    SpmlClient _client;
    List _schemas;
    SOAPTracer _tracer;

    /**
     * True to filter the Lighthouse session token from the
     * operational attributes.
     */
    boolean _filterSessionToken = true;

    public State(BrowserFrame f) {
        _frame = f;
    }

    public BrowserFrame getFrame() {
        return _frame;
    }

    public void setConnection(String url, String user, String password) {

        // Try to be smart about dropping the previous connection if
        // the parameters haven't changed.  Preserves cookies if we 
        // happen to be retaining them
        if (url == null || !url.equals(_url) ||
            user == null || !user.equals(_user) ||
            password == null || !password.equals(_password)) {

            _client = null;
            _schemas = null;
            if (_tracer != null)
                _tracer.setClient(null);
        }

        _url = url;
        _user = user;
        _password = password;
    }

    public SpmlClient getClient() {
        
        if (_client == null) {
            if (_url == null)
                SwingUtil.displayError("You must first establish connection parameters");
            else {
                // use a Lighthouse client for now so we can use
                // session tokens, but it isn't required
                // SpmlClient client = new SpmlClient();
                LighthouseClient client = new LighthouseClient();
                client.setUser(_user);
                client.setPassword(_password);

                try {
                    client.setUrl(_url);
                }
                catch (java.net.MalformedURLException e) {
                    SwingUtil.displayError(e);
                    client = null;
                }
                _client = client;
                if (_tracer != null)
                    _tracer.setClient(_client);
            }
        }

        return _client;
    }

    /**
     * Display the SOAP Trace window.
     */
    public void soapTrace() {

        if (_tracer == null) {
            // do not force a connection yet, we'll set it later
            _tracer = new SOAPTracer(_client);
	    // this shouldn't be necessary if we implemented
	    // SOAPMonitorListener
            _tracer.addWindowListener(this);
	    _tracer.trace("SPML Browser is using this monitor");
        }
    }

    /**
     * WindowAdapter overload that will be called when the trace
     * window is closed.
     */
    public void windowClosing(WindowEvent e) {
        _tracer = null;
    }

    /**
     * Control the wait cursor.
     */
    public void setWaitCursor(boolean enable) {

        if (enable)
            _frame.setCursor(new Cursor(Cursor.WAIT_CURSOR));
        else
            _frame.setCursor(null);
    }

    public void testConnection() {

        SpmlClient client = getClient();
        if (client != null) {

            // how to ping?
            // send over an extended request, as long as we get an 
            // ExtendedResponse back with "unknown request" it should be ok,
            // since not all servers may support ExtendedRequst, probably
            // need a way to disable this.
        
            ExtendedRequest req = new ExtendedRequest();
            req.setOperationIdentifier("ping");

            try {
                SpmlResponse res = client.request(req);

                // if we got a response at all, the connection
                // was technically successful, but also propagate
                // any server errors?
                // client.throwErrors(res);

                SwingUtil.displayMessage("Connection", 
                                         "Connection successful");
            }
            catch (Throwable t) {
                SwingUtil.displayError(t);
            }
        }
    }

    /**
     * Execute an SPML request.  Normally given an Installer subclass
     * that will be called after the request has completed to assimilate
     * the response into the GUI.
     */
    public void doRequest(SpmlRequest req, Installer inst) {

        SpmlClient client = getClient();
        if (client != null)
            new Thread(new Executor(client, req, inst)).start();
    }

    /**
     * Thread to execute an SPML request outside the Swing event thread.
     * Normally will be passed an Installer which will be invoked later
     * within the Swing event thread to assimilate the result into the GUI.
     */
    private class Executor implements Runnable {

        SpmlClient _client;
        SpmlRequest _request;
        Installer _installer;

        public Executor(SpmlClient client, SpmlRequest r, Installer inst) {
            _client = client;
            _request = r;
            _installer = inst;
        }

	public void run() {
	    try {
                SpmlResponse response = null;
                setWaitCursor(true);
                try {
                    response = _client.request(_request);
                }
                finally {
                    setWaitCursor(false);
                }
                
                if (_filterSessionToken) {
                    // an operational attribute with the session token will
                    // usually be returned for Lighthouse, remove this to
                    // prevent alarm
                    response.removeOperationalAttribute("session");
                    if (response instanceof StatusResponse) {
                        StatusResponse sr = (StatusResponse)response;
                        SpmlResponse inner = sr.getResponse();
                        if (inner != null)
                            inner.removeOperationalAttribute("session");
                    }
                }
                
                // hack, if this is a SchemaResponse, cache the results

                if (response instanceof SchemaResponse)
                    _schemas = ((SchemaResponse)response).getSchemas();

                else if (response instanceof BatchResponse) {
                    BatchResponse batch = (BatchResponse)response;
                    SchemaResponse sr = (SchemaResponse)
                        batch.getResponse(SchemaResponse.class);
                    if (sr != null)
                        _schemas = sr.getSchemas();
                }

                if (_installer != null) {
                    _installer.setResponse(response);
                    SwingUtilities.invokeLater(_installer);
                }
            }
	    catch (Throwable t) {
		SwingUtil.displayError(t);
	    }
	}
    }

    //////////////////////////////////////////////////////////////////////
    //  
    // Schema Maintenance
    //
    //////////////////////////////////////////////////////////////////////

    /**
     * Return the cached list of schemas supported by this PSP.
     */
    public List getSchemas() {
        return _schemas;
    }

    public ObjectClassDefinition getObjectClass(String name) {

        ObjectClassDefinition def = null;
        if (_schemas != null) {
            for (int i = 0 ; i < _schemas.size() ; i++) {
                Schema s = (Schema)_schemas.get(i);
                def = s.getObjectClassDefinition(name);
                if (def != null)
                    break;
            }
        }

        return def;
    }

    public ObjectClassDefinition getDefaultObjectClass() {

        ObjectClassDefinition def = null;
        if (_schemas != null) {
            for (int i = 0 ; i < _schemas.size() ; i++) {
                Schema s = (Schema)_schemas.get(i);
                List defs = s.getObjectClassDefinitions();
                if (defs != null && defs.size() > 0) {
                    def = (ObjectClassDefinition)defs.get(0);
                    break;
                }
            }
        }

        return def;
    }


}
