/******************************************************************************
 * $Id$
 *
 * Project:  MapServer
 * Purpose:  Headers for mapkmlrenderer.cpp Google Earth KML output
 * Author:   David Kana and the MapServer team
 *
 ******************************************************************************
 * Copyright (c) 1996-2009 Regents of the University of Minnesota.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies of this Software or works derived from this Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *****************************************************************************/

#ifndef MAPKMLRENDERER_H
#define MAPKMLRENDERER_H

#include "mapserver-config.h"
#if defined(USE_KML)

#include "mapserver.h"
#include "maplibxml2.h"

class KmlRenderer {
private:
  const char *pszLayerDescMetadata = nullptr; /*if the kml_description is set*/
  char **papszLayerIncludeItems = nullptr;
  int nIncludeItems = 0;
  char **papszLayerExcludeItems = nullptr;
  int nExcludeItems = 0;
  const char *pszLayerNameAttributeMetadata = nullptr;

protected:
  // map properties
  int Width = 0, Height = 0;
  rectObj MapExtent = {0, 0, 0, 0};
  double MapCellsize = 0;
  colorObj BgColor = {0, 0, 0, 0};
  char MapPath[MS_MAXPATHLEN] = {0};

  // xml nodes pointers
  xmlDocPtr XmlDoc = nullptr;
  xmlNodePtr DocNode = nullptr;
  xmlNodePtr LayerNode = nullptr;
  xmlNodePtr GroundOverlayNode = nullptr;

  xmlNodePtr PlacemarkNode = nullptr;
  xmlNodePtr GeomNode = nullptr;
  xmlNodePtr DescriptionNode = nullptr;

  int CurrentShapeIndex = 0;
  int CurrentDrawnShapeIndex = 0;
  char *CurrentShapeName = nullptr;
  char **Items = nullptr;
  int NumItems = 0;
  int DumpAttributes = 0;

  // placemark symbology
  hashTableObj *StyleHashTable = nullptr;

  colorObj LabelColor = {0, 0, 0, 0};
  strokeStyleObj *LineStyle = nullptr;
  int numLineStyle = 0;
  colorObj PolygonColor = {0, 0, 0, 0};

  char SymbolName[128] = {0};
  char SymbolUrl[128] = {0};

  enum { NumSymbologyFlag = 4 };
  char SymbologyFlag[NumSymbologyFlag] = {0, 0, 0, 0};

  enum symbFlagsEnum { Label, Line, Polygon, Symbol };

  int FirstLayer = 0;

  mapObj *map = nullptr;
  layerObj *currentLayer = nullptr;

  int AltitudeMode = 0;
  int Tessellate = 0;
  int Extrude = 0;

  enum altitudeModeEnum {
    undefined,
    clampToGround,
    relativeToGround,
    absolute
  };
  /**True if elevation is taken from a feature attribute*/
  bool mElevationFromAttribute = false;
  /**Attribute index of elevation (or -1 if elevation is not attribute driven*/
  int mElevationAttributeIndex = 0;
  double mCurrentElevationValue = 0;

  outputFormatObj *aggFormat = nullptr;

protected:
  imageObj *createInternalImage();
  xmlNodePtr createPlacemarkNode(xmlNodePtr parentNode, char *styleUrl);
  xmlNodePtr createGroundOverlayNode(xmlNodePtr parentNode, char *imageHref,
                                     layerObj *layer);
  xmlNodePtr createDescriptionNode(shapeObj *shape);

  const char *lookupSymbolUrl(imageObj *img, symbolObj *symbol,
                              symbolStyleObj *style);

  void addCoordsNode(xmlNodePtr parentNode, pointObj *pts, int numPts);

  void setupRenderingParams(hashTableObj *layerMetadata);
  void addAddRenderingSpecifications(xmlNodePtr node);

  int checkProjection(mapObj *map);

  int createIconImage(char *fileName, symbolObj *symbol, symbolStyleObj *style);

  void renderSymbol(imageObj *img, double x, double y, symbolObj *symbol,
                    symbolStyleObj *style);

  //////////////////////////////////////////////////////////////////////////////

  void renderLineVector(imageObj *img, shapeObj *p, strokeStyleObj *style);
  void renderPolygonVector(imageObj *img, shapeObj *p, colorObj *color);

  const char *lookupPlacemarkStyle();
  void flushPlacemark();
  xmlNodePtr getGeomParentNode(const char *geomName);
  char *getLayerName(layerObj *layer);
  void processLayer(layerObj *layer, outputFormatObj *format);
  void addLineStyleToList(strokeStyleObj *style);
  const char *getAliasName(layerObj *lp, char *pszItemName,
                           const char *namespaces);

public:
  KmlRenderer(int width, int height, outputFormatObj *format,
              colorObj *color = NULL);
  virtual ~KmlRenderer();

  imageObj *createImage(int width, int height, outputFormatObj *format,
                        colorObj *bg);
  int saveImage(imageObj *img, FILE *fp, outputFormatObj *format);

  int startNewLayer(imageObj *img, layerObj *layer);
  int closeNewLayer(imageObj *img, layerObj *layer);

  void startShape(imageObj *img, shapeObj *shape);
  void endShape(imageObj *img, shapeObj *shape);

  void renderLine(imageObj *img, shapeObj *p, strokeStyleObj *style);
  void renderPolygon(imageObj *img, shapeObj *p, colorObj *color);

  void renderGlyphs(imageObj *img, const textSymbolObj *ts, colorObj *c,
                    colorObj *oc, int ow);

  // Symbols
  void renderPixmapSymbol(imageObj *img, double x, double y, symbolObj *symbol,
                          symbolStyleObj *style);
  void renderVectorSymbol(imageObj *img, double x, double y, symbolObj *symbol,
                          symbolStyleObj *style);
  void renderEllipseSymbol(imageObj *img, double x, double y, symbolObj *symbol,
                           symbolStyleObj *style);
  void renderTruetypeSymbol(imageObj *img, double x, double y,
                            symbolObj *symbol, symbolStyleObj *style);

  int getTruetypeTextBBox(imageObj *img, char **fonts, int numfonts,
                          double size, char *string, rectObj *rect,
                          double **advances);
  int mergeRasterBuffer(imageObj *image, rasterBufferObj *rb);
};

#endif /* USE_KML */
#endif
