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

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

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Alex Usun
 */
public class SessionChannel
        extends Channel
        implements SshMsgChannelRequestPtyReq.Handler,
                   SshMsgChannelRequestEnv.Handler,
                   SshMsgChannelRequestWindowChange.Handler {

    private final Map<String, String> environmentVariables;
    private boolean occupied;
    private String terminalEnvironmentVariable;
    private int terminalCharactersWidth;
    private int terminalRowsHeight;
    private int terminalPixelsWidth;
    private int terminalPixelsHeight;
    private List<TerminalMode> terminalModes;

    public SessionChannel(MessageConnection<Message> connection,
                          int localId,
                          int remoteId,
                          long localInitialWindowSize,
                          int localMaxPacketSize,
                          long remoteInitialWindowSize,
                          int remoteMaxPacketSize) {
        super(connection, localId, remoteId, localInitialWindowSize, localMaxPacketSize, remoteInitialWindowSize, remoteMaxPacketSize);
        this.environmentVariables = new ConcurrentHashMap<>();
        this.terminalModes = Collections.emptyList();
    }

    @Override
    public void handle(SshMsgChannelRequestPtyReq message, MessageConnection<Message> connection) {
        this.terminalEnvironmentVariable = message.terminalEnvironmentVariable;
        this.terminalCharactersWidth = message.terminalCharactersWidth;
        this.terminalRowsHeight = message.terminalRowsHeight;
        this.terminalPixelsWidth = message.terminalPixelsWidth;
        this.terminalPixelsHeight = message.terminalPixelsHeight;
        this.terminalModes = message.terminalModes;

        sendRequestSuccess(message.wantReply);
    }

    @Override
    public void handle(SshMsgChannelRequestEnv message, MessageConnection<Message> connection) {
        this.environmentVariables.put(message.name, message.value);
        sendRequestSuccess(message.wantReply);
    }

    @Override
    public void handle(SshMsgChannelRequestWindowChange message, MessageConnection<Message> connection) {
        this.terminalCharactersWidth = message.terminalCharactersWidth;
        this.terminalRowsHeight = message.terminalRowsHeight;
        this.terminalPixelsWidth = message.terminalPixelsWidth;
        this.terminalPixelsHeight = message.terminalPixelsHeight;
        sendRequestSuccess(message.wantReply);
    }

    public boolean occupied() {
        return this.occupied;
    }

    public void setOccupied() {
        this.occupied = true;
    }

    public Map<String, String> environmentVariables() {
        return this.environmentVariables;
    }

    public String terminalEnvironmentVariable() {
        return this.terminalEnvironmentVariable;
    }

    public int terminalCharactersWidth() {
        return this.terminalCharactersWidth;
    }

    public int terminalRowsHeight() {
        return this.terminalRowsHeight;
    }

    public int terminalPixelsWidth() {
        return this.terminalPixelsWidth;
    }

    public int terminalPixelsHeight() {
        return this.terminalPixelsHeight;
    }

    public List<TerminalMode> terminalModes() {
        return this.terminalModes;
    }

    public void exitStatus(int exitStatus) {
        send(new SshMsgChannelRequestExitStatus(this.remoteId, exitStatus));
    }

    @Override
    public String toString() {
        return "SessionChannel {"
                + "localId=" + this.localId
                + ", remoteId=" + this.remoteId
                + ", localWindow=" + this.localWindow
                + ", localWindowMinSize=" + this.localWindowMinSize
                + ", localMaxPacketSize=" + this.localMaxPacketSize
                + ", remoteWindow=" + this.remoteWindow
                + ", remoteMaxPacketSize=" + this.remoteMaxPacketSize
                + ", environmentVariables=" + this.environmentVariables
                + ", occupied=" + this.occupied
                + ", closed=" + this.closed
                + '}';
    }
}
