/*
*
* This file is part of QMapControl,
* an open-source cross-platform map widget
*
* Copyright (C) 2007 - 2008 Kai Winter
*
* This program 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 3 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 QMapControl. If not, see <http://www.gnu.org/licenses/>.
*
* Contact e-mail: kaiwinter@gmx.de
* Program URL   : http://qmapcontrol.sourceforge.net/
*
*/

#ifndef POINT_H
#define POINT_H
#include <QWidget>

#include "geometry.h"

namespace qmapcontrol
{
    //! A geometric point to draw objects into maps
    /*!
     * This class can be used to draw your custom QPixmap or other QWidgets into maps.
     * You can instantiate a Point with any Pixmap you want. The objects cares about collision detection (for clickable objects)
     *
     * When drawing a pixmap, take care you are adding the point to a GeometryLayer.
     * You can also add a point to a MapLayer, but this should only be done, if the point is not changing its position or color etc.
     * (GeometryLayers are assured to be repainted on any changes at the point. MapLayers only gets repainted, if a new
     * offscreenImage is painter. This is a performance issue.)
     *
     * Points emit click events, if the containing layer receives clickevents (the default)
     *
     * You can also add a widget into maps. But keep in mind, that widgets always are drawn on top of all layers.
     * You also have to handle click events yourself.
     *
     * To create "zoomable objects" (objects that increases size on zooming), a base level have to be set.
     * The base level is the zoom level on which the point´s pixmap gets displayed on full size.
     * On lower zoom levels it gets displayed smaller and on higher zoom levels larger.
     * A minimal size can be set as well as a maximum size.
     * @see setBaselevel, setMinsize, setMaxsize
     *
     * @author Kai Winter <kaiwinter@gmx.de>
     */
    class Point : public Geometry
    {
        Q_OBJECT

    public:
        friend class Layer;
        friend class LineString;

        //! sets where the point should be aligned
        enum Alignment
        {
            TopLeft, /*!< Align on TopLeft*/
            TopRight, /*!< Align on TopRight*/
            BottomLeft, /*!< Align on BottomLeft*/
            BottomRight,/*!< Align on BottomRight*/
            Middle /*!< Align on Middle*/
        };

        Point();
        explicit Point(const Point&);
        //! Copy Constructor
        /*!
         * This constructor creates a Point with no image or widget.
         * @param x longitude
         * @param y latitude
         * @param name name of the point
         * @param alignment allignment of the point (Middle or TopLeft)
         */
        Point(qreal x, qreal y, QString name = QString(), enum Alignment alignment=Middle);

        //! Constructor
        /*!
         * This constructor creates a point which will display the given widget.
         * You can set an alignment on which corner the widget should be aligned to the coordinate.
         * You have to set the size of the widget, before adding it to
         * IMPORTANT: You have to set the QMapControl as parent for the widget!
         * @param x longitude
         * @param y latitude
         * @param widget the widget which should be displayed by this point
         * @param name name of the point
         * @param alignment allignment of the point (Middle or TopLeft)
         */
        Point(qreal x, qreal y, QWidget* widget, QString name = QString(), enum Alignment alignment = Middle);

        //! Constructor
        /*!
         * This constructor creates a point which will display the give pixmap.
         * You can set an alignment on which corner the pixmap should be aligned to the coordinate.
         * @param x longitude
         * @param y latitude
         * @param pixmap the pixmap which should be displayed by this point
         * @param name name of the point
         * @param alignment allignment of the point (Middle or TopLeft)
         */
        Point(qreal x, qreal y, QPixmap* pixmap, QString name = QString(), enum Alignment alignment = Middle);
        virtual ~Point();

        //! returns the bounding box of the point
        /*!
         * The Bounding contains the coordinate of the point and its size.
         * The size is set, if the point contains a pixmap or a widget
         * @return the bounding box of the point
         */
        virtual QRectF boundingBox();

        //! returns the longitude of the point
        /*!
         * @return the longitude of the point
         */
        qreal longitude() const;

        //! returns the latitude of the point
        /*!
         * @return the latitude of the point
         */
        qreal latitude() const;

        //! returns the coordinate of the point
        /*!
         * The x component of the returned QPointF is the longitude value,
         * the y component the latitude
         * @return the coordinate of a point
         */
        QPointF coordinate() const;

        virtual QList<Point*>& points();

        /*! \brief returns the widget of the point
        @return the widget of the point
         */
        QWidget* widget();

        //! returns the pixmap of the point
        /*!
         * @return the pixmap of the point
         */
        QPixmap* pixmap();

        //! Sets the zoom level on which the point�s pixmap gets displayed on full size
        /*!
         * Use this method to set a zoom level on which the pixmap gets displayed with its real size.
         * On zoomlevels below it will be displayed smaller, and on zoom levels thereover it will be displayed larger
         * @see setMinsize, setMaxsize
         * @param zoomlevel the zoomlevel on which the point will be displayed on full size
         */
        void setBaselevel(int zoomlevel);

        //! sets a minimal size for the pixmap
        /*!
         * When the point's pixmap should change its size on zooming, this method sets the minimal size.
         * @see setBaselevel
         * @param minsize the minimal size which the pixmap should have
         */
        void setMinsize(QSize minsize);

        //! sets a maximal size for the pixmap
        /*!
         * When the point´s pixmap should change its size on zooming, this method sets the maximal size.
         * @see setBaselevel
         * @param maxsize the maximal size which the pixmap should have
         */
        void setMaxsize(QSize maxsize);

        Point::Alignment alignment() const;

    protected:
        qreal X;
        qreal Y;
        QSize size;

        QWidget* mywidget;
        QPixmap* mypixmap;
        Alignment myalignment;
        int homelevel;
        QSize displaysize;
        QSize minsize;
        QSize maxsize;
        QList<Point*> m_points;


        void drawWidget(const MapAdapter* mapadapter, const QPoint offset);
        // void drawPixmap(QPainter* painter, const MapAdapter* mapadapter, const QRect &viewport, const QPoint versch);
        virtual void draw(QPainter* painter, const MapAdapter* mapadapter, const QRect &viewport, const QPoint offset);
        QPoint alignedPoint(const QPoint point) const;

        //! returns true if the given Point touches this Point
        /*!
         * The collision detection checks for the bounding rectangulars.
         * @param geom the other point which should be tested on collision
         * @param mapadapter the mapadapter which is used for calculations
         * @return
         */
        virtual bool Touches(Point* geom, const MapAdapter* mapadapter);

    public slots:
        void setCoordinate(QPointF point);
        virtual void setVisible(bool visible);
    };
}
#endif
