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

 Copyright 2017 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 *************************************/

#include "ShareTargets.h"

#include "GenAppService.hpp"
#include "MvPath.hpp"
#include "ObjectList.h"
#include "PlotMod.h"
#include "PlotModConst.h"

/* --------------------------------------------
 * ShareTargets - the registry of share targets 
 * -------------------------------------------- */

ShareTargets *ShareTargets::instance_ = 0;

ShareTargets *ShareTargets::instance()
{
   if (!instance_)
      instance_ = new ShareTargets();

   return instance_;
}

ShareTargets::~ShareTargets()
{
   if (instance_)
   {
      delete instance_;
      instance_ = 0;
   }
}

/* ---------------------------------------------------------
 * ShareTarget - the base class of each type of share target 
 * --------------------------------------------------------- */

ShareTarget::ShareTarget(const std::string& name, const std::string& icon) :
    name_(name),
    icon_(icon)
{
   // Register self to the list of available share targets
   ShareTargets::instance()->push_back(this);
}

/* ------------------------------------------------------
 * GlobeShareTarget - specific share target for the globe 
 * ------------------------------------------------------ */
#ifdef MV_SHARE_GLOBE_BUILD

#include <assert.h>

#include "MvQApplication.h"

GlobeShareTarget::GlobeShareTarget() : 
   ShareTarget("Weather Globe","globe.svg"),
   class_ ("GLOBE"),
   format_ ("GLOBEOUTPUT")
{}

bool GlobeShareTarget::dialog(Presentable* pres)
{
   // Save Presentable. It will be used to restore the contents
   // of the Display Window.
   if ( !pres )
   {
      PlotMod::Instance().errorMessage("WEATHER GLOBE: Internal Error: structure Presentable not available");
      return false;
   }
   presentable_ = pres;

   // Get output format request
   MvRequest reqFormat = ObjectList::Find ("output_format", class_.c_str());
   if ( string(reqFormat.getVerb()) == string("EMPTY") )
   {
      PlotMod::Instance().errorMessage("WEATHER GLOBE: Internal Error: GLOBEOutputDef file not found");
      return false;
   }

   // Read the selected output format request from the Metview/Defaults directory.
   // If not found, create a default request
   MvRequest reqOut = ObjectList::UserDefaultRequest ( (const char*)reqFormat("output") );

   // Parameter _NAME contains the output format filename.
   // If the file already exists, this parameter contains the absolute path.
   // Otherwise, it contains the following filename: absolute_path/<output_format_name>,
   // which needs to be replaced by relative_path/output_format_name.
   // There is a need to update this filename because the Desktop's Icon
   // Editor requires a relative path in order to be able to save the file.
   // If a relative path is not given, the Editor creates a temporary file, which
   // is not appropriate here.
   if ( !(const char*)reqOut("_NAME") )
   {
      PlotMod::Instance().errorMessage("WEATHER GLOBE: Internal Error: parameter _NAME not available");
      return false;
   }

   // If it is a new default request, then remove characters '<' and '>'
   string name = mbasename((const char*)reqOut("_NAME"));
   if ( name[0] == '<' ) // it is a default filename, remove the brackets
      name = name.substr(1,name.size()-2);

   // Get the prefix path (METVIEW_USER_DIRECTORY) and check it againt the filename
   string userDir = GetUserDirectory();
   string path = mdirname((const char*)reqOut("_NAME"));
   std::size_t found = path.find(userDir);
   if (found != std::string::npos)
      path = path.substr(userDir.size()); // remove the prefix path

   // Compose the filename
   string filename = path + '/' + name;
   reqOut("_NAME") = filename.c_str();

   // Call Metview user interface's editor
   CallGenAppService(*this,&GlobeShareTarget::edited,reqOut);

   return true;
}

void GlobeShareTarget::edited( MvRequest& reqUser )
{
   // Nothing to be edited. Button CANCEL selected by user.
   if(!reqUser)
      return;

   // Check user input parameters
   // Output file path must exist
   string spath = (const char*)reqUser("OUTPUT_GLOBE_DIRECTORY");
   if ( spath == "$MV_SHARE_GLOBE_PATH" )
   {
      if ( (const char*)getenv("MV_SHARE_GLOBE_PATH") )
         spath = (const char*)getenv("MV_SHARE_GLOBE_PATH");
      else
      {
         PlotMod::Instance().errorMessage("WEATHER GLOBE: Environment variable $MV_SHARE_GLOBE_PATH not defined");
         return;
      }
   }
   struct stat sb;
   if (stat(spath.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode))
   {
      PlotMod::Instance().errorMessage("WEATHER GLOBE: Directory not found: " + spath);
      return;
   }

   // Retrieve current plot request without output formats
   MvRequest req;
   presentable_->GetAllRequests( req, true );

   // Customise output request
   MvRequest outReq;
   this->customisePlotRequest(req,outReq);

   // Override cursor to "busy"
   QApplication::setOverrideCursor(QCursor(Qt::BusyCursor));

   // Call uPlotBatch syncronously to do the job
   int err;
   MvApplication::waitService ( "uPlotBatch", outReq, err );
//   MvApplication::callService("uPlotBatch",outReq,0);
   QApplication::restoreOverrideCursor();   // restore cursor
   if ( err )
      return;

   // uPlotBatch has finished. Upload file to Globe.
   this->upload();
}

#if 0
bool GlobeShareTarget::requirementsMet(std::string &msg)
{
   const char *path = (const char*)getenv("MV_SHARE_GLOBE_PATH");
   if (!path)
   {
      msg = "Environment variable MV_SHARE_GLOBE_PATH is not defined";
      return false;
   }
   else
      return true;
}
#endif

void GlobeShareTarget::customisePlotRequest(MvRequest& in,MvRequest& out)
{
   // Update SUPERPAGE and PAGE requests
   out = in;
   while (out)
   {
      if ( strcmp(out.getVerb(),"SUPERPAGE") == 0 )
      {
         out("SUPER_PAGE_X_LENGTH") = 100;
         out("SUPER_PAGE_Y_LENGTH") = 50;
      }
      else if ( strcmp(out.getVerb(),"PAGE") == 0 )
      {
         out("PAGE_X_LENGTH") = 100;
         out("PAGE_Y_LENGTH") = 50;
         out("PAGE_X_POSITION") = 0;
         out("PAGE_Y_POSITION") = 0;

         out("SUBPAGE_X_LENGTH") = 100;
         out("SUBPAGE_Y_LENGTH") = 50;
         out("SUBPAGE_X_POSITION") = 0;
         out("SUBPAGE_Y_POSITION") = 0;
      }
      out.advance();
   }
   out.rewind();

   // Read and expand user input info from the Metview/Defaults directory
   MvRequest reqDef = ObjectList::UserDefaultRequest (format_.c_str());
   MvRequest reqUser = ObjectList::ExpandRequest(reqDef,EXPAND_DEFAULTS);

   // Define output device
   string tname = (const char*)reqUser("OUTPUT_GLOBE_FILE_NAME");
   temp_fname_ = (const char*)MakeTmpName(tname.c_str());
   MvRequest devReq("PNGOUTPUT");
   devReq("OUTPUT_FULLNAME") = (const char*)((temp_fname_+".png").c_str());
   devReq("OUTPUT_WIDTH") = (int)reqUser("OUTPUT_GLOBE_IMAGE_WIDTH");
   devReq("OUTPUT_NAME_FIRST_PAGE_NUMBER") = "OFF";
   MvRequest outReq( "PRINTER_MANAGER" );
   outReq("DESTINATION") = MVFILE;
   outReq("OUTPUT_DEVICES") = devReq;

   out = outReq + out;
}

bool GlobeShareTarget::upload()
{
   // Read and expand user input info from the Metview/Defaults directory
   MvRequest reqDef = ObjectList::UserDefaultRequest (format_.c_str());
   MvRequest reqUser = ObjectList::ExpandRequest(reqDef,EXPAND_DEFAULTS);

   // Define output and input filenames
   string spath = (const char*)reqUser("OUTPUT_GLOBE_DIRECTORY");
   string fname = (const char*)reqUser("OUTPUT_GLOBE_FILE_NAME");
   string out_fname = spath + "/" + fname + ".mp4";
   string in_fname  = temp_fname_ + "*.png";

   // Call external function to create the animation
   string frate = (const char*)reqUser("OUTPUT_GLOBE_FRAME_RATE");
   string cmd = "ffmpeg -y -framerate " + frate + " -f image2 -pattern_type glob -i \'";
   cmd += in_fname;
   cmd += "\' -r 30 -vcodec libx264 -crf 25 -pix_fmt yuv420p ";
   cmd += out_fname;
   system (cmd.c_str());

   return true;
}

// create instances of the share targets we want to enable
static GlobeShareTarget globeShareTarget;

#endif
