#pragma once

/*
 * Copyright (c) Contributors to the Open 3D Engine Project.
 * For complete copyright and license terms please see the LICENSE at the root of this distribution.
 *
 * SPDX-License-Identifier: Apache-2.0 OR MIT
 *
 */

#include <AzCore/RTTI/RTTI.h>
#include <SceneAPI/SceneCore/DataTypes/IGraphObject.h>
#include <AzCore/Name/Name.h>

namespace AZ
{
    namespace SceneAPI
    {
        namespace DataTypes
        {
            enum class ColorChannel : AZ::u8
            {
                Red = 0,
                Green,
                Blue,
                Alpha
            };

            struct Color
            {
                union
                {
                    struct
                    {
                        float red;
                        float green;
                        float blue;
                        float alpha;
                    };
                    float m_channels[4];
                };

                Color() = default;
                Color(float r, float g, float b, float a)
                    : red(r), green(g), blue(b), alpha(a)
                {
                }

                float GetChannel(ColorChannel channel) const
                {
                    return m_channels[static_cast<AZ::u8>(channel)];
                }

                bool IsClose(const Color& c, float tolerance = AZ::Constants::Tolerance) const
                {
                    return (c - (*this)).Abs().IsLessEqualThan(tolerance);
                }

                bool IsLessEqualThan(float tolerance) const
                {
                    return AZStd::all_of(AZStd::begin(m_channels), AZStd::end(m_channels), [tolerance] (float channel) { return channel <= tolerance; } );
                }

                Color& Abs()
                {
                    for (float& channel : m_channels)
                    {
                        channel = std::abs(channel);
                    }
                    return *this;
                }

                Color operator-(const Color& rhs) const
                {
                    return Color(red - rhs.red, green - rhs.green, blue - rhs.blue, alpha - rhs.alpha);
                }
            };

            class IMeshVertexColorData
                : public IGraphObject
            {
            public:
                AZ_RTTI(IMeshVertexColorData, "{27659F76-1245-4549-87A6-AF4E8B94CD51}", IGraphObject);

                virtual ~IMeshVertexColorData() override = default;

                void CloneAttributesFrom([[maybe_unused]] const IGraphObject* sourceObject) override {}

                virtual const AZ::Name& GetCustomName() const = 0;

                virtual size_t GetCount() const = 0;
                virtual const Color& GetColor(size_t index) const = 0;
            };
        }  // DataTypes
    }  // SceneAPI

    AZ_TYPE_INFO_SPECIALIZE(SceneAPI::DataTypes::Color, "{937E3BF8-5204-4D40-A8DA-C8F083C89F9F}");

}  // AZ

namespace AZStd
{
    template<>
    struct hash<AZ::SceneAPI::DataTypes::Color>
    {
        using result_type = AZStd::size_t;

        result_type operator()(const AZ::SceneAPI::DataTypes::Color& value) const
        {
            result_type hash = 0;

            hash_combine(hash, value.red);
            hash_combine(hash, value.green);
            hash_combine(hash, value.blue);
            hash_combine(hash, value.alpha);

            return hash;
        }
    };
}
