pragma solidity ^0.5.00;

contract Notary {
    mapping (address => mapping (bytes32 => NotaryTransaction)) stamps;

    struct NotaryTransaction {
        address originator;
        address recipient;
        uint256 uploaded;
        uint256 received;
        uint256 acknowledged;
        bool accepted;
    }

    function upload(bytes32 hash, address recipient) public {
        stamps[recipient][hash] = NotaryTransaction(msg.sender, recipient, block.timestamp, 0, 0, false);
    }

    function received(bytes32 hash) public {
        NotaryTransaction memory t = stamps[msg.sender][hash];
        if(t.recipient == msg.sender && t.uploaded > 0 && t.received == 0) {
            t.received = block.timestamp;
            stamps[msg.sender][hash] = t;
        }
    }

    function acknowledge(bytes32 hash, bool accept) public {
        NotaryTransaction memory t = stamps[msg.sender][hash];
        if(t.recipient == msg.sender && t.uploaded > 0 && t.received > 0 && t.acknowledged == 0 ) {
            t.acknowledged = block.timestamp;
            t.accepted = accept;
            stamps[msg.sender][hash] = t;
        }
    }

    function verifyUpload(address recipient, bytes32 hash) public view returns (uint256) {
        return stamps[recipient][hash].uploaded;
    }

    function verifyReceived(address recipient, bytes32 hash) public view returns (uint256) {
        return stamps[recipient][hash].received;
    }

    function verifyAcknowledged(address recipient, bytes32 hash) public view returns (uint256) {
        return stamps[recipient][hash].acknowledged;
    }

    function isAccepted(address recipient, bytes32 hash) public view returns (bool) {
        return stamps[recipient][hash].accepted;
    }
}