/*******************************************************************************

* Copyright (c) 2006 IONA Technologies PLCz

* All rights reserved. This program and the accompanying materials

* are made available under the terms of the Eclipse Public License v1.0

* which accompanies this distribution, and is available at

* http://www.eclipse.org/legal/epl-v10.html

* 

* Contributors:

*     IONA Technologies PLC - initial API and implementation

*******************************************************************************/
package org.eclipse.stp.soas.deploy.tomcat;

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.wsdl.Definition;
import javax.wsdl.Port;
import javax.wsdl.PortType;
import javax.wsdl.Service;
import javax.wsdl.WSDLException;

import org.eclipse.core.filesystem.URIUtil;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.stp.common.logging.LoggingProxy;
import org.eclipse.stp.sc.common.internal.model.RuntimeCore;
import org.eclipse.stp.sc.common.utils.CXFUtil;
import org.eclipse.stp.sc.common.utils.JDTUtils;
import org.eclipse.stp.sc.jaxws.ScJaxWsResources;
import org.eclipse.stp.sc.jaxws.deploy.DeployException;
import org.eclipse.stp.sc.jaxws.utils.PackageHelper;
import org.eclipse.stp.sc.jaxws.utils.ScJDTUtils;
import org.eclipse.stp.sc.jaxws.workspace.JaxWsWorkspaceManager;
import org.eclipse.stp.sc.jaxws.wsdl.WsdlUtils;
import org.eclipse.stp.soas.deploy.core.ILogicalPackage;
import org.eclipse.stp.soas.deploy.core.IPackageConfiguration;
import org.eclipse.stp.soas.deploy.core.IPackageConstructor;
import org.eclipse.stp.soas.deploy.core.IPackageCreationContext;
import org.eclipse.stp.soas.deploy.core.IPackageOutputDescriptor;
import org.eclipse.stp.soas.deploy.core.IServerType;
import org.eclipse.stp.soas.deploy.core.utils.DeploymentUtil;

public class WarDeployFilePackageConstructor implements IPackageConstructor {

	private static final LoggingProxy LOG = LoggingProxy.getlogger(WarDeployFilePackageConstructor.class);
	private static String WAR_FILE_EXTENSION = ".war";
	private IProject project;
	private PackageHelper pkgHelper;
	
	public IPackageOutputDescriptor createPackage(ILogicalPackage pkg,
			IPackageCreationContext context, IPackageConfiguration configuration)
			throws CoreException {		
		
		    IFile wsdlFile = pkg.getFile();
		    project = wsdlFile.getProject();
		    File outputFolder = context.getOutputFolder();
		    try {
	        	
	             // copy web.xml file
		    	IContainer container = JaxWsWorkspaceManager.getWSDLFolder(project);
	            IFile webXmlFile = ScJDTUtils.getFileFromContainer(container, "web.xml");

	            if (!webXmlFile.exists()) {
	            	IPath path = RuntimeCore.getInstallPath(project);
	                
	                String webXmlFilePath = path.toOSString() + File.separator + "etc" + File.separator + "web.xml";
	                LOG.debug("web.xml file to copy:" + webXmlFilePath);
	                JaxWsWorkspaceManager.copyFile(webXmlFilePath,
	                                          webXmlFile,
	                                          JaxWsWorkspaceManager.COPY_NO_OVERWRITE,
	                                          new NullProgressMonitor());
	            }
	            

	            LOG.debug("generating celtix_servlet.xml...");
	            generateServletConf(project, wsdlFile); 

	            project.refreshLocal(IProject.DEPTH_INFINITE, null);
	             
	            LOG.debug("generating war file");
	            pkgHelper = new PackageHelper(wsdlFile, WAR_FILE_EXTENSION);			
				
				//IFolder folder = ResourcesPlugin.getWorkspace().getRoot().getFolder(URIUtil.toPath(outputFolder.toURI()));
				IFile file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(URIUtil.toPath(outputFolder.toURI()));
				IFolder folder = (IFolder)wsdlFile.getProject().getFolder(file.getProjectRelativePath());
				pkgHelper.startToPackage((IFolder)folder);				
				//pkgHelper.addFileToPackage(wsdlFile, PackageHelper.WSDL_DIR);
				pkgHelper.stopPackage();
	            //generateWarFile(wsdlFile);
	            
	            project.refreshLocal(IProject.DEPTH_INFINITE, null); 
	            
	            if (context.getTarget() == null) {
	            	return null;
	            }
	            
	            IServerType ist = DeploymentUtil.convertWTPServerTypeToSTPServerType(context.getTarget().getServerType());
	            return new WarPackageOutputDescriptor(pkgHelper.getPackageFile(),
						pkg.getTechnologyType(), ist, pkgHelper
								.getPackageFile().getPath(), pkgHelper.getPackageFile()
								.getName());
	            
	        } catch (Exception e) {
	            LOG.error("deploy error", e);
				LOG.error("create package error", e);			
				throw new CoreException(new Status(Status.ERROR, Activator.PLUGIN_ID, 0, 
						ScJaxWsResources
						.getString("error.deploy.assemble"), e)); 
	        }
			
	}
	 
	
    /**
     * genereate Celtix servlet configuration files for wsdl model
     * @param project, the project
     * @param wsdlFile, the wsdl file to generate config
     * @throws CoreException
     */
    private void generateServletConf(IProject proj, IFile wsdlFile)
        throws DeployException {
        try {
            String wsdlFileName = wsdlFile.getRawLocation().toOSString();
            Definition wsdlDef = WsdlUtils.readWSDL(wsdlFileName);
            List<WebDeployDescriptor> descList = new LinkedList<WebDeployDescriptor>();
            Map services = wsdlDef.getServices();

            for (Iterator itor = services.keySet().iterator(); itor.hasNext();) {
                Service service = (Service)services.get(itor.next());
                Map ports = service.getPorts();

                for (Iterator portItor = ports.keySet().iterator(); portItor.hasNext();) {
                    Port port = (Port)ports.get(portItor.next());
                    descList.add(generateEndpointConf(proj, wsdlFile, service, port));
                }
            }

            IFile configFile = JaxWsWorkspaceManager.getServletConfigFile(proj);
            writeServletConfig(configFile.getRawLocation().toOSString(), descList);
        } catch (WSDLException wsdlE) {
            LOG.error(wsdlE);
            throw new DeployException("Wsdl parsing error during generate servlet config:" + wsdlE.toString(),
                                      wsdlE);
        } catch (CoreException coreE) {
            LOG.error(coreE);
            throw new DeployException("Error during generate servlet config:" + coreE.toString(), coreE);
        }
    }

    /**
     * generate endpoint configuration for one service in celtix-servlet.xml
     * @param project, the celtix project
     * @param service, the service to geneate configure
     * @throws CoreException
     */
    private WebDeployDescriptor generateEndpointConf(IProject proj,
        IFile wsdlFile, Service service, Port port)
        throws CoreException {
        WebDeployDescriptor desc = new WebDeployDescriptor();        

        //IPath path = wsdlFile.getFullPath().removeFirstSegments(2);
        desc.setWsdlPath(JaxWsWorkspaceManager.WEB_INF_DIR + "/"
            + JaxWsWorkspaceManager.WEB_WSDL_DIR + "/" + wsdlFile.getName());
        String wsdlFileName = wsdlFile.getRawLocation().toOSString();

        int index = wsdlFileName.lastIndexOf(File.separator);
        if (index >= 0) {
            wsdlFileName = wsdlFileName.substring(index + 1, wsdlFileName.length());
        }
        index = wsdlFileName.lastIndexOf(".");

        if (index >= 0) {
            wsdlFileName = wsdlFileName.substring(0, index);
        }

        //todo: If there are two endpoints in one wsdl, 
        //then the endpoint name in celtix-servlet will not be unique. 
        desc.setEndpointName(wsdlFileName); //need to check???
        desc.setPattern(wsdlFileName);

        PortType portType = port.getBinding().getPortType();
        String packageName = CXFUtil.getPackageName(portType.getQName().getNamespaceURI());
        String interfaceName = packageName + "."
            + portType.getQName().getLocalPart();
        LOG.debug("[debug]interface name:" + interfaceName);        
        desc.setImplClsName(JDTUtils.findImplClsName(proj, interfaceName));        
        LOG.debug("------- endponit cfg ------");
        LOG.debug(desc.toString());
        LOG.debug("------- endponit cfg ------");

        return desc;
    }

    /**
     * write servlet config file to file system
     * @param fileName, the output file name
     * @throws DeployException
     */
    private void writeServletConfig(String fileName,
        List<WebDeployDescriptor> descList) throws DeployException {
        try {
            FileOutputStream fos = new FileOutputStream(fileName, false);
            PrintStream ps = new PrintStream(fos);
            ps.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            ps.println("<beans xmlns=\"http://www.springframework.org/schema/beans\"");            
            ps.println("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
            ps.println("xmlns:jaxws=\"http://cxf.apache.org/jaxws\"");
            ps.println("xmlns:soap=\"http://cxf.apache.org/bindings/soap\"");
            ps.println("xsi:schemaLocation=\"");
            ps.println("http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd");
            ps.println("http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd");
            ps.println("http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd\">");
            ps.println("\n");
            //ps.println("<jaxws:endpoints>");

            for (WebDeployDescriptor desc : descList) {
                desc.serizlize(fos);
            }

            //ps.println("</jaxws:endpoints>");
            ps.println("</beans>");
            ps.close();
        } catch (Exception e) {
            LOG.error(e);
            throw new DeployException("Error during write celtix-servlet.xml file",
                e);
        }
    }
		
}
