refactor code

Change-Id: Ia2bc49ed8742d79000fd59f7e95fa9b957573c54
diff --git a/core/leaf.cpp b/core/leaf.cpp
index 33ee527..e862d37 100644
--- a/core/leaf.cpp
+++ b/core/leaf.cpp
@@ -16,25 +16,239 @@
  * You should have received a copy of the GNU General Public License along with
  * NSL, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  *
- * @author Peizhen Guo <patrick.guopz@gmail.com>
+ * See AUTHORS.md for complete list of nsl authors and contributors.
  */
+
 #include "leaf.hpp"
+#include "tlv.hpp"
+#include <ndn-cxx/security/digest-sha256.hpp>
+#include <ndn-cxx/encoding/block-helpers.hpp>
+#include <ndn-cxx/util/crypto.hpp>
 
-namespace nsl{
+namespace nsl {
 
-ndn::ConstBufferPtr
-Leaf::getData() const
+const Name Leaf::EMPTY_NAME;
+const size_t Leaf::N_LOGGER_LEAF_SUFFIX = 4;
+const ssize_t Leaf::OFFSET_LEAF_SEQNO = -2;
+const ssize_t Leaf::OFFSET_LEAF_HASH = -1;
+
+Leaf::Leaf()
 {
-  return m_data;
 }
 
-
+Leaf::Leaf(const Name& dataName,
+       const Timestamp& timestamp,
+       const NonNegativeInteger& dataSeqNo,
+       const NonNegativeInteger& signerSeqNo,
+       const Name& loggerName)
+  : m_dataName(dataName)
+  , m_timestamp(timestamp)
+  , m_dataSeqNo(dataSeqNo)
+  , m_signerSeqNo(signerSeqNo)
+  , m_loggerName(loggerName)
+{
+  if (m_dataSeqNo < m_signerSeqNo)
+    throw Error("Leaf: signer seqNo should be less than the data seqNo");
+}
 
 void
-Leaf::computeHash()
+Leaf::setDataSeqNo(const NonNegativeInteger& dataSeqNo)
 {
-  ndn::ConstBufferPtr digest = ndn::crypto::sha256(m_data->buf(), m_data->size());
-  this->setHash(digest);
+  if (dataSeqNo < m_signerSeqNo)
+    throw Error("Leaf: signer seqNo should be less than the data seqNo");
+
+  m_wire.reset();
+  m_dataSeqNo = dataSeqNo;
+}
+
+void
+Leaf::setDataName(const Name& dataName)
+{
+  m_wire.reset();
+  m_dataName = dataName;
+}
+
+void
+Leaf::setTimestamp(const Timestamp& timestamp)
+{
+  m_wire.reset();
+  m_timestamp = timestamp;
+}
+
+void
+Leaf::setSignerSeqNo(const NonNegativeInteger& signerSeqNo)
+{
+  if (m_dataSeqNo < signerSeqNo)
+    throw Error("Leaf: signer seqNo should be less than the data seqNo");
+
+  m_wire.reset();
+  m_signerSeqNo = signerSeqNo;
+}
+
+void
+Leaf::setLoggerName(const Name& loggerName)
+{
+  m_loggerName = loggerName;
+}
+
+ndn::ConstBufferPtr
+Leaf::getHash() const
+{
+  wireEncode();
+  return ndn::crypto::sha256(m_wire.wire(), m_wire.size());
+}
+
+shared_ptr<Data>
+Leaf::encode() const
+{
+  auto data = make_shared<Data>();
+
+  ndn::ConstBufferPtr hash = getHash();
+
+  // Name
+  Name dataName = m_loggerName;
+  dataName.appendNumber(m_dataSeqNo).append(hash->buf(), hash->size());
+  data->setName(dataName);
+
+  // Content
+  data->setContent(wireEncode());
+
+  // Signature
+  ndn::DigestSha256 sig;
+  data->setSignature(sig);
+
+  Block sigValue(tlv::SignatureValue,
+                 ndn::crypto::sha256(data->wireEncode().value(),
+                                     data->wireEncode().value_size() -
+                                     data->getSignature().getValue().size()));
+  data->setSignatureValue(sigValue);
+
+  data->wireEncode();
+
+  return data;
+}
+
+void
+Leaf::decode(const Data& data)
+{
+  const Name& dataName = data.getName();
+
+  if (!m_loggerName.isPrefixOf(dataName))
+    throw Error("decode: leaf data name does not match logger name");
+
+  if (m_loggerName.size() + N_LOGGER_LEAF_SUFFIX != dataName.size())
+    throw Error("decode: leaf data name does not follow the naming convention");
+
+  ndn::ConstBufferPtr leafHash;
+  NonNegativeInteger dataSeqNo;
+  try {
+    leafHash = make_shared<ndn::Buffer>(dataName.get(OFFSET_LEAF_HASH).value(),
+                                        dataName.get(OFFSET_LEAF_HASH).value_size());
+
+    dataSeqNo = dataName.get(OFFSET_LEAF_SEQNO).toNumber();
+  }
+  catch (tlv::Error&) {
+    throw Error("decode: logger name encoding error");
+  }
+
+  wireDecode(data.getContent().blockFromValue());
+
+  if (*leafHash != *getHash())
+    throw Error("decode: inconsistent hash");
+
+  if (m_dataSeqNo != dataSeqNo)
+    throw Error("decode: seqNo does not match");
+}
+
+template<ndn::encoding::Tag TAG>
+size_t
+Leaf::wireEncode(ndn::EncodingImpl<TAG>& block) const
+{
+  size_t totalLength = 0;
+
+  totalLength += ndn::prependNonNegativeIntegerBlock(block, tlv::SignerSeqNo, m_signerSeqNo);
+  totalLength += ndn::prependNonNegativeIntegerBlock(block, tlv::DataSeqNo, m_dataSeqNo);
+  totalLength += ndn::prependNonNegativeIntegerBlock(block, tlv::Timestamp, m_timestamp);
+  totalLength += m_dataName.wireEncode(block);
+
+  totalLength += block.prependVarNumber(totalLength);
+  totalLength += block.prependVarNumber(tlv::LoggerLeaf);
+
+  return totalLength;
+}
+
+template size_t
+Leaf::wireEncode<ndn::encoding::EncoderTag>(ndn::EncodingImpl<ndn::encoding::EncoderTag>&) const;
+
+template size_t
+Leaf::wireEncode<ndn::encoding::EstimatorTag>(ndn::EncodingImpl<ndn::encoding::EstimatorTag>&) const;
+
+
+const Block&
+Leaf::wireEncode() const
+{
+  if (m_wire.hasWire())
+    return m_wire;
+
+  ndn::EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
+
+  ndn::EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
+
+  m_wire = buffer.block();
+  return m_wire;
+}
+
+void
+Leaf::wireDecode(const Block& wire)
+{
+  if (!wire.hasWire()) {
+    throw Error("The supplied block does not contain wire format");
+  }
+
+  m_wire = wire;
+  m_wire.parse();
+
+  if (m_wire.type() != tlv::LoggerLeaf)
+    throw tlv::Error("Unexpected TLV type when decoding logger leaf");
+
+  Block::element_const_iterator it = m_wire.elements_begin();
+
+  // the first block must be dataName
+  if (it != m_wire.elements_end() && it->type() == tlv::Name) {
+    m_dataName.wireDecode(*it);
+    it++;
+  }
+  else
+    throw Error("The first sub-TLV is not Name");
+
+  // the second block must be timestamp
+  if (it != m_wire.elements_end() && it->type() == tlv::Timestamp) {
+    m_timestamp = readNonNegativeInteger(*it);
+    it++;
+  }
+  else
+    throw Error("The second sub-TLV is not Timestamp");
+
+  // the third block must be DataSeqNo
+  if (it != m_wire.elements_end() && it->type() == tlv::DataSeqNo) {
+    m_dataSeqNo = readNonNegativeInteger(*it);
+    it++;
+  }
+  else
+    throw Error("The third sub-TLV is not DataSeqNo");
+
+  // the third block must be SignerSeqNo
+  if (it != m_wire.elements_end() && it->type() == tlv::SignerSeqNo) {
+    m_signerSeqNo = readNonNegativeInteger(*it);
+    it++;
+  }
+  else
+    throw Error("The fourth sub-TLV is not SignerSeqNo");
+
+  if (it != m_wire.elements_end())
+    throw Error("No more sub-TLV in LoggerLeaf");
 }
 
 } // namespace nsl