/***************************************************************************
                              qgswmsserver.h
                              -------------------
  begin                : May 14, 2006
  copyright            : (C) 2006 by Marco Hugentobler
  email                : marco dot hugentobler at karto dot baug dot ethz dot ch
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef QGSWMSSERVER_H
#define QGSWMSSERVER_H

#include <QDomDocument>
#include <QMap>
#include <QString>
#include <map>

class QgsCoordinateReferenceSystem;
class QgsComposerLayerItem;
class QgsComposerLegendItem;
class QgsComposition;
class QgsMapLayer;
class QgsMapRenderer;
class QgsPoint;
class QgsRasterLayer;
class QgsConfigParser;
class QgsVectorLayer;
class QgsSymbol;
class QFile;
class QFont;
class QImage;
class QPaintDevice;
class QPainter;

/**This class handles all the wms server requests. The parameters and values have to be passed in the form of
a map<QString, QString>. This map is usually generated by a subclass of QgsWMSRequestHandler, which makes QgsWMSServer
independent from any server side technology*/

class QgsWMSServer
{
  public:
    /**Constructor. Takes parameter map and a pointer to a renderer object (does not take ownership)*/
    QgsWMSServer( std::map<QString, QString> parameters, QgsMapRenderer* renderer );
    ~QgsWMSServer();
    /**Returns an XML file with the capabilities description (as described in the WMS specs)*/
    QDomDocument getCapabilities();
    /**Returns the map legend as an image (or a null pointer in case of error). The caller takes ownership\
    of the image object*/
    QImage* getLegendGraphics();
    /**Returns the map as an image (or a null pointer in case of error). The caller takes ownership\
    of the image object)*/
    QImage* getMap();
    /**Returns an SLD file with the style of the requested layer. Exception is raised in case of troubles :-)*/
    QDomDocument getStyle();

    /**Returns printed page as binary
      @param formatString out: format of the print output (e.g. pdf, svg, png, ...)
      @return printed page as binary or 0 in case of error*/
    QByteArray* getPrint( const QString& formatString );

    /**Creates an xml document that describes the result of the getFeatureInfo request.
       @return 0 in case of success*/
    int getFeatureInfo( QDomDocument& result );

    /**Sets configuration parser for administration settings. Does not take ownership*/
    void setAdminConfigParser( QgsConfigParser* parser ) { mConfigParser = parser; }

  private:
    /**Don't use the default constructor*/
    QgsWMSServer();

    /**Initializes WMS layers and configures mMapRendering.
      @param layersList out: list with WMS layer names
      @param stylesList out: list with WMS style names
      @param layerIdList out: list with QGIS layer ids
      @return image configured together with mMapRenderer (or 0 in case of error). The calling function takes ownership of the image*/
    QImage* initializeRendering( QStringList& layersList, QStringList& stylesList, QStringList& layerIdList );

    /**Creates a QImage from the HEIGHT and WIDTH parameters
     @param width image width (or -1 if width should be taken from WIDTH wms parameter)
     @param height image height (or -1 if height should be taken from HEIGHT wms parameter)
     @return 0 in case of error*/
    QImage* createImage( int width = -1, int height = -1 ) const;
    /**Configures mMapRenderer to the parameters
     HEIGHT, WIDTH, BBOX, CRS.
     @param paintDevice the device that is used for painting (for dpi)
     @return 0 in case of success*/
    int configureMapRender( const QPaintDevice* paintDevice ) const;
    /**Reads the layers and style lists from the parameters LAYERS and STYLES
     @return 0 in case of success*/
    int readLayersAndStyles( QStringList& layersList, QStringList& stylesList ) const;
    /**If the parameter SLD exists, mSLDParser is configured appropriately. The lists are
    set to the layer and style names according to the SLD
    @return 0 in case of success*/
    int initializeSLDParser( QStringList& layersList, QStringList& stylesList );
    /**Calculates the location of a feature info point in layer coordinates
     @param i pixel x-coordinate
    @param j pixel y-coordinate
    @param layerCoords calculated layer coordinates are assigned to this point
    @return 0 in case of success*/
    int infoPointToLayerCoordinates( int i, int j, QgsPoint& layerCoords, QgsMapRenderer* mapRender,
                                     QgsMapLayer* layer ) const;
    /**Appends feature info xml for the layer to the layer element of the feature info dom document
     @return 0 in case of success*/
    int featureInfoFromVectorLayer( QgsVectorLayer* layer, const QgsPoint& infoPoint, int nFeatures, QDomDocument& infoDocument, QDomElement& layerElement, QgsMapRenderer* mapRender,
                                    QMap<int, QString>& aliasMap, QSet<QString>& hiddenAttributes ) const;
    /**Appends feature info xml for the layer to the layer element of the dom document*/
    int featureInfoFromRasterLayer( QgsRasterLayer* layer, const QgsPoint& infoPoint, QDomDocument& infoDocument, QDomElement& layerElement ) const;

    /**Creates a layer set and returns a stringlist with layer ids that can be passed to a QgsMapRenderer. Usually used in conjunction with readLayersAndStyles*/
    QStringList layerSet( const QStringList& layersList, const QStringList& stylesList, const QgsCoordinateReferenceSystem& destCRS ) const;

    //helper functions for GetLegendGraphics
    /**Draws layer item and subitems
       @param p painter if the item should be drawn, if 0 the size parameters are calculated only
       @param maxTextWidth Includes boxSpace (on the right side). If p==0: maximumTextWidth is calculated, if p: maxTextWidth parameter is used for rendering
       @param maxSymbolWidth Includes boxSpace and iconLabelSpace. If p==0: maximum Symbol width is calculated, if p: maxSymbolWidth is input parameter
      */
    void drawLegendLayerItem( QgsComposerLayerItem* item, QPainter* p, double& maxTextWidth, double& maxSymbolWidth, double& currentY, const QFont& layerFont,
                              const QFont& itemFont, double boxSpace, double layerSpace, double symbolSpace, double iconLabelSpace,
                              double symbolWidth, double symbolHeight, double fontOversamplingFactor, double dpi ) const;
    /**Draws a (old generation) symbol. Optionally, maxHeight is adapted (e.g. for large point markers) */
    void drawLegendSymbol( QgsComposerLegendItem* item, QPainter* p, double boxSpace, double currentY, double& symbolWidth, double& symbolHeight,
                           double layerOpacity, double dpi, double yDownShift ) const;
    void drawPointSymbol( QPainter* p, QgsSymbol* s, double boxSpace, double currentY, double& symbolWidth, double& symbolHeight, double layerOpacity, double dpi ) const;
    void drawLineSymbol( QPainter* p, QgsSymbol* s, double boxSpace, double currentY, double symbolWidth, double symbolHeight, double layerOpacity, double yDownShift ) const;
    void drawPolygonSymbol( QPainter* p, QgsSymbol* s, double boxSpace, double currentY, double symbolWidth, double symbolHeight, double layerOpacity, double yDownShift ) const;
    void drawLegendSymbolV2( QgsComposerLegendItem* item, QPainter* p, double boxSpace, double currentY, double& symbolWidth, double& symbolHeight, double dpi, double yDownShift ) const;
    void drawRasterSymbol( QgsComposerLegendItem* item, QPainter* p, double boxSpace, double currentY, double symbolWidth, double symbolHeight, double yDownShift ) const;

    QImage* printCompositionToImage( QgsComposition* c ) const;

    /**Map containing the WMS parameters*/
    std::map<QString, QString> mParameterMap;
    QgsConfigParser* mConfigParser;
    QgsMapRenderer* mMapRenderer;
};

#endif
