package com.jscape.inet.ssh.protocol.v2.messages;

import com.jscape.inet.ssh.protocol.messages.Message;
import com.jscape.util.HexFormat;
import com.jscape.util.net.connection.MessageConnection;

import java.util.List;
import java.util.Random;

import static com.jscape.util.Parameters.assertNotNull;

/**
 * @author Alex Usun
 */
public class SshMsgKexInit
        extends Message<SshMsgKexInit.Handler> {

    public static final int COOKIE_LENGTH = 16;

    public final byte[] cookie;
    public final List<String> kexAlgorithms;
    public final List<String> serverHostKeyAlgorithms;
    public final List<String> encryptionAlgorithmsClientToServer;
    public final List<String> encryptionAlgorithmsServerToClient;
    public final List<String> macAlgorithmsClientToServer;
    public final List<String> macAlgorithmsServerToClient;
    public final List<String> compressionAlgorithmsClientToServer;
    public final List<String> compressionAlgorithmsServerToClient;
    public final List<String> languagesClientToServer;
    public final List<String> languagesServerToClient;
    public final boolean firstKexPacketFollows;
    public byte[] rawData;

    public static SshMsgKexInit messageFor(List<String> kexAlgorithms,
                                           List<String> serverHostKeyAlgorithms,
                                           List<String> encryptionAlgorithmsClientToServer,
                                           List<String> encryptionAlgorithmsServerToClient,
                                           List<String> macAlgorithmsClientToServer,
                                           List<String> macAlgorithmsServerToClient,
                                           List<String> compressionAlgorithmsClientToServer,
                                           List<String> compressionAlgorithmsServerToClient,
                                           List<String> languagesClientToServer,
                                           List<String> languagesServerToClient) {
        byte[] cookie = cookie();

        return new SshMsgKexInit(cookie,
                                 kexAlgorithms,
                                 serverHostKeyAlgorithms,
                                 encryptionAlgorithmsClientToServer,
                                 encryptionAlgorithmsServerToClient,
                                 macAlgorithmsClientToServer,
                                 macAlgorithmsServerToClient,
                                 compressionAlgorithmsClientToServer,
                                 compressionAlgorithmsServerToClient,
                                 languagesClientToServer,
                                 languagesServerToClient,
                                 false);
    }

    private static byte[] cookie() {
        Random random = new Random();
        byte[] cookie = new byte[COOKIE_LENGTH];
        random.nextBytes(cookie);

        return cookie;
    }

    public SshMsgKexInit(byte[] cookie,
                         List<String> kexAlgorithms,
                         List<String> serverHostKeyAlgorithms,
                         List<String> encryptionAlgorithmsClientToServer,
                         List<String> encryptionAlgorithmsServerToClient,
                         List<String> macAlgorithmsClientToServer,
                         List<String> macAlgorithmsServerToClient,
                         List<String> compressionAlgorithmsClientToServer,
                         List<String> compressionAlgorithmsServerToClient,
                         List<String> languagesClientToServer,
                         List<String> languagesServerToClient,
                         boolean firstKexPacketFollows) {
        assertNotNull(cookie);
        this.cookie = cookie;

        assertNotNull(kexAlgorithms);
        this.kexAlgorithms = kexAlgorithms;

        assertNotNull(serverHostKeyAlgorithms);
        this.serverHostKeyAlgorithms = serverHostKeyAlgorithms;

        assertNotNull(encryptionAlgorithmsClientToServer);
        this.encryptionAlgorithmsClientToServer = encryptionAlgorithmsClientToServer;

        assertNotNull(encryptionAlgorithmsServerToClient);
        this.encryptionAlgorithmsServerToClient = encryptionAlgorithmsServerToClient;

        assertNotNull(macAlgorithmsClientToServer);
        this.macAlgorithmsClientToServer = macAlgorithmsClientToServer;

        assertNotNull(macAlgorithmsServerToClient);
        this.macAlgorithmsServerToClient = macAlgorithmsServerToClient;

        assertNotNull(compressionAlgorithmsClientToServer);
        this.compressionAlgorithmsClientToServer = compressionAlgorithmsClientToServer;

        assertNotNull(compressionAlgorithmsServerToClient);
        this.compressionAlgorithmsServerToClient = compressionAlgorithmsServerToClient;

        assertNotNull(languagesClientToServer);
        this.languagesClientToServer = languagesClientToServer;

        assertNotNull(languagesServerToClient);
        this.languagesServerToClient = languagesServerToClient;

        this.firstKexPacketFollows = firstKexPacketFollows;
    }

    @Override
    public Class handlerClass() {
        return Handler.class;
    }

    @Override
    public void accept(Handler handler, MessageConnection<Message> connection) {
        handler.handle(this, connection);
    }

    @Override
    public String toString() {
        return "SshMsgKexInit {"
               + "cookie=" + HexFormat.formatData(this.cookie)
               + ", kexAlgorithms=" + this.kexAlgorithms
               + ", serverHostKeyAlgorithms=" + this.serverHostKeyAlgorithms
               + ", encryptionAlgorithmsClientToServer=" + this.encryptionAlgorithmsClientToServer
               + ", encryptionAlgorithmsServerToClient=" + this.encryptionAlgorithmsServerToClient
               + ", macAlgorithmsClientToServer=" + this.macAlgorithmsClientToServer
               + ", macAlgorithmsServerToClient=" + this.macAlgorithmsServerToClient
               + ", compressionAlgorithmsClientToServer=" + this.compressionAlgorithmsClientToServer
               + ", compressionAlgorithmsServerToClient=" + this.compressionAlgorithmsServerToClient
               + ", languagesClientToServer=" + this.languagesClientToServer
               + ", languagesServerToClient=" + this.languagesServerToClient
               + ", firstKexPacketFollows=" + this.firstKexPacketFollows
               + '}';
    }

    public interface Handler
            extends Message.HandlerBase {

        void handle(SshMsgKexInit message, MessageConnection<Message> connection);

    }
}
