/**
 * RSYNC 19.10.2012
 *
 * @author Philipp Haussleiter
 *
 */
package de.javastream.javassh;

import de.javastream.javassh.parser.ProcessParser;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.logging.Level;
import java.util.logging.Logger;

public class RSYNC {

    protected Runtime r;
    private int status = 255;
    private final static Logger LOG = Logger.getLogger(RSYNC.class.getName());
    private String options = "-avrz";
    private String prefix = "";
    private boolean targetDelete = false;
    private boolean daemonMonde = false;

    public RSYNC() {
        if (Utils.isWindows()) {
            throw new UnsupportedOperationException("Windows is currently not supported!");
        }
        this.prefix = "rsync ";
        r = Runtime.getRuntime();
    }

    public void pull(Host host, String remotePath, String localPath, final ProcessParser pp) {
        try {
            String command = buildCommand(host) + " " + host.user + "@" + host.url + ":" + remotePath + " " + localPath;
            LOG.log(Level.FINE, "running: {1}", new Object[]{command});
            Process p = r.exec(command);
            if (!needPassword(host)) {
                runProcess(p, pp);
            } else {
                status = 255;
                LOG.log(Level.SEVERE, "{0} needs a password. Please add the public ssh-key to {1}", new Object[]{host, host});
            }
        } catch (IOException ex) {
            LOG.log(Level.SEVERE, ex.getLocalizedMessage());
        }
    }

    public void push(String localPath, Host host, String remotePath, final ProcessParser pp) {
        try {
            String command = buildCommand(host) + " " + localPath + " " + host.user + "@" + host.url + ":" + remotePath;
            LOG.log(Level.FINE, "running: {1}", new Object[]{command});
            Process p = r.exec(command);
            if (!needPassword(host)) {
                runProcess(p, pp);
            } else {
                status = 255;
                LOG.log(Level.SEVERE, "{0} needs a password. Please add the public ssh-key to {1}", new Object[]{host, host});
            }
        } catch (IOException ex) {
            LOG.log(Level.SEVERE, ex.getLocalizedMessage());
        }
    }

    public void setOptions(final String options) {
        this.options = options;
    }

    public void daemonMode(final boolean flag) {
        this.daemonMonde = flag;
    }

    public void targetDelete(final boolean flag) {
        this.targetDelete = flag;
    }

    private boolean needPassword(Host host) throws IOException {
        return new SSH(host).needPassword();
    }

    private String buildCommand(Host host) {
        String cmd = prefix + " " + options;
        if (!daemonMonde) {
            cmd += " -e 'ssh -p " + host.port + "'";
        }
        if (targetDelete) {
            cmd += " --delete ";
        }
        return cmd;
    }

    protected void runProcess(Process p, ProcessParser pp) throws IOException {
        InputStream in = p.getInputStream();
        BufferedInputStream buf = new BufferedInputStream(in);
        InputStreamReader inread = new InputStreamReader(buf);
        BufferedReader bufferedreader = new BufferedReader(inread);
        pp.parse(bufferedreader);
        try {
            status = p.waitFor();
            LOG.log(Level.FINE, "exit value = {0}", status);
        } catch (InterruptedException e) {
            LOG.log(Level.SEVERE, e.getLocalizedMessage());
        } finally {
            // Close the InputStream
            bufferedreader.close();
            inread.close();
            buf.close();
            in.close();
        }
    }

    public int getStatus() {
        return status;
    }
}