package org.xbib.files.ftp.fs.test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.xbib.files.ftp.FTPClient;
import org.xbib.files.ftp.FTPClientConfig;
import org.xbib.files.ftp.parser.DefaultFTPFileEntryParserFactory;

import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.stream.Stream;
import org.xbib.files.ftp.fs.ConnectionMode;
import org.xbib.files.ftp.fs.DefaultFileSystemExceptionFactory;
import org.xbib.files.ftp.fs.FTPEnvironment;

public class FTPEnvironmentSetterTest {

    public static Stream<Arguments> getParameters() {
        return Stream.of(
                Arguments.of("withSoTimeout", "soTimeout", 1000),
                Arguments.of("withSendBufferSize", "sendBufferSize", 4096),
                Arguments.of("withReceiveBufferSize", "receiveBufferSize", 2048),
                Arguments.of("withTcpNoDelay", "tcpNoDelay", true),
                Arguments.of("withKeepAlive", "keepAlive", true),
                Arguments.of("withSocketFactory", "socketFactory", SocketFactory.getDefault()),
                Arguments.of("withServerSocketFactory", "serverSocketFactory", ServerSocketFactory.getDefault()),
                Arguments.of("withConnectTimeout", "connectTimeout", 1000),
                Arguments.of("withProxy", "proxy", new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", 21))),
                Arguments.of("withCharset", "charset", StandardCharsets.UTF_8),
                Arguments.of("withControlEncoding", "controlEncoding", "UTF-8"),
                Arguments.of("withStrictlyMultilineParsing", "strictMultilineParsing", true),
                Arguments.of("withDataTimeout", "dataTimeout", 1000),
                Arguments.of("withParserFactory", "parserFactory", new DefaultFTPFileEntryParserFactory()),
                Arguments.of("withRemoteVerificationEnabled", "remoteVerificationEnabled", true),
                Arguments.of("withDefaultDirectory", "defaultDir", "/"),
                Arguments.of("withConnectionMode", "connectionMode", ConnectionMode.PASSIVE),
                Arguments.of("withActiveExternalIPAddress", "activeExternalIPAddress", "127.0.0.1"),
                Arguments.of("withPassiveLocalIPAddress", "passiveLocalIPAddress", "127.0.0.1"),
                Arguments.of("withReportActiveExternalIPAddress", "reportActiveExternalIPAddress", "127.0.0.1"),
                Arguments.of("withBufferSize", "bufferSize", 1000),
                Arguments.of("withSendDataSocketBufferSize", "sendDataSocketBufferSize", 1024),
                Arguments.of("withReceiveDataSocketBufferSize", "receiveDataSocketBufferSize", 2048),
                Arguments.of("withClientConfig", "clientConfig", new FTPClientConfig()),
                Arguments.of("withUseEPSVwithIPv4", "useEPSVwithIPv4", true),
                Arguments.of("withControlKeepAliveTimeout", "controlKeepAliveTimeout", 1000L),
                Arguments.of("withControlKeepAliveReplyTimeout", "controlKeepAliveReplyTimeout", 1000),
                Arguments.of("withPassiveNatWorkaroundStrategy", "passiveNatWorkaroundStrategy", new FTPClient.NatServerResolverImpl(new FTPClient())),
                Arguments.of("withAutodetectEncoding", "autodetectEncoding", true),
                Arguments.of("withClientConnectionCount", "clientConnectionCount", 5),
                Arguments.of("withFileSystemExceptionFactory", "fileSystemExceptionFactory", DefaultFileSystemExceptionFactory.INSTANCE)
        );
    }

    @ParameterizedTest
    @MethodSource("getParameters")
    public void testSetter(String setterString, String propertyName, Object propertyValue) throws Exception {
        Method setter = findMethod(setterString);
        FTPEnvironment env = new FTPEnvironment();
        assertEquals(Collections.emptyMap(), env);
        setter.invoke(env, propertyValue);
        assertEquals(Collections.singletonMap(propertyName, propertyValue), env);
    }

    private Method findMethod(String methodName) {
        for (Method method : FTPEnvironment.class.getMethods()) {
            if (method.getName().equals(methodName) && method.getParameterTypes().length == 1) {
                return method;
            }
        }
        throw new AssertionError("Could not find method " + methodName);
    }

}
