/*
 * Copyright (c) 2018 ARM Limited.
 *
 * SPDX-License-Identifier: MIT
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#include "CommonOptions.h"

#include "../Framework.h"
#include "../printers/Printers.h"
#include <unistd.h>

using namespace arm_compute::utils;

namespace arm_compute
{
namespace test
{
namespace framework
{
CommonOptions::CommonOptions(CommandLineParser &parser)
    : help(parser.add_option<ToggleOption>("help")),
      instruments(),
      iterations(parser.add_option<SimpleOption<int>>("iterations", 1)),
      log_format(),
      log_file(parser.add_option<SimpleOption<std::string>>("log-file")),
      log_level(),
      throw_errors(parser.add_option<ToggleOption>("throw-errors")),
      color_output(parser.add_option<ToggleOption>("color-output", isatty(STDOUT_FILENO))), // Only enable colors by default if we're running in a terminal
      pretty_console(parser.add_option<ToggleOption>("pretty-console", false)),
      json_file(parser.add_option<SimpleOption<std::string>>("json-file")),
      pretty_file(parser.add_option<SimpleOption<std::string>>("pretty-file")),
      log_streams()
{
    Framework                       &framework = Framework::get();
    std::set<InstrumentsDescription> allowed_instruments
    {
        std::pair<InstrumentType, ScaleFactor>(InstrumentType::ALL, ScaleFactor::NONE),
        std::pair<InstrumentType, ScaleFactor>(InstrumentType::NONE, ScaleFactor::NONE),
    };

    for(const auto &type : framework.available_instruments())
    {
        allowed_instruments.insert(type);
    }

    std::set<LogFormat> supported_log_formats
    {
        LogFormat::NONE,
        LogFormat::PRETTY,
        LogFormat::JSON,
    };

    std::set<LogLevel> supported_log_levels
    {
        LogLevel::NONE,
        LogLevel::CONFIG,
        LogLevel::TESTS,
        LogLevel::ERRORS,
        LogLevel::DEBUG,
        LogLevel::MEASUREMENTS,
        LogLevel::ALL,
    };

    instruments = parser.add_option<EnumListOption<InstrumentsDescription>>("instruments", allowed_instruments, std::initializer_list<InstrumentsDescription> { std::pair<InstrumentType, ScaleFactor>(InstrumentType::WALL_CLOCK_TIMER, ScaleFactor::NONE) });
    log_format  = parser.add_option<EnumOption<LogFormat>>("log-format", supported_log_formats, LogFormat::PRETTY);
    log_level   = parser.add_option<EnumOption<LogLevel>>("log-level", supported_log_levels, LogLevel::ALL);

    help->set_help("Show this help message");
    instruments->set_help("Set the profiling instruments to use");
    iterations->set_help("Number of iterations per test case");
    log_format->set_help("Output format for measurements and failures (affects only log-file)");
    log_file->set_help("Write output to file instead of to the console (affected by log-format)");
    log_level->set_help("Verbosity of the output");
    throw_errors->set_help("Don't catch fatal errors (useful for debugging)");
    color_output->set_help("Produce colored output on the console");
    pretty_console->set_help("Produce pretty output on the console");
    json_file->set_help("Write output to a json file.");
    pretty_file->set_help("Write output to a text file");
}
std::vector<std::unique_ptr<Printer>> CommonOptions::create_printers()
{
    std::vector<std::unique_ptr<Printer>> printers;

    if(pretty_console->value() && (log_file->is_set() || log_format->value() != LogFormat::PRETTY))
    {
        auto pretty_printer = support::cpp14::make_unique<PrettyPrinter>();
        pretty_printer->set_color_output(color_output->value());
        printers.push_back(std::move(pretty_printer));
    }

    std::unique_ptr<Printer> printer;
    switch(log_format->value())
    {
        case LogFormat::JSON:
            printer = support::cpp14::make_unique<JSONPrinter>();
            break;
        case LogFormat::NONE:
            break;
        case LogFormat::PRETTY:
        default:
            auto pretty_printer = support::cpp14::make_unique<PrettyPrinter>();
            // Don't use colours if we print to a file:
            pretty_printer->set_color_output((!log_file->is_set()) && color_output->value());
            printer = std::move(pretty_printer);
            break;
    }

    if(log_file->is_set())
    {
        log_streams.push_back(std::make_shared<std::ofstream>(log_file->value()));
        if(printer != nullptr)
        {
            printer->set_stream(*log_streams.back().get());
        }
    }

    if(printer != nullptr)
    {
        printers.push_back(std::move(printer));
    }

    if(json_file->is_set())
    {
        printers.push_back(support::cpp14::make_unique<JSONPrinter>());
        log_streams.push_back(std::make_shared<std::ofstream>(json_file->value()));
        printers.back()->set_stream(*log_streams.back().get());
    }

    if(pretty_file->is_set())
    {
        printers.push_back(support::cpp14::make_unique<PrettyPrinter>());
        log_streams.push_back(std::make_shared<std::ofstream>(pretty_file->value()));
        printers.back()->set_stream(*log_streams.back().get());
    }

    return printers;
}
} // namespace framework
} // namespace test
} // namespace arm_compute
