contract ERC1404CustomImpl is ERC1404, StandardToken, Whitelist {
    /// @notice Restriction codes and messages as constant variables
    /// @dev Holding restriction codes and messages as constants is not required by the standard
    string public constant UNKNOWN_MESSAGE = "UNKNOWN";
    uint8 public constant SUCCESS_CODE = 0;
    string public constant SUCCESS_MESSAGE = "SUCCESS";
    uint8 public constant ZERO_ADDRESS_RESTRICTION_CODE = 1;
    string public constant ZERO_ADDRESS_RESTRICTION_MESSAGE = "ILLEGAL_TRANSFER_TO_ZERO_ADDRESS";
    uint8 public constant SEND_NOT_ALLOWED_CODE = 2;
    string public constant SEND_NOT_ALLOWED_MESSAGE = "ILLEGAL_TRANSFER_SENDING_ACCOUNT_NOT_WHITELISTED";
    uint8 public constant RECEIVE_NOT_ALLOWED_CODE = 3;
    string public constant RECEIVE_NOT_ALLOWED_MESSAGE = "ILLEGAL_TRANSFER_RECEIVING_ACCOUNT_NOT_WHITELISTED";


    /// @notice Checks if a transfer is restricted, reverts if it is
    /// @param from Sending address
    /// @param to Receiving address
    /// @param value Amount of tokens being transferred
    /// @dev Defining this modifier is not required by the standard, using detectTransferRestriction and appropriately emitting TransferRestricted is however
    modifier notRestricted (address from, address to, uint256 value) {
        uint8 restrictionCode = detectTransferRestriction(from, to, value);
        require(restrictionCode == SUCCESS_CODE, messageForTransferRestriction(restrictionCode));
        _;
    }

    /// @notice Detects if a transfer will be reverted and if so returns an appropriate reference code
    /// @param from Sending address
    /// @param to Receiving address
    /// @param value Amount of tokens being transferred
    /// @return Code by which to reference message for rejection reasoning
    /// @dev Overwrite with your custom transfer restriction logic
    function detectTransferRestriction (address from, address to, uint256 value)
        public view returns (uint8 restrictionCode)
    {
        restrictionCode = SUCCESS_CODE; // successful transfer
        
        if (to == address(0x0)) {
            restrictionCode = ZERO_ADDRESS_RESTRICTION_CODE; // illegal transfer to zero address
        } else if (!whitelist[from]) {
            restrictionCode = SEND_NOT_ALLOWED_CODE; // sender address not whitelisted
        } else if (!whitelist[to]) {
            restrictionCode = RECEIVE_NOT_ALLOWED_CODE; // receiver address not whitelisted
        }
    }

    /// @notice Returns a human-readable message for a given restriction code
    /// @param restrictionCode Identifier for looking up a message
    /// @return Text showing the restriction's reasoning
    /// @dev Overwrite with your custom message and restrictionCode handling
    function messageForTransferRestriction (uint8 restrictionCode)
        public view returns (string message)
    {
        message = UNKNOWN_MESSAGE;
        if (restrictionCode == SUCCESS_CODE) {
            message = SUCCESS_MESSAGE;
        } else if (restrictionCode == ZERO_ADDRESS_RESTRICTION_CODE) {
            message = ZERO_ADDRESS_RESTRICTION_MESSAGE;
        } else if (restrictionCode == SEND_NOT_ALLOWED_CODE) {
            message = SEND_NOT_ALLOWED_MESSAGE;
        } else if (restrictionCode == RECEIVE_NOT_ALLOWED_CODE) {
            message = RECEIVE_NOT_ALLOWED_MESSAGE;
        }
    }

    /// @notice Subclass implementation of StandardToken's ERC20 transfer method
    /// @param to Receiving address
    /// @param value Amount of tokens being transferred
    /// @return Transfer success status
    /// @dev Must compare the return value of detectTransferRestriction to 0
    function transfer (address to, uint256 value)
        public notRestricted(msg.sender, to, value) returns (bool)
    {
        return super.transfer(to, value);
    }
  
    /// @notice Subclass implementation of StandardToken's ERC20 transferFrom method
    /// @param from Sending address
    /// @param to Receiving address
    /// @param value Amount of tokens being transferred
    /// @return Transfer success status
    /// @dev Must compare the return value of detectTransferRestriction to 0
    function transferFrom (address from, address to, uint256 value)
        public notRestricted(from, to, value) returns (bool)
    {
        return super.transferFrom(from, to, value);
    }
}
/// @title Reference implementation for the ERC-1404 token
/// @notice This implementation has a transfer restriction that prevents token holders from sending to the zero address
/// @dev Ref https://github.com/ethereum/EIPs/pull/SRS
function messageForTransferRestriction (uint8 restrictionCode)
    public view returns (string message)
{
    message = UNKNOWN_MESSAGE;
    if (restrictionCode == SUCCESS_CODE) {
        message = SUCCESS_MESSAGE;
    } else if (restrictionCode == ZERO_ADDRESS_RESTRICTION_CODE) {
        message = ZERO_ADDRESS_RESTRICTION_MESSAGE;
    } else if (restrictionCode == SEND_NOT_ALLOWED_CODE) {
        message = SEND_NOT_ALLOWED_MESSAGE;
    } else if (restrictionCode == RECEIVE_NOT_ALLOWED_CODE) {
        message = RECEIVE_NOT_ALLOWED_MESSAGE;
    }
}

/// @notice Returns a human-readable message for a given restriction code
/// @param restrictionCode Identifier for looking up a message
/// @return Text showing the restriction's reasoning
/// @dev Overwrite with your custom message and restrictionCode handling