/*
 * Copyright (c) 2017 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 "AssetsLibrary.h"

#include "TypePrinter.h"
#include "UserConfiguration.h"
#include "Utils.h"

#include "arm_compute/core/ITensor.h"

#include <cctype>
#include <fstream>
#include <limits>
#include <map>
#include <mutex>
#include <sstream>
#include <stdexcept>
#include <tuple>
#include <unordered_map>
#include <utility>

namespace arm_compute
{
namespace test
{
namespace
{
template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
void rgb_to_luminance(const RawTensor &src, RawTensor &dst)
{
    const size_t min_size = std::min(src.size(), dst.size());

    for(size_t i = 0, j = 0; i < min_size; i += 3, ++j)
    {
        reinterpret_cast<T *>(dst.data())[j] = 0.2126f * src.data()[i + 0] + 0.7152f * src.data()[i + 1] + 0.0722f * src.data()[i + 2];
    }
}

void extract_r_from_rgb(const RawTensor &src, RawTensor &dst)
{
    const size_t min_size = std::min(src.size(), dst.size());

    for(size_t i = 0, j = 0; i < min_size; i += 3, ++j)
    {
        dst.data()[j] = src.data()[i];
    }
}

void extract_g_from_rgb(const RawTensor &src, RawTensor &dst)
{
    const size_t min_size = std::min(src.size(), dst.size());

    for(size_t i = 1, j = 0; i < min_size; i += 3, ++j)
    {
        dst.data()[j] = src.data()[i];
    }
}

void discard_comments(std::ifstream &fs)
{
    while(fs.peek() == '#')
    {
        fs.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
}

void discard_comments_and_spaces(std::ifstream &fs)
{
    while(true)
    {
        discard_comments(fs);

        if(isspace(fs.peek()) == 0)
        {
            break;
        }

        fs.ignore(1);
    }
}

std::tuple<unsigned int, unsigned int, int> parse_ppm_header(std::ifstream &fs)
{
    // Check the PPM magic number is valid
    std::array<char, 2> magic_number{ { 0 } };
    fs >> magic_number[0] >> magic_number[1];

    if(magic_number[0] != 'P' || magic_number[1] != '6')
    {
        throw std::runtime_error("Only raw PPM format is suported");
    }

    discard_comments_and_spaces(fs);

    unsigned int width = 0;
    fs >> width;

    discard_comments_and_spaces(fs);

    unsigned int height = 0;
    fs >> height;

    discard_comments_and_spaces(fs);

    int max_value = 0;
    fs >> max_value;

    if(!fs.good())
    {
        throw std::runtime_error("Cannot read image dimensions");
    }

    if(max_value != 255)
    {
        throw std::runtime_error("RawTensor doesn't have 8-bit values");
    }

    discard_comments(fs);

    if(isspace(fs.peek()) == 0)
    {
        throw std::runtime_error("Invalid PPM header");
    }

    fs.ignore(1);

    return std::make_tuple(width, height, max_value);
}

RawTensor load_ppm(const std::string &path)
{
    std::ifstream file(path, std::ios::in | std::ios::binary);

    if(!file.good())
    {
        throw std::runtime_error("Could not load PPM image: " + path);
    }

    unsigned int width  = 0;
    unsigned int height = 0;

    std::tie(width, height, std::ignore) = parse_ppm_header(file);

    RawTensor raw(TensorShape(width, height), Format::RGB888);

    // Check if the file is large enough to fill the image
    const size_t current_position = file.tellg();
    file.seekg(0, std::ios_base::end);
    const size_t end_position = file.tellg();
    file.seekg(current_position, std::ios_base::beg);

    if((end_position - current_position) < raw.size())
    {
        throw std::runtime_error("Not enough data in file");
    }

    file.read(reinterpret_cast<std::fstream::char_type *>(raw.data()), raw.size());

    if(!file.good())
    {
        throw std::runtime_error("Failure while reading image buffer");
    }

    return raw;
}
} // namespace

AssetsLibrary::AssetsLibrary(std::string path, std::random_device::result_type seed) //NOLINT
    : _library_path(std::move(path)),
      _seed{ seed }
{
}

std::random_device::result_type AssetsLibrary::seed() const
{
    return _seed;
}

void AssetsLibrary::fill(RawTensor &raw, const std::string &name, Format format) const
{
    //FIXME: Should be done by swapping cached buffers
    const RawTensor &src = get(name, format);
    std::copy_n(src.data(), raw.size(), raw.data());
}

void AssetsLibrary::fill(RawTensor &raw, const std::string &name, Channel channel) const
{
    fill(raw, name, get_format_for_channel(channel), channel);
}

void AssetsLibrary::fill(RawTensor &raw, const std::string &name, Format format, Channel channel) const
{
    const RawTensor &src = get(name, format, channel);
    std::copy_n(src.data(), raw.size(), raw.data());
}

const AssetsLibrary::Loader &AssetsLibrary::get_loader(const std::string &extension) const
{
    static std::unordered_map<std::string, Loader> loaders =
    {
        { "ppm", load_ppm }
    };

    const auto it = loaders.find(extension);

    if(it != loaders.end())
    {
        return it->second;
    }
    else
    {
        throw std::invalid_argument("Cannot load image with extension '" + extension + "'");
    }
}

const AssetsLibrary::Converter &AssetsLibrary::get_converter(Format src, Format dst) const
{
    static std::map<std::pair<Format, Format>, Converter> converters =
    {
        { std::make_pair(Format::RGB888, Format::U8), rgb_to_luminance<uint8_t> },
        { std::make_pair(Format::RGB888, Format::U16), rgb_to_luminance<uint16_t> },
        { std::make_pair(Format::RGB888, Format::S16), rgb_to_luminance<int16_t> },
        { std::make_pair(Format::RGB888, Format::U32), rgb_to_luminance<uint32_t> }
    };

    const auto it = converters.find(std::make_pair(src, dst));

    if(it != converters.end())
    {
        return it->second;
    }
    else
    {
        std::stringstream msg;
        msg << "Cannot convert from format '" << src << "' to format '" << dst << "'\n";
        throw std::invalid_argument(msg.str());
    }
}

const AssetsLibrary::Converter &AssetsLibrary::get_converter(DataType src, Format dst) const
{
    static std::map<std::pair<DataType, Format>, Converter> converters = {};

    const auto it = converters.find(std::make_pair(src, dst));

    if(it != converters.end())
    {
        return it->second;
    }
    else
    {
        std::stringstream msg;
        msg << "Cannot convert from data type '" << src << "' to format '" << dst << "'\n";
        throw std::invalid_argument(msg.str());
    }
}

const AssetsLibrary::Converter &AssetsLibrary::get_converter(DataType src, DataType dst) const
{
    static std::map<std::pair<DataType, DataType>, Converter> converters = {};

    const auto it = converters.find(std::make_pair(src, dst));

    if(it != converters.end())
    {
        return it->second;
    }
    else
    {
        std::stringstream msg;
        msg << "Cannot convert from data type '" << src << "' to data type '" << dst << "'\n";
        throw std::invalid_argument(msg.str());
    }
}

const AssetsLibrary::Converter &AssetsLibrary::get_converter(Format src, DataType dst) const
{
    static std::map<std::pair<Format, DataType>, Converter> converters = {};

    const auto it = converters.find(std::make_pair(src, dst));

    if(it != converters.end())
    {
        return it->second;
    }
    else
    {
        std::stringstream msg;
        msg << "Cannot convert from format '" << src << "' to data type '" << dst << "'\n";
        throw std::invalid_argument(msg.str());
    }
}

const AssetsLibrary::Extractor &AssetsLibrary::get_extractor(Format format, Channel channel) const
{
    static std::map<std::pair<Format, Channel>, Extractor> extractors =
    {
        { std::make_pair(Format::RGB888, Channel::R), extract_r_from_rgb },
        { std::make_pair(Format::RGB888, Channel::G), extract_g_from_rgb }
    };

    const auto it = extractors.find(std::make_pair(format, channel));

    if(it != extractors.end())
    {
        return it->second;
    }
    else
    {
        std::stringstream msg;
        msg << "Cannot extract channel '" << channel << "' from format '" << format << "'\n";
        throw std::invalid_argument(msg.str());
    }
}

RawTensor AssetsLibrary::load_image(const std::string &name) const
{
#ifdef _WIN32
    const std::string image_path = ("\\images\\");
#else  /* _WIN32 */
    const std::string image_path = ("/images/");
#endif /* _WIN32 */

    const std::string path      = _library_path + image_path + name;
    const std::string extension = path.substr(path.find_last_of('.') + 1);
    return (*get_loader(extension))(path);
}

const RawTensor &AssetsLibrary::find_or_create_raw_tensor(const std::string &name, Format format) const
{
    std::lock_guard<std::mutex> guard(_format_lock);

    const RawTensor *ptr = _cache.find(std::make_tuple(name, format));

    if(ptr != nullptr)
    {
        return *ptr;
    }

    RawTensor raw = load_image(name);

    if(raw.format() != format)
    {
        //FIXME: Remove unnecessary copy
        RawTensor dst(raw.shape(), format);
        (*get_converter(raw.format(), format))(raw, dst);
        raw = std::move(dst);
    }

    return _cache.add(std::make_tuple(name, format), std::move(raw));
}

const RawTensor &AssetsLibrary::find_or_create_raw_tensor(const std::string &name, Format format, Channel channel) const
{
    std::lock_guard<std::mutex> guard(_channel_lock);

    const RawTensor *ptr = _cache.find(std::make_tuple(name, format, channel));

    if(ptr != nullptr)
    {
        return *ptr;
    }

    const RawTensor &src = get(name, format);
    //FIXME: Need to change shape to match channel
    RawTensor dst(src.shape(), get_channel_format(channel));

    (*get_extractor(format, channel))(src, dst);

    return _cache.add(std::make_tuple(name, format, channel), std::move(dst));
}

TensorShape AssetsLibrary::get_image_shape(const std::string &name)
{
    return load_image(name).shape();
}

const RawTensor &AssetsLibrary::get(const std::string &name) const
{
    //FIXME: Format should be derived from the image name. Not be fixed to RGB.
    return find_or_create_raw_tensor(name, Format::RGB888);
}

RawTensor AssetsLibrary::get(const std::string &name)
{
    //FIXME: Format should be derived from the image name. Not be fixed to RGB.
    return RawTensor(find_or_create_raw_tensor(name, Format::RGB888));
}

RawTensor AssetsLibrary::get(const std::string &name, DataType data_type, int num_channels) const
{
    const RawTensor &raw = get(name);

    return RawTensor(raw.shape(), data_type, num_channels);
}

const RawTensor &AssetsLibrary::get(const std::string &name, Format format) const
{
    return find_or_create_raw_tensor(name, format);
}

RawTensor AssetsLibrary::get(const std::string &name, Format format)
{
    return RawTensor(find_or_create_raw_tensor(name, format));
}

const RawTensor &AssetsLibrary::get(const std::string &name, Channel channel) const
{
    return get(name, get_format_for_channel(channel), channel);
}

RawTensor AssetsLibrary::get(const std::string &name, Channel channel)
{
    return RawTensor(get(name, get_format_for_channel(channel), channel));
}

const RawTensor &AssetsLibrary::get(const std::string &name, Format format, Channel channel) const
{
    return find_or_create_raw_tensor(name, format, channel);
}

RawTensor AssetsLibrary::get(const std::string &name, Format format, Channel channel)
{
    return RawTensor(find_or_create_raw_tensor(name, format, channel));
}
} // namespace test
} // namespace arm_compute
