/* --*-c++-*-- */
/* osgEarth - Geospatial SDK for OpenSceneGraph
 * Copyright 2020 Pelican Mapping
 * http://osgearth.org
 *
 * osgEarth is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */
#ifndef OSGEARTH_COLOR_H
#define OSGEARTH_COLOR_H 1

#include <osgEarth/Common>
#include <osgEarth/Config>
#include <osg/Vec3f>
#include <osg/Vec4f>
#include <string>
#include <vector>

namespace osgEarth
{
    /**
     * Pre-set colors (convenience class).
     */
    struct OSGEARTH_EXPORT Color : public osg::Vec4f
    {
        enum Format {
            RGBA,
            ABGR
        };

        /** Creates a new default color */
        Color() : osg::Vec4f(1,1,1,1) { }

        /** Copy constructor */
        Color( const Color& rhs ) : osg::Vec4f(rhs) { }

        /** Make from vec4 */
        Color( const osg::Vec4f& rgba ) : osg::Vec4f(rgba) { }

        /** Make from vec3 */
        Color( const osg::Vec3f& rgb ) : osg::Vec4f(rgb[0], rgb[1], rgb[2], 1.0f) { }

        /** Copy constructor with modified alpha value */
        Color( const Color& rhs, float a );

        /** Component constructor */
        Color( float r, float g, float b, float a = 1.0f )
            : osg::Vec4f(r, g, b, a) { }

        /** Vector constructor */
        explicit Color(float v) : osg::Vec4f(v, v, v, v) { }

        /** RGBA/ABGR constructor */
        explicit Color( unsigned value, Format format =RGBA );

        /**
         * Construct a color from a hex string in one of the following formats, (with or
         * without the component order reversed):
         *   RRGGBB or RRGGBBAA
         *   #RRGGBB or #RRGGBBAA (HTML style - preceding hash)
         *   0xRRGGBB or 0xRRGGBBAA (C style - preceding "0x")
         */
        Color( const std::string& html, Format format =RGBA );

        virtual ~Color() { }

        /** Encode the color at an HTML color string (e.g., "#FF004F78") */
        std::string toHTML( Format format =RGBA ) const;

        /** Dump out the color as a 32-bit integer */
        unsigned as( Format format ) const;

        /** Lighten/darken the color by factor */
        Color brightness( float factor ) const;

        //! gets the color as HSL (and alpha)
        osg::Vec4f asHSL() const;

        //! populates the RGB from HSL
        void fromHSL(const osg::Vec4f& hsla);

        //! as normalized ubyte4
        osg::Vec4ub asNormalizedRGBA() const;

        // built in colors
        // http://en.wikipedia.org/wiki/Web_colors#HTML_color_names

        static Color White;
        static Color Silver;
        static Color Gray;
        static Color Black;
        static Color Red;
        static Color Maroon;
        static Color Yellow;
        static Color Olive;
        static Color Lime;
        static Color Green;
        static Color Aqua;
        static Color Teal;
        static Color Blue;
        static Color Navy;
        static Color Fuchsia;
        static Color Purple;
        static Color Orange;

        // others:
        static Color Cyan;
        static Color DarkGray;
        static Color Magenta;
        static Color Brown;
        static Color Transparent;

        //! generate a random color ramp
        static void createRandomColorRamp(
            unsigned count,
            std::vector<Color>& output,
            int seed = -1);
    };

} // namespace osgEarth


//------------------------------------------------------------------------

namespace osgEarth
{
    // Config specializations for Color:
    template<> inline
    void Config::set<Color>( const std::string& key, const optional<Color>& opt ) {
        if ( opt.isSet() ) {
            remove( key );
            set( key, opt->toHTML() );
        }
    }

    template<> inline
    void Config::set<Color>(const std::string& key, const Color& opt) {
        remove(key);
        set(key, opt.toHTML());
    }

    template<> inline
    bool Config::get<Color>( const std::string& key, optional<Color>& output ) const {
        if ( hasValue( key ) ) {
            output = Color( value(key) );
            return true;
        }
        else
            return false;
    }

    template<> inline
    bool Config::get<Color>(const std::string& key, Color& output) const {
        if (hasValue(key)) {
            output = Color(value(key));
            return true;
        }
        else
            return false;
    }
}


#endif // OSGEARTH_COLOR_H
