/**
 *
 * Copyright 2015-2020 Florian Schmaus
 *
 * 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.
 */
package org.jivesoftware.smackx.filetransfer;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
import org.jivesoftware.smack.util.StringUtils;

import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest;
import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment;
import org.igniterealtime.smack.inttest.annotations.SmackIntegrationTest;
import org.igniterealtime.smack.inttest.util.ResultSyncPoint;

public class FileTransferIntegrationTest extends AbstractSmackIntegrationTest {

    private static final int MAX_FT_DURATION = 360;

    private final FileTransferManager ftManagerOne;
    private final FileTransferManager ftManagerTwo;

    public FileTransferIntegrationTest(SmackIntegrationTestEnvironment environment) {
        super(environment);
        ftManagerOne = FileTransferManager.getInstanceFor(conOne);
        ftManagerTwo = FileTransferManager.getInstanceFor(conTwo);
    }

    private static final byte[] dataToSend;

    static {
        dataToSend = StringUtils.insecureRandomString(1024 * 4 * 5).getBytes(StandardCharsets.UTF_8);
    }

    @SmackIntegrationTest
    public void fileTransferTest() throws Exception {
        genericfileTransferTest();
    }

    @SmackIntegrationTest
    public void ibbFileTransferTest() throws Exception {
        FileTransferNegotiator.IBB_ONLY = true;
        genericfileTransferTest();
        FileTransferNegotiator.IBB_ONLY = false;
    }

    private void genericfileTransferTest() throws Exception {
        final ResultSyncPoint<String, Exception> resultSyncPoint = new ResultSyncPoint<>();
        final FileTransferListener receiveListener = new FileTransferListener() {
            @Override
            public void fileTransferRequest(FileTransferRequest request) {
                byte[] dataReceived;
                IncomingFileTransfer ift = request.accept();
                try {
                    InputStream is = ift.receiveFile();
                    ByteArrayOutputStream os = new ByteArrayOutputStream();
                    int nRead;
                    byte[] buf = new byte[1024];
                    while ((nRead = is.read(buf, 0, buf.length)) != -1) {
                        os.write(buf, 0, nRead);
                    }
                    os.flush();
                    dataReceived = os.toByteArray();
                    if (Arrays.equals(dataToSend, dataReceived)) {
                        resultSyncPoint.signal("Received data matches send data. \\o/");
                    }
                    else {
                        resultSyncPoint.signal(new Exception("Received data does not match"));
                    }
                }
                catch (SmackException | IOException | XMPPErrorException | InterruptedException e) {
                    resultSyncPoint.signal(e);
                }
            }
        };
        ftManagerTwo.addFileTransferListener(receiveListener);

        OutgoingFileTransfer oft = ftManagerOne.createOutgoingFileTransfer(conTwo.getUser());
        oft.sendStream(new ByteArrayInputStream(dataToSend), "hello.txt", dataToSend.length, "A greeting");
        int duration = 0;
        while (!oft.isDone()) {
            switch (oft.getStatus()) {
            case error:
                throw new Exception("FileTransfer error: " + oft.getError());
            default:
                LOGGER.info("FileTransfer status: " + oft.getStatus() + ". Progress: " + oft.getProgress());
                break;
            }
            Thread.sleep(1000);
            if (++duration > MAX_FT_DURATION) {
                throw new Exception("Max duration reached");
            }
        }

        resultSyncPoint.waitForResult(MAX_FT_DURATION * 1000);

        ftManagerTwo.removeFileTransferListener(receiveListener);
    }
}

@@ -21,17 +21,17 @@
 2015-202
-0
+1
  Florian
@@ -1004,16 +1004,81 @@
 ngUtils;
+%0Aimport org.jivesoftware.smackx.filetransfer.FileTransfer.Status;
 %0A%0Aimport
@@ -4122,58 +4122,211 @@
     
-switch (oft.getStatus()) %7B%0A            case error:
+Status status = oft.getStatus();%0A            switch (status) %7B%0A            case error:%0A                FileTransfer.Error error = oft.getError();%0A                Exception exception = oft.getException();
 %0A   
@@ -4383,30 +4383,32 @@
 or: %22 + 
-oft.getError()
+error, exception
 );%0A     

Call OutgoingFiletransfer.getException() in case of error