Add auto-config

Change-Id: I3743cfa1a08150d2953ee904ec31dc83642ec063
diff --git a/make-deps.sh b/make-deps.sh
index c042045..6a773ab 100755
--- a/make-deps.sh
+++ b/make-deps.sh
@@ -10,12 +10,13 @@
 path="$(pwd)"
 
 pushd build
-wget https://github.com/sparkle-project/Sparkle/releases/download/1.14.0/Sparkle-1.14.0.tar.bz2
-mkdir Sparkle-1.14 || true
-pushd Sparkle-1.14
-tar xf ../Sparkle-1.14.0.tar.bz2
+# wget https://github.com/sparkle-project/Sparkle/releases/download/1.14.0/Sparkle-1.14.0.tar.bz2
+wget https://github.com/sparkle-project/Sparkle/releases/download/1.16.0/Sparkle-1.16.0.tar.bz2
+mkdir Sparkle-1.16 || true
+pushd Sparkle-1.16
+tar xf ../Sparkle-1.16.0.tar.bz2
 popd
-mv Sparkle-1.14/Sparkle.framework .
+mv Sparkle-1.16/Sparkle.framework .
 popd
 
 #######################################
diff --git a/src/main.cpp b/src/main.cpp
index 4c718a1..d03f0cd 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2016, Regents of the University of California,
+ * Copyright (c) 2013-2017, Regents of the University of California,
  *
  * This file is part of NFD Control Center.  See AUTHORS.md for complete list of NFD
  * authors and contributors.
@@ -18,9 +18,9 @@
  */
 
 #include <QtQml/QQmlApplicationEngine>
+#include <QtQml/QQmlContext>
 #include <QtWidgets/QApplication>
 #include <QtWidgets/QPushButton>
-#include <QtQml/QQmlContext>
 
 #include "forwarder-status.hpp"
 #include "fib-status.hpp"
diff --git a/src/main.qml b/src/main.qml
index 6eb7b18..7ef1990 100644
--- a/src/main.qml
+++ b/src/main.qml
@@ -7,7 +7,7 @@
     visible: false
     id: window
     title: "NFD Control Center"
-    minimumWidth: 600
+    minimumWidth: 750
     minimumHeight: 400
 
     TabView {
@@ -44,19 +44,11 @@
                             text: "Automatically start NFD Control Center on login"
                         }
                         CheckBox {
-                            id: discoverHub
-                            text: "Discover nearest NDN hub"
-                            onCheckedChanged: {
-                                if (this.checked) {
-                                    trayModel.autoConfig()
-                                }
-                            }
+                            id: autoConfig
+                            text: "Automatically start NDN auto configuration"
+                            checked: trayModel.isAutoConfigEnabled()
+                            onCheckedChanged: trayModel.startStopAutoConfig(this.checked)
                         }
-                        // CheckBox {
-                        //     id: checkUpdate
-                        //     enabled: false
-                        //     text: "Check for software updates"
-                        // }
                     }
                 }
                 GroupBox {
@@ -98,7 +90,7 @@
                     anchors.rightMargin: 20
                     anchors.bottomMargin: 20
 
-                    onClicked: trayModel.startStopNfd()
+                    onClicked: trayModel.startStopNfd(autoConfig.checked)
                 }
             }
         }
@@ -150,6 +142,19 @@
             }
         }
         Tab {
+            title: "Auto-config status"
+            TextArea {
+                id: autoConfigText
+                anchors.fill: parent
+                anchors.topMargin: 20
+                anchors.bottomMargin: 20
+                anchors.leftMargin: 20
+                anchors.rightMargin: 20
+                readOnly: true
+                text: acText
+            }
+        }
+        Tab {
             title: "Security"
             Column {
                 spacing: 2
diff --git a/src/tray-menu.cpp b/src/tray-menu.cpp
index 3d3afe7..28b6d36 100644
--- a/src/tray-menu.cpp
+++ b/src/tray-menu.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2016, Regents of the University of California.
+ * Copyright (c) 2013-2017, Regents of the University of California.
  *
  * This file is part of NFD Control Center.  See AUTHORS.md for complete list of NFD
  * authors and contributors.
@@ -37,7 +37,6 @@
 
 #ifdef WAF
 #include "tray-menu.moc"
-// #include "tray-menu.cpp.moc"
 #endif
 
 namespace ndn {
@@ -54,8 +53,11 @@
   , m_entryQuit(new QAction("Quit", m_menu))
   , m_keyViewerDialog(new ncc::KeyViewerDialog)
   , m_face(face)
+  , m_acProc(new QProcess())
+  , m_settings(new QSettings())
 {
   connect(m_entryPref, SIGNAL(triggered()), this, SIGNAL(showApp()));
+  connect(this, SIGNAL(showApp()), this, SLOT(showPref()));
   connect(m_entrySec, SIGNAL(triggered()), m_keyViewerDialog, SLOT(present()));
   connect(m_entryQuit, SIGNAL(triggered()), this, SLOT(quitApp()));
 
@@ -67,9 +69,8 @@
           Qt::QueuedConnection);
 
   m_context->setContextProperty("startStopButtonText", QVariant::fromValue(QString("Start NFD")));
+  m_context->setContextProperty("acText", QVariant::fromValue(QString("")));
 
-  // m_menu->addAction(start);
-  // m_menu->addAction(stop);
   m_menu->addAction(m_entryPref);
   m_menu->addAction(m_entrySec);
 #ifdef OSX_BUILD
@@ -82,19 +83,108 @@
           this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
   m_tray->setIcon(QIcon(DISCONNECT_ICON));
   m_tray->show();
+  if (isAutoConfigEnabled()) {
+    stopAutoConfig(); // Make sure no more than one auto-config process exist
+    QTimer* mTimer = new QTimer(this);
+    mTimer->setSingleShot(true);
+    connect(mTimer, SIGNAL(timeout()), SLOT(startAutoConfig()));
+    mTimer->start(2000);
+  }
 }
 
 TrayMenu::~TrayMenu()
 {
 }
 
-Q_INVOKABLE void
-TrayMenu::autoConfig()
+void
+TrayMenu::appendMsg(QString &target, QString source)
 {
-  std::cout << "auto config" << std::endl;
+  int maxLine = 100; // Max line that will show in auto-config status tab view
+  if (target.count(QString("\n")) > maxLine) { // Only when target QString has more line than maxLine, it needs remove line
+    int end = target.indexOf(QString("\n"));
+    target.remove(0, end + 1); // Remove the first line of target
+  }
+  target.append(source);
+}
+
+void
+TrayMenu::showPref()
+{
+  m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg)); // Update auto-config status tab view
+}
+
+void
+TrayMenu::processOutput()
+{
+  std::string msg = m_acProc->readAllStandardOutput().toStdString();
+  if (msg != "") {
+    appendMsg(m_autoConfigMsg, QString::fromStdString(msg));
+  }
+  msg = m_acProc->readAllStandardError().toStdString();
+  if (msg != "") {
+    appendMsg(m_autoConfigMsg, QString::fromStdString(msg));
+  }
+  m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
+}
+
+Q_INVOKABLE bool
+TrayMenu::isAutoConfigEnabled()
+{
+  bool sAutoConfig = m_settings.value("main/auto-config", QVariant(false)).toBool();
+  return sAutoConfig;
+}
+
+void
+TrayMenu::startAutoConfig()
+{
+  if (m_isNfdRunning) {
+    appendMsg(m_autoConfigMsg, QString("NDN auto configuration will start...\n"));
+    connect(m_acProc, SIGNAL(readyReadStandardOutput()), this, SLOT(processOutput()));
+    connect(m_acProc, SIGNAL(readyReadStandardError()), this, SLOT(processOutput()));
+    m_acProc->start((QCoreApplication::applicationDirPath().toStdString() + "/../Platform/ndn-autoconfig").c_str(),
+                      QStringList()
+                        << "--daemon");
+  }
+}
+
+void
+TrayMenu::stopAutoConfig()
+{
+#ifdef OSX_BUILD
   QProcess* proc = new QProcess();
   connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
-  // proc->start(NFD_AUTOCONFIG_COMMAND);
+  proc->startDetached("killall", QStringList() << "ndn-autoconfig");
+#endif
+}
+
+Q_INVOKABLE void
+TrayMenu::startStopAutoConfig(bool autoConfig)
+{
+  if (m_isNfdRunning) {
+    if (autoConfig) {
+      stopAutoConfig(); // Make sure no more than one auto-config process exist
+      QTimer* mTimer = new QTimer(this);
+      mTimer->setSingleShot(true);
+      connect(mTimer, SIGNAL(timeout()), SLOT(startAutoConfig()));
+      mTimer->start(2000);
+      m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
+      m_settings.setValue("main/auto-config", true);
+    }
+    else {
+      stopAutoConfig();
+      appendMsg(m_autoConfigMsg, QString("NDN auto configuration will be stopped!\n"));
+      m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
+      m_settings.setValue("main/auto-config", false);
+    }
+  }
+  else { // No need to start or stop auto-config when NFD is not running, but it needs to update settings
+    if (autoConfig) {
+      m_settings.setValue("main/auto-config", true);
+    }
+    else {
+      m_settings.setValue("main/auto-config", false);
+    }
+  }
 }
 
 void
@@ -118,13 +208,24 @@
 }
 
 Q_INVOKABLE void
-TrayMenu::startStopNfd()
+TrayMenu::startStopNfd(bool autoConfig)
 {
   if (!m_isNfdRunning) {
     startNfd();
+    if (autoConfig) {
+      stopAutoConfig(); // Make sure no more than one auto-config process exist
+      QTimer* mTimer = new QTimer(this);
+      mTimer->setSingleShot(true);
+      connect(mTimer, SIGNAL(timeout()), SLOT(startAutoConfig()));
+      mTimer->start(2000);
+      m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
+    }
   }
   else {
     stopNfd();
+    stopAutoConfig();
+    appendMsg(m_autoConfigMsg, QString("NDN auto configuration will be stopped!\n"));
+    m_context->setContextProperty("acText", QVariant::fromValue(m_autoConfigMsg));
   }
 }
 
@@ -138,15 +239,17 @@
                       QStringList()
                         << "--config"
                         << (QCoreApplication::applicationDirPath().toStdString() + "/../etc/ndn/nfd.conf").c_str());
-// #endif
-//   QProcess * proc = new QProcess();
-//   connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
-// #ifdef __linux__
-//   proc->start("gksudo", QStringList() << NFD_START_COMMAND);
-// #else
-//   proc->start("osascript", QStringList()
-//               << "-e"
-//               << "do shell script \"" NFD_START_COMMAND "\" with administrator privileges");
+
+
+  // #endif
+  //   QProcess * proc = new QProcess();
+  //   connect(proc, SIGNAL(finished(int)), proc, SLOT(deleteLater()));
+  // #ifdef __linux__
+  //   proc->start("gksudo", QStringList() << NFD_START_COMMAND);
+  // #else
+  //   proc->start("osascript", QStringList()
+  //               << "-e"
+  //               << "do shell script \"" NFD_START_COMMAND "\" with administrator privileges");
 #endif
 }
 
@@ -175,9 +278,6 @@
   connect(addNewRoute,SIGNAL(finished(int)), addNewRoute, SLOT(deleteLater()));
   addNewRoute->start("bash", QStringList() << "-c" << cmd);
   std::cout << "Done" << std::endl;
-
-
-//   QProcess * proc = new QProcess();
 }
 
 void
@@ -192,7 +292,6 @@
 
 }
 
-
 void
 TrayMenu::updateNfdActivityIcon(bool isActive)
 {
diff --git a/src/tray-menu.hpp b/src/tray-menu.hpp
index cda18b8..3c7b0f0 100644
--- a/src/tray-menu.hpp
+++ b/src/tray-menu.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2013-2014, Regents of the University of California,
+ * Copyright (c) 2013-2017, Regents of the University of California,
  *
  * This file is part of NFD Control Center.  See AUTHORS.md for complete list of NFD
  * authors and contributors.
@@ -25,10 +25,15 @@
 #include <QtCore/QObject>
 #include <QtCore/QProcess>
 #include <QtCore/QCoreApplication>
+#include <QtCore/QSettings>
 
+#include <QtWidgets/QWidget>
 #include <QtWidgets/QSystemTrayIcon>
 #include <QtWidgets/QAction>
 #include <QtWidgets/QMenu>
+#include <QtWidgets/QVBoxLayout>
+#include <QtWidgets/QPlainTextEdit>
+#include <QtWidgets/QPushButton>
 
 #include <QtQml/QQmlContext>
 
@@ -55,11 +60,14 @@
 
   ~TrayMenu();
 
-  Q_INVOKABLE void
-  autoConfig();
+  Q_INVOKABLE bool
+  isAutoConfigEnabled();
 
   Q_INVOKABLE void
-  startStopNfd();
+  startStopAutoConfig(bool autoConfig);
+
+  Q_INVOKABLE void
+  startStopNfd(bool autoConfig);
 
   Q_INVOKABLE void
   addDeleteRoute();
@@ -79,6 +87,12 @@
   iconActivated(QSystemTrayIcon::ActivationReason reason);
 
   void
+  startAutoConfig();
+
+  void
+  stopAutoConfig();
+
+  void
   startNfd();
 
   void
@@ -90,6 +104,15 @@
   void
   enableCli();
 
+  void
+  processOutput();
+
+  void
+  showPref();
+
+  static void
+  appendMsg(QString &target, QString source);
+
 private:
   QQmlContext* m_context;
   bool m_isNfdRunning;
@@ -97,6 +120,9 @@
   QMenu* m_menu;
   QAction* m_entryPref;
   QAction* m_entrySec;
+  QProcess* m_acProc;
+  QString m_autoConfigMsg;
+  QSettings m_settings;
 #ifdef OSX_BUILD
   QAction* m_entryEnableCli;
 #endif