/* -*-c++-*- */
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
 * Copyright 2008-2010 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 OSGEARTHSYMBOLOGY_GEOMETRY_SYMBOL_H
#define OSGEARTHSYMBOLOGY_GEOMETRY_SYMBOL_H 1

#include <osgEarth/Common>
#include <osgEarthSymbology/Common>
#include <osgEarthSymbology/Symbol>
#include <osg/Referenced>
#include <vector>

namespace osgEarth { namespace Symbology
{
    class OSGEARTHSYMBOLOGY_EXPORT Stroke
    {
    public:
        enum LineCapStyle {
            LINECAP_DEFAULT,
            LINECAP_BUTT,
            LINECAP_SQUARE,
            LINECAP_ROUND
        };

        enum LineJoinStyle {
            LINEJOIN_DEFAULT
        };

    public:
        Stroke();
        Stroke( float r, float g, float b, float a );
        Stroke( const Config& conf ) { mergeConfig(conf); }

        osg::Vec4f& color() { return _color; }
        const osg::Vec4f& color() const { return _color; }

        optional<LineCapStyle>& lineCap() { return _lineCap; }
        const optional<LineCapStyle>& lineCap() const { return _lineCap; }

        optional<LineJoinStyle>& lineJoin() { return _lineJoin; }
        const optional<LineJoinStyle>& lineJoin() const { return _lineJoin; }

        optional<float>& width() { return _width; }        
        const optional<float>& width() const { return _width; }

    public:
        virtual Config getConfig() const {
            Config conf("stroke");
            conf.add( "color", vec4fToHtmlColor(_color) );
            conf.addIfSet("linecap", "butt", _lineCap, LINECAP_BUTT);
            conf.addIfSet("linecap", "square", _lineCap, LINECAP_SQUARE);
            conf.addIfSet("linecap", "round", _lineCap, LINECAP_ROUND);
            conf.addIfSet("width", _width);
            return conf;
        }
            
        virtual void mergeConfig( const Config& conf ) {
            _color = htmlColorToVec4f( conf.value("color") );
            conf.getIfSet("linecap", "butt", _lineCap, LINECAP_BUTT);
            conf.getIfSet("linecap", "square", _lineCap, LINECAP_SQUARE);
            conf.getIfSet("linecap", "round", _lineCap, LINECAP_ROUND);
            conf.getIfSet("width", _width);
        }

    protected:
        osg::Vec4f              _color;
        optional<LineCapStyle>  _lineCap;
        optional<LineJoinStyle> _lineJoin;
        optional<float>         _width;
    };

    class OSGEARTHSYMBOLOGY_EXPORT Fill
    {
    public:
        Fill();
        Fill( float r, float g, float b, float a );
        Fill( const Config& conf ) { mergeConfig(conf); }

        osg::Vec4f& color() { return _color; }
        const osg::Vec4f& color() const { return _color; }

    public:
        virtual Config getConfig() const {
            Config conf("fill");
            conf.add("color", vec4fToHtmlColor(_color));
            return conf;
        }
        virtual void mergeConfig( const Config& conf ) {
            _color = htmlColorToVec4f(conf.value("color"));
        }

    protected:
        osg::Vec4f _color;
    };

    class OSGEARTHSYMBOLOGY_EXPORT LineSymbol : public Symbol
    {
    public:
        LineSymbol();
        LineSymbol(const Config& conf) { mergeConfig(conf); }

        optional<Stroke>& stroke() { return _stroke; }
        const optional<Stroke>& stroke() const { return _stroke; }

    public:
        virtual Config getConfig() const {
            Config conf( "line" );
            conf.addObjIfSet("stroke", _stroke);
            return conf;
        }
        virtual void mergeConfig( const Config& conf ) {
            conf.getObjIfSet("stroke", _stroke);
        }

    protected:
        optional<Stroke> _stroke;
    };

    class OSGEARTHSYMBOLOGY_EXPORT PointSymbol : public Symbol
    {
    public:
        PointSymbol();
        PointSymbol( const Config& conf ) { mergeConfig(conf); }

        optional<Fill>& fill() { return _fill; }
        const optional<Fill>& fill() const { return _fill; }

        optional<float>& size() { return _size; }
        const optional<float>& size() const { return _size; }

    public:
        virtual Config getConfig() const {
            Config conf( "point" );
            conf.addObjIfSet( "fill", _fill );
            conf.addIfSet( "size", _size );
            return conf;
        }
        virtual void mergeConfig( const Config& conf ) {
            conf.getObjIfSet( "fill", _fill );
            conf.getIfSet( "size", _size );
        }

    protected:
        optional<Fill> _fill;
        optional<float>  _size;
    };

    class OSGEARTHSYMBOLOGY_EXPORT PolygonSymbol : public Symbol
    {
    public:
        PolygonSymbol();
        PolygonSymbol( const Config& conf ) { mergeConfig(conf); }

        optional<Fill>& fill() { return _fill; }
        const optional<Fill>& fill() const { return _fill; }

    public:
        virtual Config getConfig() const {
            Config conf( "polygon" );
            conf.addObjIfSet( "fill", _fill );
            return conf;
        }
        virtual void mergeConfig(const Config& conf ) {
            conf.getObjIfSet( "fill", _fill );
        }

    protected:
        optional<Fill> _fill;
    };


} } // namespace osgEarth::Symbology

#endif // OSGEARTH_SYMBOLOGY_SYMBOL_H
