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

 Copyright 2012 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 <iostream>
#include <sstream>
#include <fstream>

#include "Metview.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
{
private:
  GeoToKML( const GeoToKML& );
  void operator= ( const GeoToKML& );

public:
  GeoToKML();
  ~GeoToKML();

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

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

/*!
 \brief Destructor of GeoToKML
 \sa MvService
*/
GeoToKML::~GeoToKML(void)
{
}

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)
{
  ofstream pFile_;
  if(strcmp(def("OUTPUT_FORMAT"),"KMZ") == 0)
    pFile_.open("doc.kml");
  else
  pFile_.open(name.c_str());
  
  if(!pFile_)
  {
  	  cerr << "GeoToKML - write() --> Cannot open KML output file: " << name << "!\n";
  	  exit(1);
  }

  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 (int s = 0; s < GPoints.count(); s++)
   { 
      const double value = GPoints[s].value();
      const long   time  = GPoints[s].time();
      const long   date  = GPoints[s].date();
      std::stringstream out;
      out << date;
      const std::string da = out.str();
      const  double lon = (GPoints[s].lon_x() > 180) ? GPoints[s].lon_x() - 360 : GPoints[s].lon_x();

      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[s].lat_y()<<","<<GPoints[s].height()<<"</coordinates>\n"
              << "   </Point>\n"
              << "  </Placemark>\n";
  }
  }
  else if ( strcmp(def("OUTPUT_MODE"),"TRA") == 0)     // tracks
  {
   std::stringstream coords;
   for (int s = 0; s < GPoints.count(); s++)
   { 
      //const double value = GPoints[s].value();
      const long   time  = GPoints[s].time();
      const long   date  = GPoints[s].date();
      std::stringstream out;
      out << date;
      const std::string da = out.str();
      const  double lon = (GPoints[s].lon_x() > 180) ? GPoints[s].lon_x() - 360 : GPoints[s].lon_x();

      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[s].lat_y()<<" "<<GPoints[s].height()*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 (int s = 0; s < GPoints.count(); s++)
   { 
      //const double value = GPoints[s].value();
      const long   time  = GPoints[s].time();
      const long   date  = GPoints[s].date();
      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[s].lon_x() > 180) ? GPoints[s].lon_x() - 360 : GPoints[s].lon_x();

      pFile_  << "  "<<lon<<","<<GPoints[s].lat_y()<<","<<GPoints[s].height()<<"\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!" << 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) << 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();
}
