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

//#include <QDebug>

#include <Assertions.hpp>
#include "GenAppService.hpp"
#include "MgQSceneItem.h"
#include "MvQApplication.h"
#include "MvQLayerContentsIcon.h"
#include "MvPath.hpp"
#include "MvRequestUtil.hpp"
#include "ObjectList.h"
#include "../libMetview/Path.h"  // path given to disambiguate from Magics Path.h
#include "Root.h"
#include "uPlotBase.h"


MvQLayerContentsIcon::MvQLayerContentsIcon(const QString& path, const QString& type, const QString& id) :
                        visibility_(true),
                        canBeDeleted_(false),
                        canBeEdited_(false),
                        canBeSaved_(false),
                        isData_(false)
{
   // Initialise first variables
   path_ = path;
   type_ = type;
   id_   = id;

//qDebug() << "Constructor MvQLayerContentsIcon " << path_ << type_ << id_;

   QStringList lst = path_.split("/");
   if( !lst.isEmpty() )
      name_=lst.last();

   // Get the pixmap full path&name and update the interface
   string fullName = this->getPixmapPath(type_.toStdString());
   if( !fullName.empty() )
   {
      std::size_t found = fullName.find_last_of(".");
      if ( found != std::string::npos)
      {
         QString name = QString::fromStdString(fullName.substr(0,found));
         char* suffix = strdup(fullName.substr(found+1).c_str());
         // const char* suffix = fullName.substr(found+1).c_str();  never use this because the result is compiler dependent.
         pix_ = QPixmap::fromImage(QImage(name,suffix)).scaled(QSize(24,24),Qt::KeepAspectRatio,Qt::SmoothTransformation);
         free(suffix);
      }
   }

   // Set icon permissions
   // Icon in this format, <icon_name> , means that this icon is a default
   // icon and it does not exist in directory ~/System/Defaults (Metview
   // icons default directory). Therefore, it can not be saved.
   string sclass = type_.toStdString();
   if( ObjectList::IsDataUnit(sclass.c_str()) )
   {
      canBeDeleted_ = true;
      canBeEdited_  = false;
      canBeSaved_   = false;
      isData_=true;
   }
   else if( ObjectList::IsVisDef(sclass.c_str()) ||
            ObjectList::IsVisDefText(sclass.c_str()) ||
            ObjectList::IsVisDefLegend(sclass.c_str()) ||
            ObjectList::IsVisDefImport(sclass.c_str())
          )
   {
      canBeDeleted_ = true;
      canBeEdited_  = true;
      canBeSaved_   = ( name_[0] == '<' && name_[name_.size()-1] == '>' ) ? false : true;
   }
   else if( ObjectList::IsVisDefCoastlines(sclass.c_str()) )
   {
      canBeDeleted_ = true;
      canBeEdited_  = false;
      canBeSaved_   = false;
   }
   else if( ObjectList::IsView(sclass.c_str()) )
   {
      // FAMI20160929: Edit and Save options are currently
	  // disabled because the current version can not handle
	  // embeded icons. Investigate the use of script mv_compress
      canBeDeleted_ = false;
      canBeEdited_  = false;
      canBeSaved_   = false; //( name_[0] == '<' && name_[name_.size()-1] == '>' ) ? false : true;
   }
   else
   {
      canBeDeleted_ = false;
      canBeEdited_  = false;
      canBeSaved_   = false;
   }
}

MvQLayerContentsIcon::~MvQLayerContentsIcon()
{
//   qDebug() << "deleting " << path_;
}

MvQLayerContentsIcon& MvQLayerContentsIcon::operator = (const MvQLayerContentsIcon& icon)
{
   path_ = icon.path_;
   type_ = icon.type_;
   id_   = icon.id_;
   name_ = icon.name_;
   pix_  = icon.pix_;

   canBeDeleted_ = icon.canBeDeleted_;
   canBeEdited_  = icon.canBeEdited_;
   canBeSaved_   = icon.canBeSaved_;
   isData_       = icon.isData_;

   return *this;
}

bool MvQLayerContentsIcon::operator == (const MvQLayerContentsIcon& icon)
{
   return ( path_ == icon.path_ && type_ == icon.type_ );
}

void MvQLayerContentsIcon::startEditor()
{
   if( !canBeEdited_ )
      return;

   // Get icon request to be edited.
   // Although the Desktop Editor can create a copy of this icon at the
   // Temporary Directory, it can not be used because it does not have
   // the hidden parameters. Mars function save_all_requests only saves
   // the hidden parameters if Metview is running in the debug mode.
   // The solution is to use the icon from the DataBase, but there is a
   // need to update parameter _NAME to point to the uPlot Temporary 
   // Directory; otherwise, the Desktop Editor will save the changes to 
   // the original icon.

   // Get Presentable SuperPage and the DataBase
   Presentable* pres = Root::Instance().FindSuperPage();
   MvIconDataBase& dataBase = pres->IconDataBase();

   // Retrieve icon from the DataBase
   MvIcon mvIcon;
   if ( !dataBase.FindIcon ( id_.toInt(), mvIcon ) )
      return; // icon not found

   // Add parameter indicating the name of the uPlot Temporary Directory.
   // This will be used by the Desktop  Editor
   MvRequest req = mvIcon.Request();
   string uTempDir = uPlotBase::tempDir();
   if ( uTempDir[uTempDir.size()-1] == '/' )   // remove last '/'
      uTempDir = uTempDir.substr(0,uTempDir.size()-1);

   std::size_t ipos = uTempDir.find_last_of("/");
   string uTempName =  (ipos != std::string::npos) ? uTempDir.substr(ipos+1) : uTempDir;
   req("_UPLOT_TEMP_DIR") = uTempName.c_str();

   // Save information stored in the hidden parameters because, after this
   // icon is edited, the request sent back to function "edited" does not
   // contain them.
   nameOrg_ = (const char*)req("_NAME_ORIGINAL") ? (const char*)req("_NAME_ORIGINAL") : (const char*)req("_NAME");
   // probably needs to save more hidden parameters here

   // If this is the first time that this icon is edited then create a 
   // temporary filename which points to the uPlot Temporary Directory.
   // The Desktop editor will use this temporary file.
   if ( !(const char*)req("_CONTENTS_ICON_EDITED") )
   {
      // Get full filename to be edited (temporary directory + filename)
      string fname = uPlotBase::tempDir() + name_.toStdString();

      // Parameter _NAME is the full filename without the Metview user directory
      string userDir = GetUserDirectory();   // Metview user directory
      std::size_t ipos = fname.find(userDir);
      ipos = (ipos != std::string::npos) ? ipos+userDir.size() : 0;
      req("_NAME") = fname.substr(ipos).c_str();

      // If this is a default icon then remove the _DEFAULT parameter.
      // A new clone icon will be created in the temporary directory
      // and the system should edit this icon. The problem here is that
      // if this parameter is not removed then the Desktop module will
      // edit the default icon stored at /System/Defaults.
      if ( (const char*)req("_DEFAULT") )
         req.unsetParam("_DEFAULT") ;

      // Create an icon file on disk, directory uPlot Temporary Directory.
      // Desktop editor will save the user changes in this file.
      Path pnewIcon(fname);
      pnewIcon.saveRequest(req);
   }

   // Ask GenApp to edit my request
   CallGenAppService(*this,&MvQLayerContentsIcon::edited,req);
}

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

   // Restore some hidden parameters that were saved in the function
   // "startEditor". Unfortunately, these parameters are not sent back
   // by the Desktop Editor
   newIconRequest("_NAME_ORIGINAL") = nameOrg_.c_str();
   newIconRequest ("_ID") = id_.toInt();
   newIconRequest ("_CONTENTS_ICON_EDITED") = id_.toInt();

   // Create a new drop request
   // Get the target Presentable (Page) id
   int ivoid;  // void variable
   MvRequest dropRequest("DROP");
   Presentable* pres = Root::Instance().FindSuperPage();
   dropRequest("DROP_ID") = pres->FindBranchIdByIconId(id_.toInt(),ivoid);
   dropRequest("_CONTENTS") = 1;

   dropRequest = dropRequest + newIconRequest;

   // Call myself to process the request
   std::ostringstream appName;
   appName << "uPlot" << (long int)getpid();
   MvApplication::callService ( appName.str().c_str(),dropRequest,0 );
}

void MvQLayerContentsIcon::deleteIcon()
{
   if( !canBeDeleted_ )
      return;

   // Get Presentable SuperPage
   Presentable* pres = Root::Instance().FindSuperPage();

   // Delete icon and rebuild the plot
   pres->RemoveIcon(id_.toInt());
}

void MvQLayerContentsIcon::saveIcon()
{
   if( !canBeSaved_ )
      return;

   // Get Presentable SuperPage
   Presentable* pres = Root::Instance().FindSuperPage();

   // Retrieve icon from the DataBase and update it on disk
   MvIcon mvIcon;
   MvIconDataBase& dataBase = pres->IconDataBase();
   if ( dataBase.FindIcon ( id_.toInt(), mvIcon ) )
   {
      // Update icon on disk
      MvRequest iconReq = mvIcon.Request();
      const char* cname = (const char*)iconReq("_NAME_ORIGINAL") ? (const char*)iconReq("_NAME_ORIGINAL") : (const char*)iconReq("_NAME");
      if ( !cname )
      {
         marslog(LOG_WARN,"Icon file not available on disk");
         return;
      }
      string fullPath = MakeUserPath(string(cname));

      // Remove all hiden parameters before saving the icon
      RemoveParameters(iconReq,"_");
      iconReq.save ( fullPath.c_str() );

   // Notify everyone
   //MvApplication::notifyIconModified(icon_.IconName(),icon_.IconClass());
   }
}

// This function assumes that:
// a) icons are located in the subdirectory /icons_mv5/
// b) File ObjectList stores the pixmap filenames's suffix as .icon
//
// This function should be updated after icons are moved to subdirectory /icons/
// and the pixmap filenames' suffix are updated to .svg or .xpm
string MvQLayerContentsIcon::getPixmapPath(const string& sclass)
{
   // Get the pixmap file name given the class name
   string fname = ObjectList::FindPlusChildren("object",sclass,"pixmap");
   if ( fname.empty() )
      return fname;

   // Get path and filename
   std::size_t pos = fname.find_last_of("/\\");
   string path = fname.substr(0,pos);
   string filename = fname.substr(pos+1);

   // Remove suffix .icon from the filename
   pos = filename.rfind(".icon");
   if( pos != string::npos )
      filename = filename.substr(0,pos);

   // Replace subdirectoy /icons by /icons_mv5
   path += "_mv5/";

   // Build the pixmap filename. Try to find the filename suffix.
   string fullName = path + filename + ".svg";
   if ( FileCanBeOpened(fullName.c_str(), "r") )
      return fullName;
   else
   {
      fullName = path + filename + ".xpm";
      if( FileCanBeOpened(fullName.c_str(), "r") )
         return fullName;
   }

   return string("");  // empty string
}
