/*
 * Copyright (c) 2004-2020 The YAWL Foundation. All rights reserved.
 * The YAWL Foundation is a collaboration of individuals and
 * organisations who are committed to improving workflow technology.
 *
 * This file is part of YAWL. YAWL 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.
 *
 * YAWL 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 YAWL. If not, see <http://www.gnu.org/licenses/>.
 */

package org.yawlfoundation.yawl.engine.interfce.interfaceX;

import org.yawlfoundation.yawl.engine.YSpecificationID;
import org.yawlfoundation.yawl.engine.interfce.Marshaller;
import org.yawlfoundation.yawl.engine.interfce.WorkItemRecord;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;

/**
 *  InterfaceX_ServiceSideServer passes exception event calls from the engine to the
 *  exception service.
 *
 *  This class is a member class of Interface X, which provides an interface
 *  between the YAWL Engine and a Custom YAWL Service that manages exception
 *  handling at the process level.
 */
/*  InterfaceB_EnvironmentBasedServer was used as a template for this class.
 *
 *  Schematic of Interface X:
 *                                          |
 *                           EXCEPTION      |                              INTERFACE X
 *                            GATEWAY       |                                SERVICE
 *                  (implements) |          |                       (implements) |
 *                               |          |                                    |
 *  +==========+   ----->   ENGINE-SIDE  ---|-->   SERVICE-SIDE  ----->   +=============+
 *  || YAWL   ||              CLIENT        |        SERVER               || EXCEPTION ||
 *  || ENGINE ||                            |                             ||  SERVICE  ||
 *  +==========+   <-----   ENGINE-SIDE  <--|---   SERVICE-SIDE  <-----   +=============+
 *                            SERVER        |         CLIENT
 *                                          |
 *  @author Michael Adams                   |
 *  @version 0.8, 04/07/2006
 */

public class InterfaceX_ServiceSideServer extends HttpServlet {

    private InterfaceX_Service _controller;

    public void init(ServletConfig servletConfig) throws ServletException {
        super.init(servletConfig);
        ServletContext context = servletConfig.getServletContext();
        String controllerClassName =
                context.getInitParameter("InterfaceX_Service");
        try {
            Class controllerClass = Class.forName(controllerClassName);

            // If the class has a getInstance() method, call that method rather than
            // calling a constructor (& thus instantiating 2 instances of the class)
            try {
                Method instMethod = controllerClass.getDeclaredMethod("getInstance");
                _controller = (InterfaceX_Service) instMethod.invoke(null);
            }
            catch (NoSuchMethodException nsme) {
                _controller = (InterfaceX_Service) controllerClass.newInstance();
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }


    public void doGet(HttpServletRequest request, HttpServletResponse response)
                                                 throws IOException, ServletException {
        _controller.doGet(request, response);
    }


    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/xml; charset=UTF-8");
        PrintWriter outputWriter = response.getWriter();
        StringBuilder output = new StringBuilder();
        output.append("<response>");
        output.append(processPostQuery(request));
        output.append("</response>");
        outputWriter.write(output.toString());
        outputWriter.flush();
        outputWriter.close();
    }

    // receives the post and calls the specified Exception service method 
    private String processPostQuery(HttpServletRequest request) {

        // unpack the stringified parameters
        WorkItemRecord wir = null ;
        String workItemXML = request.getParameter("workItem");
        if (workItemXML != null) wir = Marshaller.unmarshalWorkItem(workItemXML);

        boolean preCheck = false ;
        String sPreCheck = request.getParameter("preCheck") ;
        if (sPreCheck != null) preCheck = sPreCheck.equalsIgnoreCase("TRUE");

        boolean primary = true;
        String sPrimary = request.getParameter("primary");
        if (sPrimary != null) primary = sPrimary.equalsIgnoreCase("TRUE");

        // unpack the strings
        String data = request.getParameter("data");
        String caseID = request.getParameter("caseID");
        String specID = request.getParameter("specID");
        String specVersion = request.getParameter("specVersion");
        String specURI = request.getParameter("specURI");
        String taskList = request.getParameter("taskList");
        String resourceID = request.getParameter("resourceid");

        switch (actionToNotifyType(request.getParameter("action"))) {
            case InterfaceX_EngineSideClient.NOTIFY_CHECK_CASE_CONSTRAINTS:
               _controller.handleCheckCaseConstraintEvent(
                       new YSpecificationID(specID, specVersion, specURI),
                       caseID, data, preCheck);
               break;
            case InterfaceX_EngineSideClient.NOTIFY_CHECK_ITEM_CONSTRAINTS:
                _controller.handleCheckWorkItemConstraintEvent(wir, data, preCheck);
               break;
            case InterfaceX_EngineSideClient.NOTIFY_WORKITEM_ABORT:
               _controller.handleWorkItemAbortException(wir, data);
               break;
            case InterfaceX_EngineSideClient.NOTIFY_TIMEOUT:
               _controller.handleTimeoutEvent(wir, taskList);
               break;
            case InterfaceX_EngineSideClient.NOTIFY_RESOURCE_UNAVAILABLE:
               _controller.handleResourceUnavailableException(resourceID, wir, data, primary);
               break;
            case InterfaceX_EngineSideClient.NOTIFY_CONSTRAINT_VIOLATION:
               _controller.handleConstraintViolationException(wir, data);
               break;
            case InterfaceX_EngineSideClient.NOTIFY_CANCELLED_CASE:
               _controller.handleCaseCancellationEvent(caseID);
               break;
            default: return "<failure>Unknown action: '" + request.getParameter("action") +
                            "'</failure>"; 
        }
        return "<success/>";
    }

    /** @return the 'action' converted to an 'int' notify type, or -1 if invalid */
    private int actionToNotifyType(String action) {
        try {
            return Integer.parseInt(action);
        }
        catch (NumberFormatException nfe) {
            return -1;
        }
    }


}