/*
 * Copyright (C)2009 - SSHJ Contributors
 *
 * 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 net.schmizz.sshj.userauth.method;

import net.schmizz.sshj.common.Buffer;
import net.schmizz.sshj.common.Message;
import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.transport.TransportException;
import net.schmizz.sshj.userauth.UserAuthException;

/** Implements the {@code keyboard-interactive} authentication method. */
public class AuthKeyboardInteractive
        extends AbstractAuthMethod {

    private final ChallengeResponseProvider provider;

    public AuthKeyboardInteractive(ChallengeResponseProvider provider) {
        super("keyboard-interactive");
        this.provider = provider;
    }

    @Override
    public SSHPacket buildReq()
            throws UserAuthException {
        return super.buildReq() // the generic stuff
                .putString("") // lang-tag
                .putString(buildCommaSeparatedSubmethodList());
    }

    private String buildCommaSeparatedSubmethodList() {
        StringBuilder sb = new StringBuilder();
        for (String submethod : provider.getSubmethods()) {
            if (sb.length() > 0)
                sb.append(",");
            sb.append(submethod);
        }
        return sb.toString();
    }

    private static class CharArrWrap {

        private final char[] arr;

        private CharArrWrap(char[] arr) {
            this.arr = arr;
        }
    }

    @Override
    public void handle(Message cmd, SSHPacket buf)
            throws UserAuthException, TransportException {
        if (cmd != Message.USERAUTH_60) {
            super.handle(cmd, buf);
        } else {
            final CharArrWrap[] userReplies;
            try {
                provider.init(makeAccountResource(), buf.readString(), buf.readString());
                buf.readString(); // lang-tag
                final int numPrompts = buf.readUInt32AsInt();
                userReplies = new CharArrWrap[numPrompts];
                for (int i = 0; i < numPrompts; i++) {
                    final String prompt = buf.readString();
                    final boolean echo = buf.readBoolean();
                    log.debug("Requesting response for challenge `{}`; echo={}", prompt, echo);
                    userReplies[i] = new CharArrWrap(provider.getResponse(prompt, echo));
                }
            } catch (Buffer.BufferException be) {
                throw new UserAuthException(be);
            }
            respond(userReplies);
        }
    }

    private void respond(CharArrWrap[] userReplies)
            throws TransportException {
        final SSHPacket pkt = new SSHPacket(Message.USERAUTH_INFO_RESPONSE).putUInt32(userReplies.length);
        for (final CharArrWrap response : userReplies)
            pkt.putSensitiveString(response.arr);
        params.getTransport().write(pkt);
    }

    @Override
    public boolean shouldRetry() {
        return provider.shouldRetry();
    }

}