contract Whitelist is Managed {
    mapping(address => bytes1) public whiteList;
    bytes1 internal listRule;
    bytes1 internal constant WHITELISTED_CAN_RX_CODE = 0x01;  // binary for 0001
    bytes1 internal constant WHITELISTED_CAN_TX_CODE = 0x02;  // binary for 0010
    bytes1 internal constant WHITELISTED_FREEZE_CODE = 0x04;  // binary for 0100 Always applies
    bytes1 internal constant WHITELISTED_PAUSED_CODE = 0x08;  // binary for 1000 Always applies

    function isFrozen(address _account) public view returns (bool) {
        return (WHITELISTED_FREEZE_CODE == (whiteList[_account] & WHITELISTED_FREEZE_CODE)); // 10 & 11 = True
    }

    function addToSendAllowed(address _to) external onlyManager {
        whiteList[_to] = whiteList[_to] | WHITELISTED_CAN_TX_CODE; // just add the code 1
    }

    function addToReceiveAllowed(address _to) external onlyManager {
        whiteList[_to] = whiteList[_to] | WHITELISTED_CAN_RX_CODE; // just add the code 2
    }

    function removeFromSendAllowed(address _to) public onlyManager {
        if (WHITELISTED_CAN_TX_CODE == (whiteList[_to] & WHITELISTED_CAN_TX_CODE))  { // check code 4 so it does toggle when recalled
            whiteList[_to] = whiteList[_to] ^ WHITELISTED_CAN_TX_CODE; // xor the code to remove the flag
        }
    }

    function removeFromReceiveAllowed(address _to) public onlyManager {
        if (WHITELISTED_CAN_RX_CODE == (whiteList[_to] & WHITELISTED_CAN_RX_CODE))  {
            whiteList[_to] = whiteList[_to] ^ WHITELISTED_CAN_RX_CODE;
        }
    }

    function removeFromBothSendAndReceiveAllowed (address _to) external onlyManager {
        removeFromSendAllowed(_to);
        removeFromReceiveAllowed(_to);
    }

    /*  this overrides the individual whitelisting and manager positions so a
        frozen account can not be unfrozen by a lower level manager
    */
    function freeze(address _to) external onlyOwner {
        whiteList[_to] = whiteList[_to] | WHITELISTED_FREEZE_CODE; // 4 [0100]
    }

    function unFreeze(address _to) external onlyOwner {
        if (WHITELISTED_FREEZE_CODE == (whiteList[_to] & WHITELISTED_FREEZE_CODE )) { // Already Unfrozen
            whiteList[_to] = whiteList[_to] ^ WHITELISTED_FREEZE_CODE; // 4 [0100]
        }
    }

    function pause() external onlyOwner {
        listRule = WHITELISTED_PAUSED_CODE; // 8 [1000]
    }

    function resume() external onlyOwner {
        if (WHITELISTED_PAUSED_CODE == listRule ) { // Already Unfrozen
            listRule = listRule ^ WHITELISTED_PAUSED_CODE; // 4 [0100]
        }
    }

    /*    Whitelist Rule defines what the rules are for the whitelisting
          0x00 = No rule
          0x01 = Receiver must be whitelisted
          0x10 = Sender must be whitelisted
          0x11 = Both must be whitelisted
    */
    function setWhitelistRule(byte _newRule) external onlyOwner {
        listRule = _newRule;
    }

    function getWhitelistRule() external view returns (byte){
        return listRule;
    }
}
/* ----------------------------------------------------------------------------
 * Contract function to manage the white list
 * Byte operation to control function of the whitelist,
 * and prevent duplicate address entries. simple example
 * whiteList[add] = 0000 = 0x00 = Not allowed to do either
 * whiteList[add] = 0001 = 0x01 = Allowed to receive
 * whiteList[add] = 0010 = 0x02 = Allowed to send
 * whiteList[add] = 0011 = 0x03 = Allowed to send and receive
 * whiteList[add] = 0100 = 0x04 = Frozen not allowed to do either
 * whiteList[add] = 1000 = 0x08 = Paused No one can transfer any tokens
 *----------------------------------------------------------------------------
 */
function isFrozen(address _account) public view returns (bool) {
    return (WHITELISTED_FREEZE_CODE == (whiteList[_account] & WHITELISTED_FREEZE_CODE)); // 10 & 11 = True
}

// binary for 1000 Always applies