/* -*- c++ -*-
 *
 * Copyright (C) 2004-2006 Mekensleep
 *
 *	Mekensleep
 *	24 rue vieille du temple
 *	75004 Paris
 *       licensing@mekensleep.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * Authors:
 *  Loic Dachary <loic@gnu.org>
 *
 */

#ifndef BETSLIDER
#define BETSLIDER

#ifndef UGAME_USE_VS_PCH

#include <osg/Vec4>
#include <osg/Group>
#include <osgDB/ReaderWriter>

#endif

#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined( __BCPLUSPLUS__) || defined( __MWERKS__)
	#  ifdef BETSLIDER_LIBRARY
	#    define BETSLIDER_EXPORT   __declspec(dllexport)
	#  else
	#    define BETSLIDER_EXPORT   __declspec(dllimport)
	#  endif /* BETSLIDER_LIBRARY */
#else
	#  define BETSLIDER_EXPORT
#endif

#ifdef UNITTEST
#undef BETSLIDER_EXPORT
#define BETSLIDER_EXPORT
#endif

extern "C" {
  struct _xmlDoc;
}

namespace osg {
  class Geode;
  class Geometry;
  class PositionAttitudeTransform;
};

namespace osgText {
  class Text;
  class Font;
};

namespace betslider {

  class BETSLIDER_EXPORT BetSlider : public osg::Group {
  public:
    enum RowIndex {
      ROW_CANCEL = 0,
      ROW_CALL,
      ROW_RAISE,
      ROW_POT,
      ROW_RAISE_MAX,
      ROW_CURRENT_POT_AMOUNT,
      ROW_CURRENT_RAISE_AMOUNT,
      ROW_COUNT
    };

    enum SideIndex {
      SIDE_LEFT = 0,
      SIDE_RIGHT,
      SIDE_COUNT
    };

    META_Node(betslider, BetSlider)

    class Background : public Referenced {
    public:
      enum BackgroundType { RECTANGLE = 1, IMAGE };

      virtual enum BackgroundType getType() = 0;
      virtual void stretch(float left_width, float right_width, float height) = 0;

    protected:
      virtual ~Background();

    public:
      osg::ref_ptr<osg::Geometry> _geometry;
    };

    class RectangleBackground : public Background {
    public:
      RectangleBackground();

      virtual enum BackgroundType getType() { return RECTANGLE; }

      virtual void stretch(float left_width, float right_width, float height);

      void setBackgroundColor(int side_index, const osg::Vec4& background_color);
      void setMiddleColor(const osg::Vec4& middle_color);
      void setMiddleWidth(float middle_width);

    protected:
      virtual ~RectangleBackground();

    public:
      osg::Vec4 _background_color[SIDE_COUNT];
      osg::Vec4 _middle_color;
      float _middle_width;
    };
    
    class ImageBackground : public Background {
    public:
      //
      // Unit is pixel on the background image used as
      // a texture.
      //                  s   s
      //                  t m t
      //                  r i r
      //                  e d e
      //                  t d t
      //                  c l c
      //                  h e h
      //         left              right
      //      +----------+-+-+-+-----------+
      //      |          | | | |           |
      //      |          | | | |           | top
      //      |          | | | |           | 
      // y    +----------+-+-+-+-----------+
      // =--->|          | | | |           | stretch
      // 0    +----------+-+-+-+-----------+
      //      |          | | | |           |
      //      |          | | | |           | bottom
      //      |          | | | |           |
      //      +----------+-+-+-+-----------+
      //                    ^
      //                    |
      //                    |
      //                  x = 0
      //
      virtual enum BackgroundType getType() { return IMAGE; }

      ImageBackground();

      virtual void stretch(float left_width, float right_width, float height);

    protected:
      virtual ~ImageBackground();

    public:
      float _left;
      float _right;
      float _top;
      float _bottom;
      float _middle;
			float _z;
      osg::ref_ptr<osg::Vec3Array> _vertexes;
    };

    class RowBackground : public Referenced {
    public:
      RowBackground();

      void update(const osg::Vec2& bottom_left, const osg::Vec2& top_right);
      void setColor(const osg::Vec4& background_color);
      const std::string& when() { return _when; }

    protected:
      virtual ~RowBackground();

    public:
      float _left_pad;
      float _right_pad;
      float _bottom_pad;
      float _top_pad;
      std::string _when;
      osg::ref_ptr<osg::Geometry> _geometry;
    };

    BetSlider();
    BetSlider(const BetSlider&, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);

  protected:
    virtual ~BetSlider();

  public:
    void setFont(int side_index, osgText::Font* font, float font_size);
    void setNormalColor(int row_index, int side_index, const osg::Vec4& color);
    void setSelectedColor(int row_index, int side_index, const osg::Vec4& color);
    void setRowBackground(int row_index, int side_index, RowBackground* background);
    void setSeparator(osg::Geode* separator);
    void setCursor(osg::Geode* cursor);
    void setMotorFixedLength(float motor_fixed_length) { _motor_fixed_length = motor_fixed_length; }
    void setMotorVariableLength(float motor_variable_length) { _motor_variable_length = motor_variable_length; }
    void setCenterPad(float pad);
    void setBorderPad(float pad);

    void setLimits(unsigned int call, unsigned int raise, unsigned int raise_max, unsigned int all_in, unsigned int pot, unsigned int step);

    unsigned int moveCursor(float delta);

    unsigned int getCurrentValue();
    RowIndex getCurrentIndex();

    Background* getBackground() { return _background.get(); }
    void replaceBackground(Background* background);

    bool unserialize(struct _xmlDoc* doc, const osgDB::ReaderWriter::Options* options);
    bool unserialize(const std::string& fileName, const osgDB::ReaderWriter::Options* options);
    bool serialize(const std::string& fileName) const;

  protected:
    class Row : public Referenced {
    public:
      Row(osg::Geode* geode, bool left, bool right, const osg::PositionAttitudeTransform* separator);

      void setText(const std::string& left, const std::string& right);
      void setMotorRange(float& origin, float length);
      void setCursorRange(float& origin, float& cursor, float height);
      void setValueRange(unsigned int value_start, unsigned int value_end) {
	_value_start = value_start;
	_value_end = value_end;
      }
      void setSeparator(osg::Group* group, osg::PositionAttitudeTransform* separator);
      osg::BoundingBox getBound() const;
      void add(osg::Group* group);
      void remove(osg::Group* group);
      void selected();
      void unselected();

    protected:
      virtual ~Row();

    public:
      bool _defines_range;
      bool _active;
      bool _variable;
      unsigned int _value_start;
      unsigned int _value_end;
      float _cursor_start;
      float _cursor_end;
      float _motor_start;
      float _motor_end;
      osg::ref_ptr<osg::Geode> _geode;
      osg::ref_ptr<osgText::Text> _text[SIDE_COUNT];
      osg::Vec4 _normal[SIDE_COUNT];
      osg::Vec4 _selected[SIDE_COUNT];
      osg::ref_ptr<RowBackground> _background[SIDE_COUNT];
      osg::ref_ptr<osg::PositionAttitudeTransform> _separator;
    };

    void layout();
    void build();
    Row* getCurrentRow();
    void setMotorPosition(float motor_position);
    void updateCursorPosition();
    void updateCurrentValue();
public:
    osg::ref_ptr<osg::Geode> _geode;
    osg::ref_ptr<Background> _background;
    typedef std::vector<osg::ref_ptr<Row> > Rows;
    Rows _rows;
    osg::ref_ptr<osgText::Font> _font[SIDE_COUNT];
    float _font_size[SIDE_COUNT];
    float _height;
    float _center_pad;
    float _border_pad;
    float _motor_span;
    float _motor_position;
    float _motor_fixed_length;
    float _motor_variable_length;
    float _cursor_position;
    unsigned int _value_step;
    osg::ref_ptr<osg::PositionAttitudeTransform> _separator;
    osg::ref_ptr<osg::PositionAttitudeTransform> _cursor;
  };

} // namespace betslider

#endif // BETSLIDER
