/* -*-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_TEXT_SYMBOL_H
#define OSGEARTHSYMBOLOGY_TEXT_SYMBOL_H 1

#include <osgEarth/Common>
#include <osgEarthSymbology/Common>
#include <osgEarthSymbology/Symbolizer>
#include <osgEarthSymbology/GeometrySymbol>
#include <osg/Referenced>
#include <vector>

namespace osgEarth { namespace Symbology
{
    class OSGEARTHSYMBOLOGY_EXPORT TextSymbol : public Symbol
    {
    public:
        enum SizeMode {
            SIZEMODE_SCREEN,
            SIZEMODE_OBJECT
        };

        enum LineOrientation {
            LINEORIENTATION_PARALLEL,
            LINEORIENTATION_PERPENDICULAR,
            LINEORIENTATION_HORIZONTAL
        };

        enum LinePlacement {
            LINEPLACEMENT_ALONG_LINE,
            LINEPLACEMENT_CENTROID
        };

        TextSymbol();
        TextSymbol( const Config& conf ) { mergeConfig(conf); }

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

        optional<Stroke>& halo() { return _halo; }
        const optional<Stroke>& halo() const { return _halo; }

        optional<std::string>& font() { return _font; }
        const optional<std::string>& font() const { return _font; }

        optional<std::string>& content() { return _content; }
        const optional<std::string>& content() const { return _content; }

        optional<std::string>& contentAttributeDelimiter() { return _contentAttributeDelimiter; }
        const optional<std::string>& contentAttributeDelimiter() const { return _contentAttributeDelimiter; }

        optional<std::string>& attribute() { return _attribute; }
        const optional<std::string>& attribute() const { return _attribute; }

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

        optional<bool>& rotateToScreen() { return _rotateToScreen; }
        const optional<bool>& rotateToScreen() const { return _rotateToScreen; }

        optional<osg::Vec2s>& pixelOffset() { return _pixelOffset; }
        const optional<osg::Vec2s>& pixelOffset() const { return _pixelOffset; }

        optional<bool>& removeDuplicateLabels() { return _removeDuplicateLabels; }
        const optional<bool>& removeDuplicateLabels() const { return _removeDuplicateLabels; }

        optional<SizeMode>& sizeMode() { return _sizeMode; }
        const optional<SizeMode>& sizeMode() const { return _sizeMode; }

        optional<LineOrientation>& lineOrientation() { return _lineOrientation; }
        const optional<LineOrientation>& lineOrientation() const { return _lineOrientation; }

        optional<LinePlacement>& linePlacement() { return _linePlacement; }
        const optional<LinePlacement>& linePlacement() const { return _linePlacement; }

    public:
        virtual Config getConfig() const {
            Config conf("text");
            conf.addObjIfSet( "fill", _fill );
            conf.addObjIfSet( "halo", _halo );
            conf.addIfSet( "font", _font );
            conf.addIfSet( "size", _size );
            conf.addIfSet( "content", _content );
            conf.addIfSet( "content_attribute_delim", _contentAttributeDelimiter );
            conf.addIfSet( "attribute", _attribute );
            conf.addIfSet( "rotate_to_screen", _rotateToScreen );
            conf.addIfSet( "remove_duplicate_labels", _removeDuplicateLabels );
            conf.addIfSet( "size_mode", "screen", _sizeMode, SIZEMODE_SCREEN );
            conf.addIfSet( "size_mode", "object", _sizeMode, SIZEMODE_OBJECT );
            conf.addIfSet( "line_orientation", "parallel", _lineOrientation, LINEORIENTATION_PARALLEL );
            conf.addIfSet( "line_orientation", "perpendicular", _lineOrientation, LINEORIENTATION_PERPENDICULAR );
            conf.addIfSet( "line_orientation", "horizontal", _lineOrientation, LINEORIENTATION_HORIZONTAL );
            conf.addIfSet( "line_placement", "along_line", _linePlacement, LINEPLACEMENT_ALONG_LINE );
            conf.addIfSet( "line_placement", "centroid", _linePlacement, LINEPLACEMENT_CENTROID );
            conf.addIfSet( "theme", _theme );
            if ( _pixelOffset.isSet() ) {
                conf.add( "pixel_offset_x", toString(_pixelOffset->x()) );
                conf.add( "pixel_offset_y", toString(_pixelOffset->y()) );
            }
            return conf;
        }
        virtual void mergeConfig( const Config& conf ) {
            conf.getObjIfSet( "fill", _fill );
            conf.getObjIfSet( "halo", _halo );
            conf.getIfSet( "font", _font );
            conf.getIfSet( "size", _size );
            conf.getIfSet( "content", _content );
            conf.getIfSet( "content_attribute_delim", _contentAttributeDelimiter );
            conf.getIfSet( "attribute", _attribute );
            conf.getIfSet( "rotate_to_screen", _rotateToScreen );
            conf.getIfSet( "remove_duplicate_labels", _removeDuplicateLabels );
            conf.getIfSet( "size_mode", "screen", _sizeMode, SIZEMODE_SCREEN );
            conf.getIfSet( "size_mode", "object", _sizeMode, SIZEMODE_OBJECT );
            conf.getIfSet( "line_orientation", "parallel", _lineOrientation, LINEORIENTATION_PARALLEL );
            conf.getIfSet( "line_orientation", "perpendicular", _lineOrientation, LINEORIENTATION_PERPENDICULAR );
            conf.getIfSet( "line_orientation", "horizontal", _lineOrientation, LINEORIENTATION_HORIZONTAL );
            conf.getIfSet( "line_placement", "along_line", _linePlacement, LINEPLACEMENT_ALONG_LINE );
            conf.getIfSet( "line_placement", "centroid", _linePlacement, LINEPLACEMENT_CENTROID );
            conf.getIfSet( "theme", _theme );
            if ( conf.hasValue( "pixel_offset_x" ) )
                _pixelOffset = osg::Vec2s( conf.value<short>("pixel_offset_x",0), 0 );
            if ( conf.hasValue( "pixel_offset_y" ) )
                _pixelOffset = osg::Vec2s( _pixelOffset->x(), conf.value<short>("pixel_offset_y",0) );
        }

    protected:
        optional<Fill>            _fill;
        optional<Stroke>          _halo;
        optional<std::string>     _font;
        optional<float>           _size;
        optional<std::string>     _content;
        optional<std::string>     _contentAttributeDelimiter;
        optional<std::string>     _attribute;
        optional<bool>            _rotateToScreen;
        optional<bool>            _removeDuplicateLabels;
        optional<SizeMode>        _sizeMode;
        optional<LineOrientation> _lineOrientation;
        optional<LinePlacement>   _linePlacement;
        optional<std::string>     _theme;
        optional<osg::Vec2s>      _pixelOffset;
    };

} } // namespace osgEarth::Symbology

#endif // OSGEARTHSYMBOLOGY_TEXT_SYMBOL_H

