Allow changing alias
diff --git a/src/addcontactpanel.cpp b/src/addcontactpanel.cpp
index 9d332a7..80675ea 100644
--- a/src/addcontactpanel.cpp
+++ b/src/addcontactpanel.cpp
@@ -36,8 +36,10 @@
           this, SLOT(onCancelClicked()));
   connect(ui->searchButton, SIGNAL(clicked()),
           this, SLOT(onSearchClicked()));
-  connect(&*m_contactManager, SIGNAL(contactFetched(const EndorseCertificate&>)),
-          this, SLOT(selfEndorseCertificateFetched(const EndorseCertificate&>)));
+  connect(ui->addButton, SIGNAL(clicked()),
+          this, SLOT(onAddClicked()));
+  connect(&*m_contactManager, SIGNAL(contactFetched(const EndorseCertificate&)),
+          this, SLOT(selfEndorseCertificateFetched(const EndorseCertificate&)));
   connect(&*m_contactManager, SIGNAL(contactFetchFailed(const ndn::Name&)),
           this, SLOT(selfEndorseCertificateFetchFailed(const ndn::Name&)));
 }
@@ -55,6 +57,9 @@
 void
 AddContactPanel::onSearchClicked()
 {
+  ui->infoView->clear();
+  for(int i = ui->infoView->rowCount() - 1; i >= 0 ; i--)
+    ui->infoView->removeRow(i);
   QString inputIdentity = ui->contactInput->text();
   m_searchIdentity = Name(inputIdentity.toUtf8().constData());
 
@@ -64,12 +69,30 @@
 void
 AddContactPanel::onAddClicked()
 {
+  ContactItem contactItem(*m_currentEndorseCertificate);
+  m_contactManager->getContactStorage()->addNormalContact(contactItem);
+  emit newContactAdded();
+  this->close();
 }
 
 void 
 AddContactPanel::selfEndorseCertificateFetched(const EndorseCertificate& endorseCertificate)
 {
-  _LOG_DEBUG("CALLED");
+  m_currentEndorseCertificate = Ptr<EndorseCertificate>(new EndorseCertificate(endorseCertificate));
+  const Profile& profile = endorseCertificate.getProfileData()->getProfile();
+  ui->infoView->setColumnCount(3);
+  Profile::const_iterator it = profile.begin();
+  int rowCount = 0;
+  for(; it != profile.end(); it++)
+  {
+    ui->infoView->insertRow(rowCount);  
+    QTableWidgetItem *type = new QTableWidgetItem(QString::fromUtf8(it->first.c_str()));
+    ui->infoView->setItem(rowCount, 0, type);
+    string valueString(it->second.buf(), it->second.size());
+    QTableWidgetItem *value = new QTableWidgetItem(QString::fromUtf8(valueString.c_str()));
+    ui->infoView->setItem(rowCount, 1, value);
+    rowCount++;
+  }
 }
 
 void
diff --git a/src/addcontactpanel.h b/src/addcontactpanel.h
index f6776c0..1536464 100644
--- a/src/addcontactpanel.h
+++ b/src/addcontactpanel.h
@@ -17,6 +17,7 @@
 
 #ifndef Q_MOC_RUN
 #include "endorse-certificate.h"
+#include "profile.h"
 #include "contact-manager.h"
 #endif
 
@@ -54,11 +55,16 @@
   void
   selfEndorseCertificateFetchFailed(const ndn::Name& identity);
 
+signals:
+  void
+  newContactAdded();
+
 private:
   Ui::AddContactPanel *ui;
   ndn::Name m_searchIdentity;
   ndn::Ptr<ContactManager> m_contactManager;
   WarningDialog* m_warningDialog;
+  ndn::Ptr<EndorseCertificate> m_currentEndorseCertificate;
 };
 
 #endif // ADDCONTACTPANEL_H
diff --git a/src/addcontactpanel.ui b/src/addcontactpanel.ui
index 99fd5e9..7974593 100644
--- a/src/addcontactpanel.ui
+++ b/src/addcontactpanel.ui
@@ -60,7 +60,11 @@
      </layout>
     </item>
     <item>
-     <widget class="QTableWidget" name="infoView"/>
+     <widget class="QTableWidget" name="infoView">
+      <attribute name="horizontalHeaderStretchLastSection">
+       <bool>true</bool>
+      </attribute>
+     </widget>
     </item>
     <item>
      <layout class="QHBoxLayout" name="buttonLayout">
diff --git a/src/contact-item.cpp b/src/contact-item.cpp
index 08f4fa6..c14b328 100644
--- a/src/contact-item.cpp
+++ b/src/contact-item.cpp
@@ -13,10 +13,14 @@
 
 #include <ndn.cxx/fields/signature-sha256-with-rsa.h>
 
+#include "logging.h"
+
 using namespace std;
 using namespace ndn;
 using namespace ndn::security;
 
+INIT_LOGGER("ContactItem");
+
 ContactItem::ContactItem(const EndorseCertificate& selfEndorseCertificate,
                          const string& alias)
   : m_selfEndorseCertificate(selfEndorseCertificate)
@@ -24,8 +28,31 @@
   Name endorsedkeyName = selfEndorseCertificate.getPublicKeyName();
   Ptr<const signature::Sha256WithRsa> endorseSig = boost::dynamic_pointer_cast<const signature::Sha256WithRsa>(selfEndorseCertificate.getSignature());
   const Name& signingKeyName = endorseSig->getKeyLocator().getKeyName();
+  
+  int i = 0;
+  int j = -1;
+  string keyString("KEY");
+  string idString("ID-CERT");
+  for(; i < signingKeyName.size(); i++)
+    {
+      if(keyString == signingKeyName.get(i).toUri())
+        j = i;
+      if(idString == signingKeyName.get(i).toUri())
+        break;
+    }
 
-  if(endorsedkeyName != signingKeyName)
+  if(i >= signingKeyName.size() || j < 0)
+    throw LnException("Wrong name!");
+
+  Name subName = signingKeyName.getSubName(0, j);
+  subName.append(signingKeyName.getSubName(j+1, i-j-1));
+
+
+
+  // _LOG_DEBUG("endorsedkeyName " << endorsedkeyName.toUri());
+  // _LOG_DEBUG("subKeyName " << subName.toUri());
+
+  if(endorsedkeyName != subName)
     throw LnException("not a self-claimed");
 
   m_namespace = endorsedkeyName.getSubName(0, endorsedkeyName.size() - 1);
diff --git a/src/contact-manager.cpp b/src/contact-manager.cpp
index 01168a0..9b7d7a3 100644
--- a/src/contact-manager.cpp
+++ b/src/contact-manager.cpp
@@ -157,6 +157,20 @@
     }
 }
 
+vector<Ptr<ContactItem> >
+ContactManager::getContactItemList()
+{
+  vector<Ptr<ContactItem> > result;
+  
+  vector<Ptr<ContactItem> > ncList = m_contactStorage->getAllNormalContacts();
+  vector<Ptr<TrustedContact> > tcList = m_contactStorage->getAllTrustedContacts();
+
+  result.insert(result.end(), tcList.begin(), tcList.end());
+  result.insert(result.end(), ncList.begin(), ncList.end());
+
+  return result;
+}
+
 Ptr<EndorseCertificate>
 ContactManager::getSignedSelfEndorseCertificate(const Name& identity,
                                                 const Profile& profile)
@@ -203,6 +217,11 @@
 
   if(security::PolicyManager::verifySignature(*plainData, ksk))
     {
+      // Profile profile = selfEndorseCertificate->getProfileData()->getProfile();
+      // Profile::const_iterator it = profile.getEntries().begin();
+      // it++;
+      // _LOG_DEBUG("Entry Size: " << it->first);
+
       emit contactFetched (*selfEndorseCertificate); 
     }
   else
diff --git a/src/contact-manager.h b/src/contact-manager.h
index 42fd847..666cf9b 100644
--- a/src/contact-manager.h
+++ b/src/contact-manager.h
@@ -17,6 +17,7 @@
 #include "contact-storage.h"
 #include "dns-storage.h"
 #include "endorse-certificate.h"
+#include "profile.h"
 #include <ndn.cxx/wrapper/wrapper.h>
 #endif
 
@@ -38,6 +39,9 @@
   void
   updateProfileData(const ndn::Name& identity);
 
+  std::vector<ndn::Ptr<ContactItem> >
+  getContactItemList();
+
   inline ndn::Ptr<ContactStorage>
   getContactStorage()
   { return m_contactStorage; }
@@ -75,7 +79,7 @@
 
 signals:
   void 
-  contactFetched(const EndorseCertificate& selfEndorseCertificate);
+  contactFetched(const EndorseCertificate& endorseCertificate);
   
   void
   contactFetchFailed(const ndn::Name& identity);
diff --git a/src/contact-storage.cpp b/src/contact-storage.cpp
index 5c6dc31..24c322e 100644
--- a/src/contact-storage.cpp
+++ b/src/contact-storage.cpp
@@ -200,14 +200,16 @@
 Ptr<Profile>
 ContactStorage::getSelfProfile(const Name& identity)
 {
+  _LOG_DEBUG("getSelfProfile " << identity.toUri());
   sqlite3_stmt *stmt;
   Ptr<Profile> profile = Ptr<Profile>(new Profile(identity));
   
-  sqlite3_prepare_v2(m_db, "SELECT profile_type, profile_value FROM SelfProfile WHERE profile_identity=", -1, &stmt, 0);
+  sqlite3_prepare_v2(m_db, "SELECT profile_type, profile_value FROM SelfProfile WHERE profile_identity=?", -1, &stmt, 0);
   sqlite3_bind_text(stmt, 1, identity.toUri().c_str(), identity.toUri().size(), SQLITE_TRANSIENT);
-  
-  while( sqlite3_step (stmt) == SQLITE_ROW)
+
+  while(sqlite3_step (stmt) == SQLITE_ROW)
     {
+      _LOG_DEBUG("entry");
       string profileType(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0));
       Blob profileValue(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1)), sqlite3_column_bytes (stmt, 1));
 
@@ -260,9 +262,35 @@
   sqlite3_bind_text(stmt, 3, selfCertificateBlob->buf(), selfCertificateBlob->size(), SQLITE_TRANSIENT);
 
   int res = sqlite3_step (stmt);
+  // _LOG_DEBUG("res " << res);
   sqlite3_finalize (stmt);
 }
 
+void 
+ContactStorage::updateAlias(const ndn::Name& identity, std::string alias)
+{
+  if(doesNormalContactExist(identity))
+    {
+      sqlite3_stmt *stmt;
+      sqlite3_prepare_v2 (m_db, "UPDATE NormalContact SET contact_alias=? WHERE contact_namespace=?", -1, &stmt, 0);
+      sqlite3_bind_text(stmt, 1, alias.c_str(), alias.size(), SQLITE_TRANSIENT);
+      sqlite3_bind_text(stmt, 2, identity.toUri().c_str(),  identity.toUri().size (), SQLITE_TRANSIENT);
+      int res = sqlite3_step (stmt);
+      sqlite3_finalize (stmt);
+      return;
+    }
+  if(doesTrustedContactExist(identity))
+    {
+      sqlite3_stmt *stmt;
+      sqlite3_prepare_v2 (m_db, "UPDATE TrustedContact SET contact_alias=? WHERE contact_namespace=?", -1, &stmt, 0);
+      sqlite3_bind_text(stmt, 1, alias.c_str(), alias.size(), SQLITE_TRANSIENT);
+      sqlite3_bind_text(stmt, 2, identity.toUri().c_str(),  identity.toUri().size (), SQLITE_TRANSIENT);
+      int res = sqlite3_step (stmt);
+      sqlite3_finalize (stmt);
+      return;
+    }
+}
+
 bool
 ContactStorage::doesContactExist(const Name& name, bool normal)
 {
diff --git a/src/contact-storage.h b/src/contact-storage.h
index 3275c40..e08790e 100644
--- a/src/contact-storage.h
+++ b/src/contact-storage.h
@@ -40,6 +40,9 @@
   void
   addNormalContact(const ContactItem& contactItem);
 
+  void 
+  updateAlias(const ndn::Name& identity, std::string alias);
+
   std::vector<ndn::Ptr<TrustedContact> >
   getAllTrustedContacts() const;
 
diff --git a/src/contactpanel.cpp b/src/contactpanel.cpp
index abfbb08..5128105 100644
--- a/src/contactpanel.cpp
+++ b/src/contactpanel.cpp
@@ -25,6 +25,7 @@
 
 namespace fs = boost::filesystem;
 using namespace ndn;
+using namespace std;
 
 INIT_LOGGER("ContactPanel");
 
@@ -34,6 +35,9 @@
     , m_contactManager(contactManager)
     , m_contactListModel(new QStringListModel)
     , m_addContactPanel(new AddContactPanel(contactManager))
+    , m_setAliasDialog(new SetAliasDialog(contactManager))
+    , m_menuInvite(new QAction("&Invite", this))
+    , m_menuAlias(new QAction("&Set Alias", this))
 {
   
     ui->setupUi(this);
@@ -46,21 +50,28 @@
 
     m_profileEditor = new ProfileEditor(m_contactManager);
 
-    QStringList contactNameList;
-    contactNameList << "Alex" << "Wentao" << "Yingdi";
-
-    m_contactListModel->setStringList(contactNameList);
+    refreshContactList();
     ui->ContactList->setModel(m_contactListModel);
 
     QItemSelectionModel* selectionModel = ui->ContactList->selectionModel();
 
     connect(selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
 	    this, SLOT(updateSelection(const QItemSelection &, const QItemSelection &)));
+    connect(ui->ContactList, SIGNAL(customContextMenuRequested(const QPoint&)),
+            this, SLOT(showContextMenu(const QPoint&)));
     connect(ui->EditProfileButton, SIGNAL(clicked()), 
             this, SLOT(openProfileEditor()));
 
     connect(ui->AddContactButton, SIGNAL(clicked()),
             this, SLOT(openAddContactPanel()));
+
+    connect(m_addContactPanel, SIGNAL(newContactAdded()),
+            this, SLOT(refreshContactList()));
+    connect(m_setAliasDialog, SIGNAL(aliasChanged()),
+            this, SLOT(refreshContactList()));
+
+
+
 }
 
 ContactPanel::~ContactPanel()
@@ -69,6 +80,8 @@
     delete m_contactListModel;
     delete m_profileEditor;
     delete m_addContactPanel;
+
+    delete m_menuInvite;
 }
 
 void
@@ -77,7 +90,25 @@
 {
   QModelIndexList items = selected.indexes();
   QString text = m_contactListModel->data(items.first(), Qt::DisplayRole).toString();
-  ui->NameData->setText(text);
+  string alias = text.toUtf8().constData();
+
+  m_currentSelectedContact = alias;
+
+  int i = 0;
+  for(; i < m_contactList.size(); i++)
+    {
+      if(alias == m_contactList[i]->getAlias())
+        break;
+    }
+  
+  QString name = QString::fromUtf8(m_contactList[i]->getName().c_str());
+  QString institution = QString::fromUtf8(m_contactList[i]->getInstitution().c_str());
+  QString nameSpace = QString::fromUtf8(m_contactList[i]->getNameSpace().toUri().c_str());
+  ui->NameData->setText(name);
+  ui->NameSpaceData->setText(nameSpace);
+  ui->InstitutionData->setText(institution);
+  
+  // _LOG_DEBUG("current Alias: " << m_currentSelectedContact);
 }
 
 void
@@ -88,6 +119,36 @@
 ContactPanel::openAddContactPanel()
 { m_addContactPanel->show(); }
 
+void
+ContactPanel::refreshContactList()
+{
+  m_contactList = m_contactManager->getContactItemList();
+  QStringList contactNameList;
+  for(int i = 0; i < m_contactList.size(); i++)
+    contactNameList << QString::fromUtf8(m_contactList[i]->getAlias().c_str());
+
+  m_contactListModel->setStringList(contactNameList);
+}
+
+void
+ContactPanel::showContextMenu(const QPoint& pos)
+{
+  QMenu menu(ui->ContactList);
+  menu.addAction(m_menuInvite);
+  menu.addAction(m_menuAlias);
+  connect(m_menuAlias, SIGNAL(triggered()),
+          this, SLOT(openSetAliasDialog()));
+  menu.exec(ui->ContactList->mapToGlobal(pos));
+
+}
+
+void
+ContactPanel::openSetAliasDialog()
+{
+  m_setAliasDialog->setTargetIdentity(m_currentSelectedContact);
+  m_setAliasDialog->show();
+}
+
 #if WAF
 #include "contactpanel.moc"
 #include "contactpanel.cpp.moc"
diff --git a/src/contactpanel.h b/src/contactpanel.h
index 5e20ee5..54c586b 100644
--- a/src/contactpanel.h
+++ b/src/contactpanel.h
@@ -14,9 +14,11 @@
 #include <QDialog>
 #include <QStringListModel>
 #include <QtSql/QSqlDatabase>
+#include <QMenu>
 
 #include "profileeditor.h"
 #include "addcontactpanel.h"
+#include "setaliasdialog.h"
 
 #ifndef Q_MOC_RUN
 #include "contact-manager.h"
@@ -45,12 +47,29 @@
   void
   openAddContactPanel();
 
+  void
+  openSetAliasDialog();
+
+  void
+  refreshContactList();
+
+  void
+  showContextMenu(const QPoint& pos);
+
 private:
   Ui::ContactPanel *ui;
   ndn::Ptr<ContactManager> m_contactManager;
   QStringListModel* m_contactListModel;
   ProfileEditor* m_profileEditor;
   AddContactPanel* m_addContactPanel;
+  SetAliasDialog* m_setAliasDialog;
+  QAction* m_menuInvite;
+  QAction* m_menuAlias;
+
+
+  std::vector<ndn::Ptr<ContactItem> > m_contactList;
+
+  std::string m_currentSelectedContact;
 };
 
 #endif // CONTACTPANEL_H
diff --git a/src/contactpanel.ui b/src/contactpanel.ui
index 442fdae..6819ad0 100644
--- a/src/contactpanel.ui
+++ b/src/contactpanel.ui
@@ -43,7 +43,7 @@
       <item>
        <widget class="QListView" name="ContactList">
         <property name="contextMenuPolicy">
-         <enum>Qt::DefaultContextMenu</enum>
+         <enum>Qt::CustomContextMenu</enum>
         </property>
         <property name="acceptDrops">
          <bool>false</bool>
diff --git a/src/profile.h b/src/profile.h
index 0f5a5cc..5c9ce24 100644
--- a/src/profile.h
+++ b/src/profile.h
@@ -65,6 +65,10 @@
   static ndn::Ptr<Profile>
   fromDerBlob(const ndn::Blob& derBlob);
 
+  inline const std::map<std::string, ndn::Blob>&
+  getEntries() const
+  { return m_entries; }
+
 protected:
   ndn::Name m_identityName;
   std::map<std::string, ndn::Blob> m_entries;
diff --git a/src/setaliasdialog.cpp b/src/setaliasdialog.cpp
new file mode 100644
index 0000000..38e70d9
--- /dev/null
+++ b/src/setaliasdialog.cpp
@@ -0,0 +1,68 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "setaliasdialog.h"
+#include "ui_setaliasdialog.h"
+
+
+using namespace ndn;
+using namespace std;
+
+SetAliasDialog::SetAliasDialog(Ptr<ContactManager> contactManager,
+			       QWidget *parent) 
+  : QDialog(parent)
+  , ui(new Ui::SetAliasDialog)
+  , m_contactManager(contactManager)
+{
+    ui->setupUi(this);
+
+    connect(ui->okButton, SIGNAL(clicked()),
+	    this, SLOT(onOkClicked()));
+    connect(ui->cancelButton, SIGNAL(clicked()),
+	    this, SLOT(onCancelClicked()));
+}
+
+SetAliasDialog::~SetAliasDialog()
+{
+    delete ui;
+}
+
+void
+SetAliasDialog::onOkClicked()
+{
+  QString text = ui->aliasInput->text();
+  string alias = text.toUtf8().constData();
+  
+  m_contactManager->getContactStorage()->updateAlias(Name(m_target), alias);
+
+  emit aliasChanged();
+
+  this->close();
+}
+
+void
+SetAliasDialog::onCancelClicked()
+{ this->close(); }
+
+void 
+SetAliasDialog::setTargetIdentity(const string& name)
+{ 
+  m_target = name; 
+  string msg("Set alias for ");
+  msg.append(name).append(":");
+  ui->introLabel->setText(QString::fromUtf8(msg.c_str()));
+  ui->aliasInput->clear();
+}
+
+
+#if WAF
+#include "setaliasdialog.moc"
+#include "setaliasdialog.cpp.moc"
+#endif
diff --git a/src/setaliasdialog.h b/src/setaliasdialog.h
new file mode 100644
index 0000000..1e24963
--- /dev/null
+++ b/src/setaliasdialog.h
@@ -0,0 +1,53 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef SETALIASDIALOG_H
+#define SETALIASDIALOG_H
+
+#include <QDialog>
+
+#ifndef Q_MOC_RUN
+#include "contact-manager.h"
+#endif
+
+namespace Ui {
+class SetAliasDialog;
+}
+
+class SetAliasDialog : public QDialog
+{
+  Q_OBJECT
+
+public:
+  explicit SetAliasDialog(ndn::Ptr<ContactManager> contactManager,
+			  QWidget *parent = 0);
+  ~SetAliasDialog();
+
+  void
+  setTargetIdentity(const std::string& name);
+
+signals:
+  void
+  aliasChanged();
+
+private slots:
+  void
+  onOkClicked();
+
+  void 
+  onCancelClicked();
+
+private:
+  Ui::SetAliasDialog *ui;
+  ndn::Ptr<ContactManager> m_contactManager;
+  std::string m_target;
+};
+
+#endif // SETALIASDIALOG_H
diff --git a/src/setaliasdialog.ui b/src/setaliasdialog.ui
new file mode 100644
index 0000000..3beeb3a
--- /dev/null
+++ b/src/setaliasdialog.ui
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SetAliasDialog</class>
+ <widget class="QDialog" name="SetAliasDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>300</width>
+    <height>150</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <widget class="QLineEdit" name="aliasInput">
+   <property name="geometry">
+    <rect>
+     <x>20</x>
+     <y>60</y>
+     <width>260</width>
+     <height>21</height>
+    </rect>
+   </property>
+  </widget>
+  <widget class="QPushButton" name="okButton">
+   <property name="geometry">
+    <rect>
+     <x>180</x>
+     <y>100</y>
+     <width>100</width>
+     <height>32</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>OK</string>
+   </property>
+  </widget>
+  <widget class="QPushButton" name="cancelButton">
+   <property name="geometry">
+    <rect>
+     <x>20</x>
+     <y>100</y>
+     <width>100</width>
+     <height>32</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>Cancel</string>
+   </property>
+  </widget>
+  <widget class="QLabel" name="introLabel">
+   <property name="geometry">
+    <rect>
+     <x>20</x>
+     <y>20</y>
+     <width>260</width>
+     <height>30</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>TextLabel</string>
+   </property>
+   <property name="alignment">
+    <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+   </property>
+  </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>