/*
 * Copyright 2001-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * JOnAS : Java(TM) OpenSource Application Server
 * Copyright (C) 2004 Bull S.A.
 * Contact: jonas-team@ow2.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */
package org.ow2.jonas.generators.wsgen.generator.ews.wsdltoj2ee.writer;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;

import javax.wsdl.Definition;
import javax.wsdl.Port;
import javax.wsdl.Service;
import javax.wsdl.extensions.UnknownExtensibilityElement;
import javax.wsdl.extensions.soap.SOAPBinding;
import javax.xml.namespace.QName;

import org.ow2.jonas.generators.wsgen.generator.ews.wsdltoj2ee.wscf.JOnASWSCFHandler;

import org.apache.axis.Constants;
import org.apache.axis.constants.Style;
import org.apache.axis.constants.Use;
import org.apache.axis.utils.Messages;
import org.apache.axis.wsdl.symbolTable.BindingEntry;
import org.apache.axis.wsdl.symbolTable.SymbolTable;
import org.apache.axis.wsdl.toJava.Emitter;
import org.apache.axis.wsdl.toJava.Utils;
import org.apache.ws.ews.context.webservices.client.ServiceReferenceContext;
import org.apache.ws.ews.context.webservices.server.WSCFHandler;
import org.apache.ws.ews.context.webservices.server.WSCFInitParam;
import org.apache.ws.ews.context.webservices.server.WSCFSOAPHeader;


/**
 * This is Wsdl2java's deploy Writer. It writes the deploy.wsdd file.
 * Based on J2eeDeployWriter from Ias
 * (http://cvs.apache.org/viewcvs.cgi/ws-axis/contrib/ews/src/org/apache/geronimo/ews/ws4j2ee/toWs/ws/J2eeDeployWriter.java?rev=1.13&view=markup)
 */
public class J2EEClientDeployWriter extends JOnASDeployWriter {

    /**
     * WSDD Extension prefix
     */
    private static final String WSDD_PREFIX = "deploy-client-";

    /**
     * Constructor.
     * @param emitter J2eeEmitter
     * @param definition wsdl:definition
     * @param symbolTable SymbolTable
     */
    public J2EEClientDeployWriter(Emitter emitter, Definition definition, SymbolTable symbolTable) {
        super(emitter, definition, symbolTable);
    }

    /**
     * Generate deploy.wsdd. Only generate it if the emitter is generating
     * server-side mappings.
     * @throws IOException When generation fails
     */
    public void generate() throws IOException {

        if (!emitter.isServerSide()) {
            super.generate();
        }
    }

    /**
     * Write out deployment and undeployment instructions for each WSDL service
     * @param pw PrintWriter
     * @throws IOException IOException
     */
    protected void writeDeployServices(PrintWriter pw) throws IOException {

        int sRefIndex = getJonasWSContext().getServiceReferenceContextCount();
        // should only have 1 service-ref
        if (sRefIndex == 1) {

            ServiceReferenceContext ctx = getJonasWSContext().getServiceReferenceContext(0);
            QName desiredServiceQName = ctx.getServiceQName();

            Service myService = getDefinition().getService(desiredServiceQName);

            // Generate only if there is a Service
            if (myService != null) {
                pw.println();
                pw.println("  <!-- " + Messages.getMessage("wsdlService00", myService.getQName().getLocalPart()) + " -->");
                pw.println();

                for (Iterator portIterator = myService.getPorts().values().iterator(); portIterator.hasNext();) {
                    Port myPort = (Port) portIterator.next();
                    BindingEntry bEntry = getSymbolTable().getBindingEntry(myPort.getBinding().getQName());

                    // If this isn't an SOAP binding, skip it
                    if (bEntry.getBindingType() != BindingEntry.TYPE_SOAP) {
                        continue;
                    }

                    writeDeployPort(pw, myPort, bEntry, ctx);
                }
            }
        }
    }

    /**
     * Write out deployment and undeployment instructions for given WSDL port
     * @param pw PrintWriter
     * @param port wsdl:port
     * @param bEntry Axis BindingEntry
     * @param ctx ServiceReferanceContext
     */
    protected void writeDeployPort(PrintWriter pw, Port port, BindingEntry bEntry, ServiceReferenceContext ctx) {

        String serviceName = port.getName();
        boolean hasLiteral = bEntry.hasLiteral();
        boolean hasMIME = Utils.hasMIME(bEntry);


        Use use = Use.DEFAULT;
        String styleStr = "";
        Iterator iterator = bEntry.getBinding().getExtensibilityElements().iterator();

        // iterate throught extensibilityElements of given Port's Binding
        while (iterator.hasNext()) {
            Object obj = iterator.next();

            if (obj instanceof SOAPBinding) {
                use = Use.ENCODED;
            } else if (obj instanceof UnknownExtensibilityElement) {

                // TODO After WSDL4J supports soap12, change this code
                UnknownExtensibilityElement unkElement = (UnknownExtensibilityElement) obj;
                QName name = unkElement.getElementType();

                if (name.getNamespaceURI().equals(Constants.URI_WSDL12_SOAP) && name.getLocalPart().equals("binding")) {
                    use = Use.ENCODED;
                }
            }
        }

        if (getSymbolTable().isWrapped()) {
            styleStr = " style=\"" + Style.WRAPPED + "\"";
            use = Use.LITERAL;
        } else {
            styleStr = " style=\"" + bEntry.getBindingStyle().getName() + "\"";
            if (hasLiteral) {
                use = Use.LITERAL;
            }
        }

        String useStr = " use=\"" + use + "\"";

        pw.println("  <service name=\"" + serviceName + "\" " + styleStr + useStr + " provider=\"java:Noop\">");

        // MIME attachments don't work with multiref, so turn it off.
        if (hasMIME) {
            pw.println("      <parameter name=\"sendMultiRefs\" value=\"false\"/>");
        }
        // force JAXRPC 1.1 Type Mapping
        pw.println("      <parameter name=\"typeMappingVersion\" value=\"" + emitter.getTypeMappingVersion() + "\"/>");

        //writeDeployBinding(pw, bEntry);
        writeDeployTypes(pw, bEntry.getBinding(), hasLiteral, hasMIME, use);

        WSCFHandler[] handlers = ctx.getHandlers();
        if (handlers != null && handlers.length != 0) {
            pw.println("    <handlerInfoChain>");
            for (int i = 0; i < handlers.length; i++) {
                writeHandlerForPort(pw, (JOnASWSCFHandler) handlers[i], port);
            }
            pw.println("    </handlerInfoChain>");
        }
        pw.println("  </service>");
    }

    /**
     * Writes out a client-side handler
     * @param pw PrintWriter
     * @param handler EWS Handler description
     * @param port wsdl:port
     */
    private void writeHandlerForPort(PrintWriter pw, JOnASWSCFHandler handler, Port port) {

        /**
         * If handler contains no port-names, add the handler
         * else, check if the handler is applied to the current port
         */
        List ports = handler.getPortNames();
        if (ports.isEmpty()) {
            // handler applied for all ports
            writeHandler(pw, handler);
        } else if (ports.contains(port.getName())) {
            // handler applied for current port
            writeHandler(pw, handler);
        }
    }
    /**
     * Writes out a client-side handler
     * @param pw PrintWriter
     * @param handler EWS Handler description
     */
    private void writeHandler(PrintWriter pw, JOnASWSCFHandler handler) {

        pw.println("      <handlerInfo classname=\"" + handler.getHandlerClass() + "\">");
        WSCFInitParam[] param = handler.getInitParam();
        for (int i = 0; i < param.length; i++) {
            pw.println("        <parameter name=\"" + param[i].getParamName() + "\" value=\"" + param[i].getParamValue()
                    + "\"/>");
        }
        WSCFSOAPHeader[] headers = handler.getSoapHeader();
        for (int i = 0; i < headers.length; i++) {
            pw.println("        <header xmlns:ns=\"" + headers[i].getNamespaceURI() + "\" qname=\"ns:" + headers[i].getLocalpart()
                    + "\"/>");
        }
        pw.println("      </handlerInfo>");
        String[] roles = handler.getSoapRole();
        for (int i = 0; i < roles.length; i++) {
            pw.println("      <role soapActorName=\"" + roles[i] + "\"/>");
        }
    }

    /**
     * @return Returns the filename prefix
     */
    protected String getPrefix() {
        return WSDD_PREFIX;
    }
}
