package leigh.tesseract;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import leigh.mecha.cred.Credential;
import leigh.mecha.log.MechaLogger;
import leigh.mecha.log.MechaLoggerFactory;
import org.apache.commons.io.IOUtils;

import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Class for executing mass SSH commands.
 *
 * @author Alex Leigh
 */
public class Tesseract {
    private static final MechaLogger logger = MechaLoggerFactory.getLogger(Tesseract.class);
    private final ThreadPoolExecutor tpe;
    private final ResultWriter resultWriter;
    private final HostGroup hostGroup;

    public Tesseract(ThreadPoolExecutor tpe, ResultWriter resultWriter, HostGroup hostGroup) {
        this.tpe = tpe;
        this.resultWriter = resultWriter;
        this.hostGroup = hostGroup;
    }

    public void excecute(String cmd) {
        for (String host : hostGroup.getHosts()) {
            tpe.execute(new Runnable() {
                @Override
                public void run() {
                    String s;
                    int exitStatus;
                    try {
                        Credential cred = hostGroup.getCredential(host);
                        String key = hostGroup.getSshKey(host);

                        JSch jSch = new JSch();
                        if (key != null) {
                            jSch.addIdentity(key);
                        }

                        Session session;
                        Channel channel;
                        session = jSch.getSession(cred.getUsername(), host);
                        Properties config = new Properties();
                        config.put("StrictHostKeyChecking", "no");
                        session.setConfig(config);
                        session.setPassword(cred.getPassword());
                        session.connect();
                        channel = session.openChannel("exec");
                        ((ChannelExec) channel).setCommand(cmd);
                        channel.connect();
                        s = IOUtils.toString(channel.getInputStream());
                        channel.disconnect();
                        exitStatus = channel.getExitStatus();
                        session.disconnect();
                    } catch (Exception e) {
                        s = e.toString();
                        exitStatus = -1;
                    }

                    try {
                        resultWriter.output(host, s.trim(), exitStatus);
                    } catch (IOException e) {
                        logger.error("Failed to write result. [e: {}]", e.toString());
                    }
                }
            });
        }
    }
}
