/***************************** LICENSE START ***********************************

 Copyright 2021 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

/*!

 \file GeoToKML.cc
 \brief Implementation of ...
 \author Graphics Section, ECMWF

 Started: Jan-2009

 \todo Fill this skeleton for new Metview module with life!
*/

#include <fstream>
#include <iostream>
#include <sstream>

#include "fstream_mars_fix.h"

#include "Metview.h"
#include "MvException.h"
#include "MvGeoPoints.h"
#include "MvStopWatch.h"

//! For generating KMZ files
/*extern "C"{
#include <sys/stat.h>
#include "minizip/zip.h"
#define MAXFILENAME 256
#define WRITEBUFFERSIZE 16384
}
*/

/*!
 \class GeoToKML
 \brief Definiton of class GeoToKML
 \sa MvService
*/
class GeoToKML : public MvService
{
public:
    GeoToKML();
    ~GeoToKML();

    GeoToKML(const GeoToKML&) = delete;
    void operator=(const GeoToKML&) = delete;

    void serve(MvRequest& in, MvRequest& out);
};

/*!
 \brief Contructor of GeoToKML
 \sa MvService
*/
GeoToKML::GeoToKML() :
    MvService("GeoToKML")
{
}

/*!
 \brief Destructor of GeoToKML
 \sa MvService
*/
GeoToKML::~GeoToKML() = default;

class ToPlacemark
{
    MvGeoPoints GPoints;

    //    double North;
    //    double South;
    //    double West;
    //    double East;

public:
    ToPlacemark(MvRequest&);
    void write(std::string, MvRequest&);
};

ToPlacemark::ToPlacemark(MvRequest& def)
{
    /*	North     = def("AREA", 0);
	West      = def("AREA", 1);
	South     = def("AREA", 2);
	East      = def("AREA", 3);

	if(North < South)
	{
		double tmp = North;
		North      = South;
		South      = tmp;
	}
*/
    MvRequest data;
    def.getValue(data, "GEOPOINTS");
    const char* path = data("PATH");
    GPoints.load(path);
}

void ToPlacemark::write(std::string name, MvRequest& def)
{
    std::ofstream pFile_;
    if (strcmp(def("OUTPUT_FORMAT"), "KMZ") == 0)
        pFile_.open("doc.kml");
    else
        pFile_.open(name.c_str());

    if (!pFile_) {
        std::ostringstream oss;
        oss << "GeoToKML-> write() --> Cannot open KML output file: " << name;
        throw MvException(oss.str());
    }

    pFile_ << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
           << "<kml xmlns=\"http://www.opengis.net/kml/2.2\" \n"
           << "    xmlns:gx=\"http://www.google.com/kml/ext/2.2\"\n"
           << "     xmlns:atom=\"http://www.w3.org/2005/Atom\">\n"
           << "<Folder>\n"
           << " <name>Metview GeoToKML output</name>\n"
           << " <open>1</open>\n"
           << " <description>\n"
           << " <![CDATA[This KML file was generated by Metview 4 using the GeoToKML module.]]>\n"
           << " </description>\n";

    // Write data as loose Placemarks
    if (strcmp(def("OUTPUT_MODE"), "POI") == 0) {
        for (size_t s = 0; s < GPoints.count(); s++) {
            const double value = GPoints.value(s);
            const long time    = GPoints.time(s);
            const long date    = GPoints.date(s);
            std::stringstream out;
            out << date;
            const std::string da = out.str();
            const double lon     = (GPoints.lon_x(s) > 180) ? GPoints.lon_x(s) - 360 : GPoints.lon_x(s);

            pFile_ << "  <Placemark>\n"
                   << "   <name>" << value << "</name>\n"
                   << "   <description><![CDATA[</p><p>Date: " << da.substr(0, 4) << "-" << da.substr(4, 2) << "-" << da.substr(6, 2) << "</p><p>Time: " << time << "</p>]]></description>\n"
                   << "   <TimeStamp>\n"
                   << "     <when>" << da.substr(0, 4) << "-" << da.substr(4, 2) << "-" << da.substr(6, 2) << "T";

            if (int(time / 100) < 10)
                pFile_ << "0";
            pFile_ << int(time / 100) << ":";
            if (int(time % 100) < 10)
                pFile_ << "0";
            pFile_ << int(time % 100) << ":00Z</when>\n"
                   << "   </TimeStamp>\n"
                   << "   <Point>\n"
                   << "     <coordinates>" << lon << "," << GPoints.lat_y(s) << "," << GPoints.height(s) << "</coordinates>\n"
                   << "   </Point>\n"
                   << "  </Placemark>\n";
        }
    }
    else if (strcmp(def("OUTPUT_MODE"), "TRA") == 0)  // tracks
    {
        std::stringstream coords;
        for (size_t s = 0; s < GPoints.count(); s++) {
            //const double value = GPoints[s].value();
            const long time = GPoints.time(s);
            const long date = GPoints.date(s);
            std::stringstream out;
            out << date;
            const std::string da = out.str();
            const double lon     = (GPoints.lon_x(s) > 180) ? GPoints.lon_x(s) - 360 : GPoints.lon_x(s);

            if (s == 0) {
                pFile_ << "  <Placemark>\n"
                       << "   <name>Metview4 track</name>\n"
                       << "   <description>Date: " << da << " T:" << time << "</description>\n"
                       << "  <gx:Track>\n";
            }

            pFile_ << "   <when>" << da.substr(0, 4) << "-" << da.substr(4, 2) << "-" << da.substr(6, 2) << "T";
            if (int(time / 100) < 10)
                pFile_ << "0";
            pFile_ << int(time / 100) << ":";
            if (int(time % 100) < 10)
                pFile_ << "0";
            pFile_ << int(time % 100) << ":00Z</when>\n";
            coords << "   <gx:coord>" << lon << " " << GPoints.lat_y(s) << " " << GPoints.height(s) * 1000 << "</gx:coord>\n";
        }
        pFile_ << coords.str() << "\n  </gx:Track>\n </Placemark>\n";
    }
    // Write data as loose Placemarks
    else if (strcmp(def("OUTPUT_MODE"), "POL") == 0) {
        for (size_t s = 0; s < GPoints.count(); s++) {
            //const double value = GPoints[s].value();
            const long time = GPoints.time(s);
            const long date = GPoints.date(s);
            std::stringstream out;
            out << date;
            const std::string da = out.str();
            if (s == 0) {
                pFile_ << "  <Placemark>\n"
                       << "   <name>Metview4 polygon</name>\n"
                       << "   <description><![CDATA[</p><p>Date: " << da.substr(0, 4) << "-" << da.substr(4, 2) << "-" << da.substr(6, 2) << "</p><p>Time: " << time << "</p>]]></description>\n"
                       << "   <Polygon>\n <extrude>1</extrude>\n <altitudeMode>relativeToGround</altitudeMode>\n <outerBoundaryIs><LinearRing>\n"
                       << "     <coordinates>\n";
            }

            const double lon = (GPoints.lon_x(s) > 180) ? GPoints.lon_x(s) - 360 : GPoints.lon_x(s);

            pFile_ << "  " << lon << "," << GPoints.lat_y(s) << "," << GPoints.height(s) << "\n";
        }

        pFile_ << " </coordinates>\n"
               << "   </LinearRing></outerBoundaryIs>\n</Polygon>\n"
               << "  </Placemark>\n";
    }

    pFile_ << "</Folder>\n</kml>\n";
    pFile_.close();


    // KMZ
    /*  if(strcmp(def("OUTPUT_FORMAT"),"KMZ") == 0)
  {
	   zipFile zf;
	   int err=0;

	   zf = zipOpen(fileName_.c_str(),0);
           if (zf == 0)
           {
               printf("ERROR opening zip file %s\n",fileName_.c_str());
               err= ZIP_ERRNO;
           }
           else
	   {
		int size_buf = WRITEBUFFERSIZE;
		void* buf = (void*)malloc(size_buf);
		if (buf==0)
		{
			Log::error() <<"Error allocating memory for KMZ generation!"<<endl;
			return;
		}
		stringarray::iterator it    = kml_output_resource_list_.begin();
		stringarray::iterator itend = kml_output_resource_list_.end();
		for(; it != itend; it++)
		{
			if(getDebug()) Log::dev()<< "KMLDriver.close() > Start adding file " <<  *it << " to KMZ file.\n";
			FILE * fin;
			int size_read;

			const char *filename = (*it).c_str();

			err = zipOpenNewFileInZip(zf,filename, 0, 0, 0, 0, 0, 0, Z_DEFLATED, Z_DEFAULT_COMPRESSION);

			if(err != ZIP_OK)
				Log::error() << "Could NOT open ... KMZ file!" << std::endl;
			else
			{
			  fin = fopen(filename,"rb");
			  if(fin==0)
			  {
			     Log::fatal() << "Open file "<<filename<<" to be added to KMZ FAILED!"<< endl;
			     return;
			  }
			  else
			  {
			    do{
				err=ZIP_OK;
				size_read = (int)fread(buf,1,size_buf,fin);
				if (size_read < size_buf)
				  if (feof(fin)==0)
				  {
					Log::error() << "Could NOT add "<<(*it) << std::endl;
					err = ZIP_ERRNO;
				  }

				if (size_read>0)
				{
				  err = zipWriteInFileInZip(zf,buf,size_read);
				  if (err<0)
				  {
					Log::error() << "Could NOT write KMZ file "<< fileName_<< endl;
				  }
				}
			     } while ((err==ZIP_OK) && (size_read>0));
			  }
			  if (fin)
				fclose(fin);
			}

			if (err<0)
				err=ZIP_ERRNO;
			else
			{
				err = zipCloseFileInZip(zf);
				if (err!=ZIP_OK)
					printf("error in closing xxxx in the zipfile\n");
			}
//				delete [] filename;
		}
		free(buf);

		err = zipClose(zf,0);
		if (err != ZIP_OK)
			printf("error in closing %s\n",fileName_.c_str());
		else if (!getDebug())
		{
			stringarray::iterator it = kml_output_resource_list_.begin();
			stringarray::iterator itend = kml_output_resource_list_.end();
			for(; it != itend; it++)
			{
				remove((*it).c_str());
			}
			printOutputName("KML kmz "+fileName_);
}
	   }// Zipping ---> K M Z
	}
*/
}


/*!
 \brief Method to process requests
 \sa MvRequest
*/
void GeoToKML::serve(MvRequest& in, MvRequest& out)
{
    std::string outname = marstmp();
    outname += ".kmz";
    ToPlacemark placemarks(in);
    placemarks.write(outname, in);

    MvRequest kml    = "KML";
    kml("PATH")      = outname.c_str();
    kml("TEMPORARY") = 1;

    out = kml;
}

/*!
 \brief Main program of module GeoToKML
*/
int main(int argc, char** argv)
{
    MvApplication theApp(argc, argv);
    GeoToKML module;

    theApp.run();
}
