package com.collabnet.ctf.events;

import com.vasoftware.sf.common.logger.Logger;
import com.vasoftware.sf.events.EventHandler60;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.StandardCharsets;

public class SynchronousHookScriptEventListener extends EventHandler60 {
    private static final Logger log = Logger.getLogger(SynchronousHookScriptEventListener.class);

    private static String hookDirectory = "/opt/collabnet/teamforge/hooks/synchronous/";

    @Override
    public void processEvent() throws Exception {
        boolean intendedException = false;
        int returnCode = 0;

        File hookScript = HookUtil.getHookScript(hookDirectory, getEventContext().getType(),
                getEventContext().getOperation());
        log.info("Going to call " + hookScript.getAbsolutePath() + " if it does exist.");
        try {

            if (hookScript.exists()) {

                Process runningProcess = runHookScript(hookScript);

                returnCode = runningProcess.waitFor();

                String errorMessage = processStream(runningProcess.getErrorStream());
                if (!errorMessage.equals("")) {
                    addErrorMessage(errorMessage);
                }

                String successMessage = processStream(runningProcess.getInputStream());
                if (!successMessage.equals("")) {
                    addSuccessMessage(successMessage);
                }

                if (returnCode != 0) {
                    intendedException = true;
                    throw new Exception("Hook script " + hookScript.getAbsolutePath() +
                            " rejected anticipated event with error code " + returnCode);
                }
            }

        } catch (Exception e) {
            if (!intendedException) {
                log.error("Exception occured: " + e.getMessage(), e);
            } else {
                log.warn("Hook script " + hookScript.getAbsolutePath() +
                        " rejected anticipated event with error code " + returnCode);
                throw e;
            }
        }
    }

    /**
     * Process the stream from the process
     * @param inputStream
     * @return
     * @throws IOException
     */
    private String processStream(InputStream inputStream) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
        StringBuffer buffer = new StringBuffer();
        while (reader.ready()) {
            String line = reader.readLine();
            if (line == null) {
                break;
            }
            buffer.append(line);
        }
        return buffer.toString();
    }

    /**
     * Runt he hook script
     *
     * @param hookScript
     * @return
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @throws IOException
     */
    private Process runHookScript(File hookScript)
            throws IllegalAccessException, InvocationTargetException, IOException {

        ProcessBuilder process = new ProcessBuilder(hookScript.getAbsolutePath());

        HookUtil.setEventContextInformationInEnvironment(getEventContext(), process);

        HookUtil.setResultValuesInEnvironment(process, getOriginalData(), "original");
        HookUtil.setResultValuesInEnvironment(process, getUpdatedData(), "updated");

        Process runningProcess = process.start();

        runningProcess.getOutputStream().close();

        return runningProcess;
    }
}
