/*
    QAD - Qt ADvanced

    Ivan Pelipenko peri4ko@yandex.ru

    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 this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef mapview_h
#define mapview_h

#include "mapitembase.h"
#include "qad_map_export.h"

#include <QGeoCoordinate>
#include <QImage>
#include <QWidget>


class MapViewTileDownloader;
class MapViewTileProviderBase;
class MapViewTileCache;

class QAD_MAP_EXPORT MapView: public QWidget {
	Q_OBJECT
	Q_PROPERTY(QPointF center READ center WRITE setCenter)
	Q_PROPERTY(double zoom READ getZoom WRITE setZoom)
	Q_PROPERTY(double contrast READ getContrast WRITE setContrast)
	Q_PROPERTY(bool offlineMode READ isOfflineMode WRITE setOfflineMode)

	friend class MapViewTileDownloader;
	friend class MapViewTileCache;
	friend class MapItemBase;

public:
	explicit MapView(QWidget * parent = 0);
	~MapView();

	void addItem(MapItemBase * item);
	void removeItem(MapItemBase * item);

	QPointF center() const;
	void setCenter(QPointF c);
	void setCenter(QGeoCoordinate c) { setCenter(QPointF(c.latitude(), c.longitude())); }

	int getCurrentZoomLevel() const { return zoom_level; }
	int getMaximumZoomLevel() const { return max_level; }
	double getZoom() const { return zoom_; }
	void setZoom(double z);

	double getContrast() const { return contrast; }

	/// 0 - 100
	void setContrast(double value);

	/// {lat, lng}
	QPointF clickedCoordinate() const { return last_click_coord; }

	QString cachePath() const;
	void setCachePath(const QString & p);

	bool isOfflineMode() const { return is_offline; }
	void setOfflineMode(bool yes);

	void setTileObsoleteTime(int secs);
	void setTileProvider(MapViewTileProviderBase * p);
	MapViewTileProviderBase * tileProvider() const;

	void downloadCurrentView(int target_zoom_level = 17, bool only_new = true, int parallel = 1);

protected:
	QSize sizeHint() const override { return QSize(200, 200); }
	void mousePressEvent(QMouseEvent * e) override;
	void mouseReleaseEvent(QMouseEvent * e) override;
	void mouseDoubleClickEvent(QMouseEvent * e) override;
	void mouseMoveEvent(QMouseEvent * e) override;
	void wheelEvent(QWheelEvent * e) override;
	void paintEvent(QPaintEvent *) override;
	void resizeEvent(QResizeEvent *) override;

private:
	void drawBackground();
	void drawItems(QPainter & p);
	void checkZoom();
	void checkCenter();
	void zoomLevelChanged(int new_level);
	void updateZoomLevel();
	void updateViewRect();
	void updateMouse(QPoint mouse);
	double scalePx2M(QPointF norm);

	QPointF mapToNorm(QPoint screen) const;
	QPoint mapFromNorm(QPointF norm) const;

	MapViewTileDownloader * downloader = nullptr;
	MapViewTileCache * cache           = nullptr;
	MapItemBase * hover                = nullptr;
	QPointF center_                    = QPointF(0.5, 0.5);
	QPointF last_click_coord           = center_;
	QPoint press_point, zoom_anchor;
	QPixmap background;
	QRectF view_rect;
	QVector<MapItemBase *> items_;
	QBrush brush_tr;
	bool is_pan = false, is_downloading = false, is_offline = false;
	double zoom_ = 1., scale_ = 1., px2m = 1., contrast = 100.;
	int zoom_level = 0, tiles_side = 1, max_level = 19;

public slots:
	void zoom(double factor);
	void zoom(double factor, QPoint anchor);
	void zoomTo(double level);
	void centerTo(QPointF coord);

private slots:

signals:
	void mapClicked(QPointF);
	void itemClicked(MapItemBase * item);
	void itemEntered(MapItemBase * item);
	void itemLeaved(MapItemBase * item);
};


#endif
