/*
 *     Created by Angel Leon (@gubatron)
 *     Copyright (c) 2011-2026, FrostWire(R). All rights reserved.
 * 
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package org.team_hermes.wireshare.search.telluride;

import org.team_hermes.wireshare.concurrent.concurrent.ThreadExecutor;
import org.team_hermes.wireshare.util.Logger;

import java.io.*;

/**
 * A Java process builder and parser for the telluride cloud downloader.
 * Launches the process passing the appropriate options, parses its output to dispatch events to a TellurideListener
 */
public final class TellurideLauncher {

    private static final Logger LOG = Logger.getLogger(TellurideLauncher.class);

    /**
     * We're not using this method anymore, we now communicate with Telluride via HTTP
     * We're leaving this code for unit test purposes.
     *
     * @param metaOnly Get only metadata about the downloadUrl. If set to true, it ignores audioOnly
     */
    public static void launch(final File executable,
                              final String downloadUrl,
                              final File saveDirectory,
                              final boolean audioOnly,
                              final boolean metaOnly,
                              final boolean playlistOnly,
                              final boolean verboseOutput,
                              TellurideListener processListener) {
        checkExecutable(executable);
        ThreadExecutor.startThread(
                launchRunnable(
                        executable,
                        downloadUrl,
                        saveDirectory,
                        audioOnly,
                        metaOnly,
                        playlistOnly,
                        verboseOutput,
                        processListener),
                "telluride-process-adapter:" + downloadUrl);
    }

    private static void checkExecutable(final File executable) {
        if (executable == null) {
            throw new IllegalArgumentException("TellurideLauncher::checkExecutable executable path is null, no telluride to launch");
        }
        if (!executable.isFile()) {
            throw new IllegalArgumentException("TellurideLauncher::checkExecutable " + executable + " is not a file");
        }
        if (!executable.canExecute()) {
            throw new IllegalArgumentException("TellurideLauncher::checkExecutable " + executable + " is not executable");
        }
    }

    private static Runnable launchRunnable(final File executable,
                                           final String downloadUrl,
                                           final File saveDirectory,
                                           final boolean audioOnly,
                                           final boolean metaOnly,
                                           final boolean playlistOnly,
                                           final boolean verboseOutput,
                                           TellurideListener processListener) {
        return () -> {
            ProcessBuilder processBuilder = new ProcessBuilder(executable.getAbsolutePath(), downloadUrl);
            if (audioOnly) {
                processBuilder = new ProcessBuilder(
                        executable.getAbsolutePath(),
                        "-a",
                        downloadUrl);
            }
            if (metaOnly) {
                processBuilder = new ProcessBuilder(
                        executable.getAbsolutePath(),
                        "-m",
                        downloadUrl);
            }
            if (playlistOnly) {
                processBuilder = new ProcessBuilder(
                        executable.getAbsolutePath(),
                        "-p",
                        downloadUrl);
            }
            if (saveDirectory != null && saveDirectory.isDirectory() && saveDirectory.canWrite()) {
                processBuilder.directory(saveDirectory);
            }
            processBuilder.redirectErrorStream(true); // merge stderr into stdout
            try {
                final Process process = processBuilder.start();
                final InputStream stdOut = process.getInputStream();
                final BufferedReader reader = new BufferedReader(new InputStreamReader(stdOut));
                TellurideParser parser = null;
                if (processListener != null) {
                    parser = new TellurideParser(processListener, metaOnly || playlistOnly);
                }
                String line;
                while ((line = reader.readLine()) != null) {
                    if (verboseOutput) {
                        System.out.println("TellurideLauncher::launchRunnable [" + executable.getName() + "] " + line);
                    }
                    if (processListener != null && processListener.aborted()) {
                        process.destroyForcibly();
                        break;
                    }
                    if (parser != null) {
                        parser.parse(line);
                    }
                }
                process.waitFor();
                if (verboseOutput) {
                    System.out.println("TellurideLauncher::launchRunnable Exit-Code: " + process.exitValue());
                }
                if (parser != null) {
                    parser.done();
                }
                if (processListener != null) {
                    processListener.onFinished(process.exitValue());
                }
            } catch (IOException | InterruptedException e) {
                LOG.error("TellurideLauncher::launchRunnable", e);
            }
        };
    }

}
