// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <assert.h>
#include <lib/fdio/io.h>
#include <lib/fdio/spawn.h>
#include <lib/fdio/util.h>
#include <memory.h>
#include <memory>
#include <string>
#include <unistd.h>
#include <vector>
#include <zircon/process.h>
#include <zircon/processargs.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/object.h>

#include "deProcess.h"

#if (DE_OS != DE_OS_FUCHSIA)
#error DE_OS_FUCHSIA expected
#endif

#include "deCommandLine.h"

struct deProcess_s {
};

class ModifiedEnviron {
public:
    explicit ModifiedEnviron(char** env)
    {
        for (size_t i = 0; env[i]; i++) {
            envs_.push_back(env[i]);
        }
    }

    void ReplacePwd(const char* working_directory)
    {
        assert(working_directory);
        char pwd_string[strlen(working_directory) + 4 + 1];

        sprintf(pwd_string, "PWD=%s", working_directory);
        for (size_t i = 0; i < envs_.size(); i++) {
            if (strstr(envs_[i].c_str(), "PWD=") == 0) {
                envs_[i] = pwd_string;
                return;
            }
        }
        envs_.push_back(pwd_string);
    }

    // Return value must not outlive ModifiedEnviron. Invalidated if ReplacePwd
    // is called.
    std::vector<const char*> GetEnviron()
    {
        std::vector<const char*> env;
        for (size_t i = 0; i < envs_.size(); i++) {
            env.push_back(envs_[i].c_str());
        }
        env.push_back(nullptr);
        return env;
    }

private:
    std::vector<std::string> envs_;
};

class DeProcess : public deProcess_s {
public:
    static std::unique_ptr<DeProcess> Create()
    {
        return std::unique_ptr<DeProcess>(new DeProcess());
    }

    DeProcess() : proc_(ZX_HANDLE_INVALID), fstdin_(nullptr), fstdout_(nullptr), fstderr_(nullptr)
    {
    }

    ~DeProcess()
    {
        if (proc_ != ZX_HANDLE_INVALID)
            zx_handle_close(proc_);
        closeStdIn();
        closeStdOut();
        closeStdErr();
    }

    bool start(const char* commandLine, const char* workingDirectory)
    {
        deCommandLine* cmdLine = deCommandLine_parse(commandLine);
        assert(cmdLine->args[cmdLine->numArgs] == 0);
        fdio_spawn_action_t spawn_actions[3];
        int result;
        int stdin_pipes[2];
        result = pipe(stdin_pipes);
        assert(result == 0);
        int stdout_pipes[2];
        result = pipe(stdout_pipes);
        assert(result == 0);
        int stderr_pipes[2];
        result = pipe(stderr_pipes);
        assert(result == 0);

        spawn_actions[0].action = FDIO_SPAWN_ACTION_TRANSFER_FD;
        spawn_actions[0].fd.local_fd = stdin_pipes[0];
        spawn_actions[0].fd.target_fd = STDIN_FILENO;
        fstdin_ = deFile_createFromHandle(stdin_pipes[1]);

        spawn_actions[1].action = FDIO_SPAWN_ACTION_TRANSFER_FD;
        spawn_actions[1].fd.local_fd = stdout_pipes[1];
        spawn_actions[1].fd.target_fd = STDOUT_FILENO;
        fstdout_ = deFile_createFromHandle(stdout_pipes[0]);

#ifndef RAW_STDERR
        spawn_actions[2].action = FDIO_SPAWN_ACTION_TRANSFER_FD;
        spawn_actions[2].fd.local_fd = stderr_pipes[1];
        spawn_actions[2].fd.target_fd = STDERR_FILENO;
        fstderr_ = deFile_createFromHandle(stderr_pipes[0]);
#else
        // Printing to our stderr sometimes works better.
        spawn_actions[2].action = FDIO_SPAWN_ACTION_CLONE_FD;
        spawn_actions[2].fd.local_fd = STDERR_FILENO;
        spawn_actions[2].fd.target_fd = STDERR_FILENO;
        fstderr_ = deFile_createFromHandle(stderr_pipes[0]);
#endif

        ModifiedEnviron env(environ);
        if (workingDirectory)
            env.ReplacePwd(workingDirectory);

        char err_msg_out[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];

        uint32_t spawn_flags = FDIO_SPAWN_CLONE_NAMESPACE | FDIO_SPAWN_CLONE_ENVIRON |
                               FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_JOB;
        zx_status_t status = fdio_spawn_etc(
            ZX_HANDLE_INVALID, spawn_flags, cmdLine->args[0], (const char* const*)&cmdLine->args[0],
            env.GetEnviron().data(), 3, spawn_actions, &proc_, err_msg_out);

        if (status != ZX_OK) {
            fprintf(stderr, "fdio_spawn error: %d %s\n", status, err_msg_out);
            return false;
        }

        return true;
    }

    bool IsRunning()
    {
        zx_signals_t pending = 0;
        zx_status_t status = zx_object_wait_one(proc_, ZX_TASK_TERMINATED, 0, &pending);
        if (pending & ZX_TASK_TERMINATED)
            return false;
        assert(status == ZX_ERR_TIMED_OUT);
        return true;
    }

    bool Wait()
    {
        zx_status_t status = zx_object_wait_one(proc_, ZX_TASK_TERMINATED, ZX_TIME_INFINITE, NULL);
        return status == ZX_OK;
    }

    int GetExitCode()
    {
        zx_info_process_t info;
        zx_status_t status =
            zx_object_get_info(proc_, ZX_INFO_PROCESS, &info, sizeof(info), NULL, NULL);
        assert(status == ZX_OK);
        return info.return_code;
    }

    static DeProcess* cast(deProcess* process) { return static_cast<DeProcess*>(process); }

    deFile* fstdin() { return fstdin_; }
    deFile* fstdout() { return fstdout_; }
    deFile* fstderr() { return fstderr_; }

    void closeStdIn()
    {
        if (fstdin_) {
            deFile_destroy(fstdin_);
            fstdin_ = nullptr;
        }
    }

    void closeStdOut()
    {
        if (fstdout_) {
            deFile_destroy(fstdout_);
            fstdout_ = nullptr;
        }
    }

    void closeStdErr()
    {
        if (fstderr_) {
            deFile_destroy(fstderr_);
            fstderr_ = nullptr;
        }
    }

private:
    zx_handle_t proc_;
    deFile* fstdin_;
    deFile* fstdout_;
    deFile* fstderr_;
};

deProcess* deProcess_create()
{
    std::unique_ptr<DeProcess> process = DeProcess::Create();
    if (!process)
        return nullptr;

    return process.release();
}

void deProcess_destroy(deProcess* process) { delete DeProcess::cast(process); }

deBool deProcess_start(deProcess* de_process, const char* commandLine, const char* workingDirectory)
{
    (void)workingDirectory;

    DeProcess* process = DeProcess::cast(de_process);

    if (!process->start(commandLine, workingDirectory))
        return false;

    return true;
}

deBool deProcess_isRunning(deProcess* process) { return DeProcess::cast(process)->IsRunning(); }

deBool deProcess_waitForFinish(deProcess* process)
{
    return DeProcess::cast(process)->Wait() ? DE_TRUE : DE_FALSE;
}

const char* deProcess_getLastError(const deProcess*) { return nullptr; }

int deProcess_getExitCode(const deProcess* process)
{
    return DeProcess::cast((deProcess*)process)->GetExitCode();
}

deBool deProcess_terminate(deProcess*)
{
    printf("%s:%d Not implemented\n", __FILE__, __LINE__);
    return DE_FALSE;
}

deBool deProcess_kill(deProcess*)
{
    printf("%s:%d Not implemented\n", __FILE__, __LINE__);
    return DE_FALSE;
}

deFile* deProcess_getStdIn(deProcess* process) { return DeProcess::cast(process)->fstdin(); }

deFile* deProcess_getStdOut(deProcess* process) { return DeProcess::cast(process)->fstdout(); }

deFile* deProcess_getStdErr(deProcess* process) { return DeProcess::cast(process)->fstderr(); }

deBool deProcess_closeStdIn(deProcess* process)
{
    DeProcess::cast(process)->closeStdIn();
    return DE_TRUE;
}

deBool deProcess_closeStdOut(deProcess* process)
{
    DeProcess::cast(process)->closeStdOut();
    return DE_TRUE;
}

deBool deProcess_closeStdErr(deProcess* process)
{
    DeProcess::cast(process)->closeStdErr();
    return DE_TRUE;
}
