package ca.ucalgary.services;

import ca.ucalgary.services.util.MobySpecWrapper;

import org.biomoby.shared.MobyService;
import org.biomoby.shared.MobyUnitTest;

import java.net.URL;

/**
 * Based class for servlets implementing a Moby wrapper around 
 * existing Web-based interface specifications enhanced with semantic info
 * (represented in a MobySpecWrapper), such as WSDL and CGI services.
 */
public abstract class WrapperService<E extends MobySpecWrapper> extends LegacyService{

    /**
     * @param configParamName the name of the servlet configuration parameter holding the exisiting service spec's location (e.g. where is the WSDL file or CGI form to be wrapped?)
     *
     * @throws Exception if the parameter specified cannot be found, or it cannot be turned into a valid URL
     */
    public URL getSpecURL(String configParamName) throws Exception{
        String remoteSpecURLString = null;
        URL remoteSpecURL = null;
        if(getCoCInitParameter(configParamName) != null){
            remoteSpecURLString = getCoCInitParameter(configParamName);
        }
        else{
            throw new Exception("No parameter called " + configParamName +
                                " was found in the servlet configuration");
        }
        try{
            remoteSpecURL = new URL(remoteSpecURLString);
        } catch(Exception e){
            // Fallback to finding it as a resource
            remoteSpecURL = getClass().getClassLoader().getResource(remoteSpecURLString);
            if(remoteSpecURL == null){
              throw new Exception("The configuration parameter '" + configParamName +
                                  "' (value '" + remoteSpecURLString +
                                  "') was not parseable as a URL, nor is it a Java resource");
            }
        }
        return remoteSpecURL;
    }

    public MobyService createServiceFromConfig(javax.servlet.http.HttpServletRequest request, 
                                               E wrapperSpec) throws Exception{

        // Configure meta-data for the Moby service about to be created
        String[] serviceNames = wrapperSpec.getServiceNames();
        if(serviceNames.length > 1){
            String targetedService = getCoCInitParameter(MOBY_SERVICENAME_PARAM);
            String valuesString = "";
            for(String value: serviceNames){
                valuesString += value + " ";
            }
            if(targetedService == null || targetedService.trim().length() == 0){
                throw new Exception("The legacy specification to wrap contains more than one Moby-annotated " +
                                    "operation/service, but no '"+MOBY_SERVICENAME_PARAM+"' parameter was " +
                                    "specified in the servlet configuration.  Please specify this " +
                                    "parameter with one of the following values: " + valuesString);
            }
            boolean foundService = false;
            for(String validName: serviceNames){
                if(targetedService.equals(validName)){
                    foundService = true;
                    break;
                }
            }
            if(!foundService){
                throw new Exception("The service to wrap (" + targetedService +
                                    "), named in the servlet configuration parameter '" +
                                    MOBY_SERVICENAME_PARAM + "', was not one of the service names " +
                                    "available from the WSDL.  Valid values are: " + valuesString);
            }
            wrapperSpec.setCurrentService(targetedService);
        }

        setCoCInitParameter(MOBY_SERVICENAME_PARAM, wrapperSpec.getServiceName());
        setCoCInitParameter(MOBY_SERVICETYPE_PARAM, wrapperSpec.getServiceType());
        setCoCInitParameter(MOBY_SERVICE_DESC_PARAM, wrapperSpec.getServiceDesc());
        setCoCInitParameter(MOBY_PROVIDER_URI_PARAM, wrapperSpec.getProviderURI());
        setCoCInitParameter(MOBY_CENTRAL_URL_PARAM, wrapperSpec.getCentralEndpoint());
        setCoCInitParameter(MOBY_CONTACT_PARAM, wrapperSpec.getContactEmail());

        // Determine primary I/O parameters
        setCoCInitParameter(MOBY_INPUT_PARAM, createInputSpecString(wrapperSpec));
        setCoCInitParameter(MOBY_OUTPUT_PARAM, createOutputSpecString(wrapperSpec));
        // Determine secondary parameters
        setCoCInitParameter(MOBY_SECONDARYINPUT_PARAM, createSecondarySpecString(wrapperSpec));

        MobyService srvc = super.createServiceFromConfig(request);

	if(wrapperSpec.getUnitTests() != null){
	    for(MobyUnitTest unitTest: wrapperSpec.getUnitTests()){
		srvc.addUnitTest(unitTest);
	    }
	}

	return srvc;
    }

    public abstract String createInputSpecString(E wrapperSpec);
    public abstract String createOutputSpecString(E wrapperSpec);
    public abstract String createSecondarySpecString(E wrapperSpec);
}
