/**
 * Copyright (c) 2016-2024 Linagora
 * 
 * This program/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 (at your
 * option) any later version.
 * 
 * This program/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 program/library; If not, see http://www.gnu.org/licenses/
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.bc.filetransfer;

import java.io.File;
import java.io.FileOutputStream;

import javax.xml.namespace.QName;

import org.ow2.petals.component.framework.jbidescriptor.generated.MEPType;
import org.ow2.petals.component.framework.junit.ResponseMessage;
import org.ow2.petals.component.framework.junit.impl.ConsumesServiceConfiguration;
import org.ow2.petals.component.framework.junit.impl.ProvidesServiceConfiguration;
import org.w3c.dom.Node;

public abstract class AbstractSimpleTestEnvironment extends AbstractTest {

    // ----------------------------------------------
    // Expected XML tag name in request and reply
    // ----------------------------------------------
    protected static final String EXPECTED_NAMESPACE = FileTransferConstants.FILETRANSFER_SERVICE_NS;

    protected static final QName EXPECTED_OP_DIR_ELT_ROOT = new QName(EXPECTED_NAMESPACE, "dirResponse");

    protected static final QName EXPECTED_OP_CHECKFILE_ELT_ROOT = new QName(EXPECTED_NAMESPACE, "checkFileResponse");

    protected static final QName EXPECTED_NODE_FILENAME = new QName(EXPECTED_NAMESPACE, "filename");

    protected static final QName EXPECTED_NODE_EXIST = new QName(EXPECTED_NAMESPACE, "exist");

    protected static final QName EXPECTED_NODE_XOP = new QName("http://www.w3.org/2004/08/xop/include", "Include");

    protected static final String EXPECTED_ATTR_XOP_HREF = "href";

    // ----------------------------------------------
    // Service unit configurations
    // ----------------------------------------------
    protected static final String TEST_NS = "http://testProvideService";

    protected static final QName TEST_ITF = new QName(TEST_NS, "testProvideInterfaceName");

    protected static final QName TEST_SVC = new QName(TEST_NS, "testServiceName");

    protected static final String TEST_EP = "testEndpointName";

    protected static final QName TEST_OP_PUT = new QName(EXPECTED_NAMESPACE, FileTransferConstants.PUT_OPERATION);

    protected static final QName TEST_OP_GET = new QName(EXPECTED_NAMESPACE, FileTransferConstants.GET_OPERATION);

    protected static final QName TEST_OP_GET_AS_ATTACHMENT = new QName(EXPECTED_NAMESPACE,
            FileTransferConstants.GET_ATTACHMENT_OPERATION);

    protected static final QName TEST_OP_DIR = new QName(EXPECTED_NAMESPACE, FileTransferConstants.DIR_OPERATION);

    protected static final QName TEST_OP_DEL = new QName(EXPECTED_NAMESPACE, FileTransferConstants.DEL_OPERATION);

    protected static final QName TEST_OP_CHECKFILE = new QName(EXPECTED_NAMESPACE,
            FileTransferConstants.CHECK_FILE_OPERATION);

    protected static final QName TEST_OP_MPUT = new QName(EXPECTED_NAMESPACE, FileTransferConstants.MPUT_OPERATION);

    protected static final QName TEST_OP_MGET = new QName(EXPECTED_NAMESPACE, FileTransferConstants.MGET_OPERATION);

    protected static final long DEFAULT_TIMEOUT = 5000;

    protected static ConsumesServiceConfiguration createConsumesPut(final File listeningDir, final String transfertMode) {

        final ConsumesServiceConfiguration sc = new ConsumesServiceConfiguration(TEST_ITF, TEST_SVC, TEST_EP);
        sc.setOperation(TEST_OP_PUT);
        sc.setTimeout(DEFAULT_TIMEOUT);
        sc.setParameter(new QName(FileTransferConstants.FILETRANSFER_SERVICE_NS, FileTransferConstants.PARAM_FOLDER),
                listeningDir.getAbsolutePath());
        sc.setParameter(
                new QName(FileTransferConstants.FILETRANSFER_SERVICE_NS, FileTransferConstants.PARAM_TRANSFER_MODE),
                transfertMode);
        return sc;
    }

    protected static ConsumesServiceConfiguration createConsumesMput(final File listeningDir,
            final String transfertMode) {

        final ConsumesServiceConfiguration sc = new ConsumesServiceConfiguration(TEST_ITF, TEST_SVC, TEST_EP);
        sc.setOperation(TEST_OP_MPUT);
        sc.setParameter(new QName(FileTransferConstants.FILETRANSFER_SERVICE_NS, FileTransferConstants.PARAM_FOLDER),
                listeningDir.getAbsolutePath());
        sc.setParameter(
                new QName(FileTransferConstants.FILETRANSFER_SERVICE_NS, FileTransferConstants.PARAM_TRANSFER_MODE),
                transfertMode);
        sc.setParameter(new QName(FileTransferConstants.FILETRANSFER_SERVICE_NS, FileTransferConstants.PARAM_BASE_MSG),
                "<ver:mput xmlns:ver=\"" + FileTransferConstants.FILETRANSFER_SERVICE_NS + "\">"
                        + "<ver:attachments><ver:filename>$attachment</ver:filename></ver:attachments></ver:mput>");
        return sc;
    }

    protected static ConsumesServiceConfiguration createConsumesGet(final File listeningDir,
            final String transfertMode) {

        final ConsumesServiceConfiguration sc = new ConsumesServiceConfiguration(TEST_ITF, TEST_SVC, TEST_EP);
        sc.setOperation(TEST_OP_GET);
        sc.setMEP(MEPType.IN_OUT);
        sc.setParameter(new QName(FileTransferConstants.FILETRANSFER_SERVICE_NS, FileTransferConstants.PARAM_FOLDER),
                listeningDir.getAbsolutePath());
        sc.setParameter(
                new QName(FileTransferConstants.FILETRANSFER_SERVICE_NS, FileTransferConstants.PARAM_TRANSFER_MODE),
                transfertMode);
        return sc;
    }

    protected static ProvidesServiceConfiguration createProvides(final File outputDir, final String filename) {
        return createProvides(outputDir, filename, false);
    }

    protected static ProvidesServiceConfiguration createProvides(final File outputDir, final String filename,
            final File backupDir) {
        return createProvides(outputDir, filename, backupDir, false);
    }

    protected static ProvidesServiceConfiguration createProvides(final File outputDir, final String filename,
            final boolean isReadOnly) {
        return createProvides(outputDir, filename, null, isReadOnly);
    }

    private static ProvidesServiceConfiguration createProvides(final File outputDir, final String filename,
            final File backupDir, final boolean isReadOnly) {

        final ProvidesServiceConfiguration sc = new ProvidesServiceConfiguration(TEST_ITF, TEST_SVC, TEST_EP);
        sc.setParameter(new QName(FileTransferConstants.FILETRANSFER_SERVICE_NS, FileTransferConstants.PARAM_FOLDER),
                outputDir.getAbsolutePath());
        sc.setParameter(new QName(FileTransferConstants.FILETRANSFER_SERVICE_NS, FileTransferConstants.PARAM_FILENAME),
                filename);
        if (backupDir != null) {
            sc.setParameter(new QName(FileTransferConstants.FILETRANSFER_SERVICE_NS,
                    FileTransferConstants.PARAM_BACKUP_DIRECTORY), backupDir.getAbsolutePath());
        }
        if (isReadOnly) {
            sc.setParameter(
                    new QName(FileTransferConstants.FILETRANSFER_SERVICE_NS, FileTransferConstants.PARAM_ISREADONLY),
                    Boolean.toString(isReadOnly));
        }
        return sc;
    }

    protected static QName buildQName(final Node node) {
        if (node.getPrefix() != null) {
            return new QName(node.getNamespaceURI(), node.getLocalName(), node.getPrefix());
        } else {
            return new QName(node.getNamespaceURI(), node.getLocalName());
        }
    }

    /**
     * @param node
     * @param response
     * @param expectedFilename
     *            If not {@code null}, the XOP node will be checked against the value of this filename.
     */
    protected static void assertXopNodeIncluded(final Node node,
            final ResponseMessage response, final String expectedFilename) {
        final Node xopNode = node.getFirstChild();
        assertNotNull(xopNode);
        assertEquals(EXPECTED_NODE_XOP, buildQName(xopNode));
        assertNotNull(xopNode.getAttributes());
        final Node attrHref = xopNode.getAttributes().getNamedItem(EXPECTED_ATTR_XOP_HREF);
        assertNotNull(attrHref);
        final String attrHrefValue = attrHref.getTextContent();
        assertNotNull(attrHrefValue);
        final String filename = attrHrefValue.substring("cid:".length());
        if (expectedFilename != null) {
            assertEquals(expectedFilename, filename);
        }
        assertTrue(response.getOutAttachmentNames().contains(filename));
    }

    protected static File createXmlFile(final File dir) throws Exception {

        return createXmlFile(dir, "filetransfer à Test.xml");
    }

    protected static File createXmlFile(final File dir, final String file) throws Exception {

        // the file contains a correct message to send to the component to continue testing
        final String payload = "<?xml version='1.0' encoding='UTF-8'?><" + FileTransferConstants.PUT_OPERATION
                + " xmlns=\"" + TEST_NS + "\">blablabla</" + FileTransferConstants.PUT_OPERATION + ">";

        final File tempFile;
        if (file == null) {
            tempFile = File.createTempFile("tmp", ".xml", dir);
        } else {
            tempFile = new File(dir, file);
        }
        try (final FileOutputStream outputStream = new FileOutputStream(tempFile)) {
            outputStream.write(payload.getBytes());
        }
        return tempFile;
    }
}
