# Path: pyledger/server/db.py
# DB = Handler()
# 
# class Contract(Model):
#     __tablename__ = 'contracts'
#     id = Column(Integer, primary_key=True)
#     name = Column(String, unique=True)
#     description = Column(String)
#     created = Column(DateTime)
#     status = relationship("Status", lazy="subquery")
#     user_id = Column(Integer, ForeignKey('users.id'))
#     user = relationship("User", back_populates="contracts")
# 
#     @classmethod
#     def query(cls):
#         return DB.session.query(cls)
# 
#     @staticmethod
#     def from_name(name):
#         return Contract.query().filter(Contract.name == name).one_or_none()
# 
#     def last_status(self):
#         return Status.query().filter(
#             Status.contract == self
#         ).order_by(desc(Status.when)).first()
# 
#     def last_statuses(self):
#         return Status.query().filter(
#             Status.contract == self
#         ).order_by(desc.Status.when).limit(2).all()
# 
# class Status(Model):
#     __tablename__ = 'status'
#     id = Column(Integer, primary_key=True)
#     contract_id = Column(Integer, ForeignKey('contracts.id'))
#     contract = relationship("Contract", back_populates="status")
#     attributes = Column(LargeBinary)
#     key = Column(LargeBinary, unique=True)  # Crash if there is a key collision.
#     when = Column(DateTime)
#     owner = Column(String)
# 
#     def __repr__(self):
#         return '<Status key: {}>'.format(self.key)
# 
#     @classmethod
#     def query(cls):
#         return DB.session.query(cls)
# 
# Path: pyledger/server/status.py
# class SimpleStatus(BaseStatus):
#     """
#     Simple status for the smart contract based on a dictionary.
#     """
#     def __init__(self, **kwargs):
#         self.args_list = [a for a in kwargs]
# 
#         for k, v in kwargs.items():
#             setattr(self, k, v)
# 
#     def dump(self):
#         return pickle.dumps({k: getattr(self, k) for k in self.args_list})
# 
#     def load(self, dump: bytes):
#         status = pickle.loads(dump)
#         self.args_list = [a for a in status]
# 
#         for k, v in status.items():
#             setattr(self, k, v)
# 
#     def to_dict(self):
#         return {k: getattr(self, k) for k in self.args_list}
# 
#     def __contains__(self, item):
#         return item in self.__dict__
# 
#     def __repr__(self):
#         return 'Pyledger status with attributes {}'.format(
#             self.args_list)


import abc
import datetime
import inspect
from pyledger.server.db import DB, Contract, Status
from pyledger.server.status import SimpleStatus


def register_contract(contract, description=''):
    """
    Register a contract and make it
    :param contract:
    :param description:
    :return:
    """
    global contract_registry

    if contract.__class__.__name__ in contract_registry:
        raise ValueError('A contract with the same name already registered')
    else:
        contract_registry[contract.__class__.__name__] = contract

    db_contract = Contract()
    db_contract.name = contract.__class__.__name__
    db_contract.created = datetime.datetime.now()
    db_contract.description = description

    first_status = Status()
    first_status.contract = db_contract
    first_status.when = datetime.datetime.now()
    first_status.attributes = status(contract).dump()
    # Genesis key is the name of the contract
    first_status.key = contract.__class__.__name__.encode('utf-8')

    DB.session.add(db_contract)
    DB.session.add(first_status)

# Path: pyledger/server/db.py
# DB = Handler()
# 
# class Contract(Model):
#     __tablename__ = 'contracts'
#     id = Column(Integer, primary_key=True)
#     name = Column(String, unique=True)
#     description = Column(String)
#     created = Column(DateTime)
#     status = relationship("Status", lazy="subquery")
#     user_id = Column(Integer, ForeignKey('users.id'))
#     user = relationship("User", back_populates="contracts")
# 
#     @classmethod
#     def query(cls):
#         return DB.session.query(cls)
# 
#     @staticmethod
#     def from_name(name):
#         return Contract.query().filter(Contract.name == name).one_or_none()
# 
#     def last_status(self):
#         return Status.query().filter(
#             Status.contract == self
#         ).order_by(desc(Status.when)).first()
# 
#     def last_statuses(self):
#         return Status.query().filter(
#             Status.contract == self
#         ).order_by(desc.Status.when).limit(2).all()
# 
# class Status(Model):
#     __tablename__ = 'status'
#     id = Column(Integer, primary_key=True)
#     contract_id = Column(Integer, ForeignKey('contracts.id'))
#     contract = relationship("Contract", back_populates="status")
#     attributes = Column(LargeBinary)
#     key = Column(LargeBinary, unique=True)  # Crash if there is a key collision.
#     when = Column(DateTime)
#     owner = Column(String)
# 
#     def __repr__(self):
#         return '<Status key: {}>'.format(self.key)
# 
#     @classmethod
#     def query(cls):
#         return DB.session.query(cls)
# 
# Path: pyledger/server/status.py
# class SimpleStatus(BaseStatus):
#     """
#     Simple status for the smart contract based on a dictionary.
#     """
#     def __init__(self, **kwargs):
#         self.args_list = [a for a in kwargs]
# 
#         for k, v in kwargs.items():
#             setattr(self, k, v)
# 
#     def dump(self):
#         return pickle.dumps({k: getattr(self, k) for k in self.args_list})
# 
#     def load(self, dump: bytes):
#         status = pickle.loads(dump)
#         self.args_list = [a for a in status]
# 
#         for k, v in status.items():
#             setattr(self, k, v)
# 
#     def to_dict(self):
#         return {k: getattr(self, k) for k in self.args_list}
# 
#     def __contains__(self, item):
#         return item in self.__dict__
# 
#     def __repr__(self):
#         return 'Pyledger status with attributes {}'.format(
#             self.args_list)


# Path: pyledger/server/contract.py
import abc
import datetime
import inspect
from pyledger.server.db import DB, Contract, Status
from pyledger.server.status import SimpleStatus



def register_contract(contract, description=''):
    """
    Register a contract and make it
    :param contract:
    :param description:
    :return:
    """
    global contract_registry

    if contract.__class__.__name__ in contract_registry:
        raise ValueError('A contract with the same name already registered')
    else:
        contract_registry[contract.__class__.__name__] = contract

    db_contract = Contract()
    db_contract.name = contract.__class__.__name__
    db_contract.created = datetime.datetime.now()
    db_contract.description = description

    first_status = Status()
    first_status.contract = db_contract
    first_status.when = datetime.datetime.now()
    first_status.attributes = status(contract).dump()
    # Genesis key is the name of the contract
    first_status.key = contract.__class__.__name__.encode('utf-8')

    DB.session.add(db_contract)
    DB.session.add(first_status)

    DB.session.commit()