/***************************************************************************
**
**  This file is part of QGpGuiTools.
**
**  This library is free software; you can redistribute it and/or
**  modify it under the terms of the GNU Lesser General Public
**  License as published by the Free Software Foundation; either
**  version 2.1 of the License, or (at your option) any later version.
**
**  This file is distributed in the hope that it will be useful, but WITHOUT
**  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
**  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
**  License for more details.
**
**  You should have received a copy of the GNU Lesser General Public
**  License along with this library; if not, write to the Free Software
**  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2006-11-03
**  Copyright: 2006-2019
**    Marc Wathelet
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include <QtNetwork>

#include "UpdateIcon.h"
#include "ConnectionParam.h"
#include "Settings.h"
#include "HttpAccess.h"

namespace QGpGuiTools {

  /*!
    \class UpdateIcon UpdateIcon.h
    \brief Brief description of class still missing

    Full description of class still missing
  */

  /*!
    Checking of new release availability starts automatically after returning
    to the event loop. Name and plugin list must be setup right after constructor.
  */
  UpdateIcon::UpdateIcon(QWidget * parent)
      : QLabel(parent)
  {
    TRACE;
    if(HttpAccess::isAvailable()) {
      _access=new HttpAccess("http://www.geopsy.org/access_testing.txt", this);
      connect(_access, SIGNAL(ready()), this, SLOT(checkAvailability()));
      connect(_access, SIGNAL(finished(bool)), this, SLOT(sent(bool)));

      _state=Connecting;
      setPixmap(QPixmap(":update_unavailable.png"));
      setToolTip(tr("Live update: connecting ..."));
    } else {
      _access=nullptr;
      _state=NotConnected;
      setPixmap(QPixmap(":update_error.png"));
      setToolTip(tr("No connectivity"));
    }

    QAction * a;

    a=new QAction(tr("&Download"), this);
    a->setStatusTip(tr("Open your browser at download page"));
    connect(a, SIGNAL(triggered()), this, SLOT(download()));
    addAction(a);

    setContextMenuPolicy(Qt::ActionsContextMenu);
  }

  /*!
    Description of destructor still missing
  */
  UpdateIcon::~UpdateIcon()
  {
    TRACE;
    clear();
  }

  /*!
    Adds one plugin. \n can have an absolute path and library suffix and prefix.
    Everything is stripped in a platform-independent way before adding it.
  */
  void UpdateIcon::addPlugin(const QString& n)
  {
    TRACE;
    QFileInfo fi(n);
    QString ns=fi.fileName();  // Removes path name
#if defined(Q_OS_MAC)
    if(ns.startsWith("lib") && ns.endsWith(".dylib")) {
      ns=ns.mid(3, ns.count()-9);
    }
#elif defined(Q_OS_WIN)
    QRegExp r("[0-9]{1,}\\.dll$");
    int i=r.indexIn(ns);
    if(i>0) {
      ns=ns.left(i);
    }
#else
    if(ns.startsWith("lib") && ns.endsWith(".so")) {
      ns=ns.mid(3, ns.count()-6);
    }
#endif
    _plugins.append(ns);
  }

  /*!
    Add several plugins using addPlugin(const QString& n).
  */
  void UpdateIcon::addPlugins(const QStringList& nl)
  {
    TRACE;
    for(QStringList::const_iterator it=nl.begin(); it!=nl.end(); it++) {
      addPlugin(*it);
    }
  }

  void UpdateIcon::download()
  {
    TRACE;
    QUrl doc("http://www.geopsy.org/download.php?branch="+_versionType);
    QDesktopServices::openUrl(doc);
  }

  void UpdateIcon::checkAvailability()
  {
    TRACE;
    QSettings& reg=CoreApplication::instance()->settings();
    reg.beginGroup("New release");
    QDateTime t=reg.value("lastChecked", QDate(2000,1,1)).toDateTime();
    QString lastState=reg.value("lastState", "NotConnected").toString();
    if(t.secsTo(QDateTime::currentDateTime())>86400 || lastState=="NotConnected") {
      // A random number is generated as the request id
      // 'a' is the application or object list. It must be the main application first, then
      // eventually a list of plugins separated by coma.
      QString app=_name;
      if(!_plugins.isEmpty()) {
        app+=","+_plugins.join(",");
      }
      QString request=QString("http://www.geopsy.org/last_release/index.php?p=%1&b=%2&a=%3&u=%4&r=%5")
          .arg(platform())
          .arg(_versionType)
          .arg(app)
          .arg(CoreApplication::userId())
          .arg(rand());
      _access->get(request);
      APP_LOG(100, tr("Sending last release request:\n%1\n").arg(request))
    } else {
      if(lastState=="NewRelease") {
        _state=NewRelease;
      } else {
        _state=Connected;
      }
      showState();
    }
  }

  void UpdateIcon::sent(bool ok)
  {
    TRACE;
    QSettings& reg=CoreApplication::instance()->settings();
    reg.beginGroup("New release");
    reg.setValue("lastChecked", QDateTime::currentDateTime());
    if(ok) {
      QString info=_access->receivedData();
      APP_LOG(100, info)
      QStringList packages=info.split(" ", QString::SkipEmptyParts);
      QMap<QString, Version> packageMap;
      for(int i=packages.count()-1; i>0; i-=2) {
        packageMap.insert(packages.at(i-1), packages.at(i));
      }
      QList<PackageInfo> * list=PackageInfo::list();
      _state=Connected;
      for(QList<PackageInfo>::iterator it=list->begin(); it!=list->end(); it++) {
        QMap<QString, Version>::iterator itMap=packageMap.find(it->package());
        if(itMap!=packageMap.end()) {
          if(Version(it->version())<itMap.value()) {
            _state=NewRelease;
            break;
          }
        }
      }
      if(_state==NewRelease) {
        // Do not display message box more than once
        if(reg.value("lastState").toString()!="NewRelease") {
          reg.setValue("lastState", "NewRelease");
          if(Message::information(MSG_ID, tr("New release ready"),
                                  tr("A new release is now available for download at http://www.geopsy.org/download.php?branch=%1.").arg(_versionType),
                                  tr("Download now"), Message::ignore())==Message::Answer0) {
            download();
          }
        }
      } else {
        reg.setValue("lastState", "Connected");
      }
    } else {
      _state=NotConnected;
      reg.setValue("lastState", "NotConnected");
    }
    showState();
  }

  /*!
    Modify image and tool tip according to state
  */
  void UpdateIcon::showState()
  {
    TRACE;
    switch (_state) {
    case Connecting:
    case NotConnected:
      setPixmap(QPixmap(":update_error.png"));
      setToolTip(tr("No connectivity"));
      break;
    case Connected:
      setToolTip(tr("You are running the latest release."));
      break;
    case NewRelease:
      setPixmap(QPixmap(":update_available.png"));
      setToolTip(tr("A new release is now available for download at http://www.geopsy.org/download.php?branch=%1.")
                 .arg(_versionType));
      break;
    }
  }


  /*!
    Returns platform codes compatible with download website
  */
  QString UpdateIcon::platform()
  {
#if defined(Q_OS_WIN)
    return "win64";
#elif defined(Q_OS_MAC)
    QString version=QSysInfo::productVersion();
    bool ok;
    int major=version.section('.', 1, 1).toInt(&ok);
    if(ok) {
      switch(major) {
      case 6: return "mac-snowleopard";
      case 7: return "mac-lion";
      case 8: return "mac-mountainlion";
      case 9: return "mac-mavericks";
      case 10: return "mac-yosemite";
      case 11: return "mac-elcapitan";
      case 12: return "mac-sierra";
      case 13: return "mac-highsierra";
      case 14: return "mac-mojave";
      default: return "mac-unknown";
      }
    } else {
      return "mac-unknown";
    }
#else
    return "src";
#endif
  }

} // namespace QGpGuiTools
