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

import com.jscape.inet.ssh.protocol.v2.marshaling.*;
import com.jscape.inet.ssh.protocol.v2.marshaling.keys.PublicKeyCodec;
import com.jscape.inet.ssh.protocol.v2.marshaling.keys.PublicKeyCodecs;
import com.jscape.inet.ssh.protocol.v2.marshaling.keys.SignatureCodec;
import com.jscape.inet.ssh.protocol.v2.marshaling.keys.SignatureCodecs;
import com.jscape.inet.ssh.protocol.v2.messages.*;
import com.jscape.util.CollectionTools;
import com.jscape.util.io.DataCodec;

import java.security.PublicKey;
import java.util.Collection;

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

/**
 * @author Alex Usun
 */
public class PasswordPublicKeyAuthenticationMessages
        implements MessageCodec.Factory {
    
    public static final Class[] REQUEST_TYPES = {
            SshMsgUserAuthRequestNone.class,
            SshMsgUserAuthRequestPassword.class,
            SshMsgUserAuthRequestNewPassword.class,
            SshMsgUserAuthRequestPublicKey.class,
            SshMsgUserAuthRequestPublicKeySignature.class,
            SshMsgUserAuthRequestKeyboardInteractive.class
    };
    
    private final MessageCodec.Entry[] entries;
    
    public static MessageCodec init(MessageCodec codec) {
        return AuthenticationMessages.init(codec.set(entries()));
    }
    
    public static PasswordPublicKeyAuthenticationMessages defaultMessages() {
        Collection<MessageCodec.Entry> entries = CollectionTools.collect(AuthenticationMessages.ENTRIES, entries());
        return new PasswordPublicKeyAuthenticationMessages(entries.toArray(new MessageCodec.Entry[entries.size()]));
    }
    
    public static MessageCodec initPasswordChangeRequestEntry(MessageCodec codec) {
        return codec.set(new MessageCodec.Entry(60, new SshMsgUserAuthPasswdChangeReqCodec(), SshMsgUserAuthPasswdChangeReq.class));
    }
    
    public static MessageCodec initPublicKeyOkEntry(MessageCodec codec) {
        DataCodec<PublicKey> publicKeyCodec = PublicKeyCodecs.init(new PublicKeyCodec());
        return codec.set(new MessageCodec.Entry(60, new SshMsgUserAuthPkOkCodec(publicKeyCodec), SshMsgUserAuthPkOk.class));
    }
    
    public static MessageCodec initKeyboardInteractiveEntry(MessageCodec codec) {
        return codec.set(new MessageCodec.Entry(60, new SshMsgUserAuthInfoRequestCodec(), SshMsgUserAuthInfoRequest.class),
                         new MessageCodec.Entry(61, new SshMsgUserAuthInfoResponseCodec(), SshMsgUserAuthInfoResponse.class));
    }
    
    private static MessageCodec.Entry[] entries() {
        return new MessageCodec.Entry[]{
                new MessageCodec.Entry(50, new SshMsgUserAuthRequestCodec(methodEntries()), REQUEST_TYPES)
        };
    }
    
    private static SshMsgUserAuthRequestCodec.Entry[] methodEntries() {
        DataCodec<PublicKey> publicKeyCodec = PublicKeyCodecs.init(new PublicKeyCodec());
        DataCodec<Signature> signatureCodec = SignatureCodecs.init(new SignatureCodec());
        
        return new SshMsgUserAuthRequestCodec.Entry[]{
                new SshMsgUserAuthRequestCodec.Entry("none", new SshMsgUserAuthRequestNoneCodec(), SshMsgUserAuthRequestNone.class),
                new SshMsgUserAuthRequestCodec.Entry("password", new SshMsgUserAuthRequestPasswordCodec(), SshMsgUserAuthRequestPassword.class, SshMsgUserAuthRequestNewPassword.class),
                new SshMsgUserAuthRequestCodec.Entry("publickey", new SshMsgUserAuthRequestPublicKeyCodec(publicKeyCodec, signatureCodec), SshMsgUserAuthRequestPublicKey.class, SshMsgUserAuthRequestPublicKeySignature.class),
                new SshMsgUserAuthRequestCodec.Entry("keyboard-interactive", new SshMsgUserAuthRequestKeyboardInteractiveCodec(), SshMsgUserAuthRequestKeyboardInteractive.class)
        };
    }
    
    public PasswordPublicKeyAuthenticationMessages(MessageCodec.Entry... entries) {
        assertNotNull(entries);
        this.entries = entries;
    }
    
    @Override
    public MessageCodec update(MessageCodec codec) {
        return codec.set(this.entries);
    }
}
