## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
#
# Copyright (c) 2011-2013, Regents of the University of California
#                          Alexander Afanasyev
#
# GNU 3.0 license, See the LICENSE file for more information
#
# Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
#

#
# Based on PyCCN code, copyrighted and licensed as follows
#
# Copyright (c) 2011-2013, Regents of the University of California
# BSD license, See the COPYING file for more information
# Written by: Derek Kulinski <takeda@takeda.tk>
#             Jeff Burke <jburke@ucla.edu>
#

import ns.ndnSIM
from Name import Name
from SignedInfo import SignedInfo

class DataError (Exception):
    pass

class Data (object):
    _data = None

    def __init__(self,
                 name = None, content = None, signed_info = None,
                 data = None):
        if data:
            if isinstance (data, Data):
                self._data = data._data
            elif isinstance (data, ns.ndnSIM.ndn.Data):
                self._data = data
                self.signedInfo = SignedInfo ()
                # timestamp
                self.signedInfo.freshnessSeconds = self._data.GetFreshness ().ToDouble (ns.core.Time.S)
                if self._data.GetKeyLocator ():
                    self.signedInfo.keyLocator = Name (name = self._data.GetKeyLocator ())
            else:
                raise TypeError ("Invalid type supplied for 'data' parameter [%s]" % type (data))
        else:
            self._data = ns.ndnSIM.ndn.Data ()

            self.name = name
            self.content = content
            self.signedInfo = signed_info or SignedInfo ()

    @staticmethod
    def fromWire (wire):
        return Data (data = ns.ndnSIM.ndn.Wire.ToDataStr (bytes (wire)))

    def sign (self, key):
        """There is no actual signing in ndnSIM for now, but we will assign signature bits based on key"""
        self._data.SetSignature (key.fakeKey)

    def toWire (self):
        if self._data.GetSignature () == 0:
            raise DataError ("Data packet has not been signed, cannot create wire format")

        return ns.ndnSIM.ndn.Wire.FromDataStr (self._data)

    def verify_signature (self, key):
        """There is no actual signing in ndnSIM for now, but we will check if signature matches the key"""
        return self._data.GetSignature () == key.fakeKey

    def __getattr__ (self, name):
        if name == "_data":
            return object.__getattr__ (self, name)

        elif name == "signedInfo":
            return object.__getattr__ (self, name)
        elif name == "name":
            return Name (self._data.GetName ())
        elif name == "scope":
            return self._data.GetScope ()
        elif name == "interestLifetime":
            return self._data.GetInterestLifetime ().ToDouble (ns.core.Time.S)
        elif name == "content":
            pkt = self._data.GetPayload ()
            return ns.ndnSIM.ndn.PacketToBuffer (pkt)
        else:
            return self._data.__getattribute__ (name)

    def __setattr__(self, name, value):
        if name == "_data":
            return object.__setattr__ (self, name, value)

        elif name == 'signedInfo':
            if value is None:
                return
            if isinstance (value, SignedInfo):
                object.__setattr__ (self, name, value)

                if value.timestamp:
                    # ?
                    pass
                if value.freshnessSeconds:
                    self._data.SetFreshness (ns.core.Seconds (value))
                if value.keyLocator:
                    self._data.SetKeyLocator (value._name)
            else:
                raise TypeError ("signedInfo can be assigned either None or SignedInfo object, [%s] supplied" % type (value))
        elif name == "name":
            if value is None:
                return self._data.SetName (ns.ndnSIM.ndn.Name ())
            elif isinstance (value, Name):
                return self._data.SetName (value._name)
            elif isinstance (value, ns.ndnSIM.ndn.Name):
                return self._data.SetName (value)
            elif isinstance (value, str):
                return self._data.SetName (ns.ndnSIM.ndn.Name (value))
            else:
                raise ValueError ("Invalid name parameter")
        elif name == "content":
            if value is None:
                pkt = ns.network.Packet ()
                self._data.SetPayload (pkt)
            else:
                pkt = ns.ndnSIM.ndn.BufferToPacket (bytes (value))
                self._data.SetPayload (pkt)
        else:
            raise NameError ("Unknown attribute [%s]" % name)

    def __repr__(self):
        return "ndn.Data(%s; %s)" % str (self._data, self.signedInfo)
