contract MaraCoin is MintableToken, PausableToken, StandardBurnableToken, DetailedERC20 {
    event EnabledWhitelist();
    event DisabledWhitelist();
    event ChangedWhitelistManager(address indexed whitelistManager);
    event AddedRecipientToWhitelist(address indexed recipient);
    event AddedSenderToWhitelist(address indexed sender);
    event RemovedRecipientFromWhitelist(address indexed recipient);
    event RemovedSenderFromWhitelist(address indexed sender);

    // If the token whitelist feature is enabled or not.
    bool public whitelist = true;

    // Address of the whitelist manager.
    address public whitelistManager;

    // Addresses that can receive tokens.
    mapping(address => bool) public whitelistedRecipients;

    // Addresses that can send tokens.
    mapping(address => bool) public whitelistedSenders;

    /**
     * @dev Initialize the MaraCoin and transfer the initialBalance to the
     *      initialAccount.
     */
    constructor(address initialAccount, uint256 initialBalance)
        DetailedERC20("MaraCoin", "MARA", 18)
        public
    {
        totalSupply_ = initialBalance;
        balances[initialAccount] = initialBalance;
        emit Transfer(address(0), initialAccount, initialBalance);
    }

    /**
    * @dev Throws if called by any account other than the whitelistManager.
    */
    modifier onlyWhitelistManager() {
        require(msg.sender == whitelistManager);
        _;
    }

    /**
     * @dev Enable the whitelist feature.
     */
    function enableWhitelist() external onlyOwner {
        require(
            !whitelist,
            'Whitelist is already enabled'
        );

        whitelist = true;
        emit EnabledWhitelist();
    }
    
    /**
     * @dev Enable the whitelist feature.
     */
    function disableWhitelist() external onlyOwner {
        require(
            whitelist,
            'Whitelist is already disabled'
        );

        whitelist = false;
        emit DisabledWhitelist();
    }

    /**
     * @dev Change the whitelist manager address.
     * @param _whitelistManager address
     */
    function changeWhitelistManager(address _whitelistManager) external onlyOwner
    {
        require(_whitelistManager != address(0));

        whitelistManager = _whitelistManager;

        emit ChangedWhitelistManager(whitelistManager);
    }

    /**
     * @dev Add recipient to the whitelist.
     * @param _recipient address of the recipient
     */
    function addRecipientToWhitelist(address _recipient) external onlyWhitelistManager
    {
        require(
            !whitelistedRecipients[_recipient],
            'Recipient already whitelisted'
        );

        whitelistedRecipients[_recipient] = true;

        emit AddedRecipientToWhitelist(_recipient);
    }

    /**
     * @dev Add sender to the whitelist.
     * @param _sender address of the sender
     */
    function addSenderToWhitelist(address _sender) external onlyWhitelistManager
    {
        require(
            !whitelistedSenders[_sender],
            'Sender already whitelisted'
        );

        whitelistedSenders[_sender] = true;

        emit AddedSenderToWhitelist(_sender);
    }

    /**
     * @dev Remove recipient from the whitelist.
     * @param _recipient address of the recipient
     */
    function removeRecipientFromWhitelist(address _recipient) external onlyWhitelistManager
    {
        require(
            whitelistedRecipients[_recipient],
            'Recipient not whitelisted'
        );

        whitelistedRecipients[_recipient] = false;

        emit RemovedRecipientFromWhitelist(_recipient);
    }

    /**
     * @dev Remove sender from the whitelist.
     * @param _sender address of the sender
     */
    function removeSenderFromWhitelist(address _sender) external onlyWhitelistManager
    {
        require(
            whitelistedSenders[_sender],
            'Sender not whitelisted'
        );

        whitelistedSenders[_sender] = false;

        emit RemovedSenderFromWhitelist(_sender);
    }

    /**
     * @dev transfer token for a specified address
     * @param _to The address to transfer to.
     * @param _value The amount to be transferred.
    */
    function transfer(address _to, uint256 _value) public returns (bool)
    {
        if (whitelist) {
            require (
                whitelistedSenders[msg.sender]
                || whitelistedRecipients[_to]
                || msg.sender == owner
                || _to == owner,
                'Sender or recipient not whitelisted'
            );
        }
        return super.transfer(_to, _value);
    }

    /**
     * @dev Transfer tokens from one address to another
     * @param _from address The address which you want to send tokens from
     * @param _to address The address which you want to transfer to
     * @param _value uint256 the amount of tokens to be transferred
     */
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool)
    {
        if (whitelist) {
            require (
                whitelistedSenders[_from]
                || whitelistedRecipients[_to]
                || _from == owner
                || _to == owner,
                'Sender or recipient not whitelisted'
            );
        }

        return super.transferFrom(_from, _to, _value);
    }
}
/**
 * @title MaraCoin
 * @author https://bit-sentinel.com
 */
function addRecipientToWhitelist(address _recipient) external onlyWhitelistManager
    {
        require(
            !whitelistedRecipients[_recipient],
            'Recipient already whitelisted'
        );

        whitelistedRecipients[_recipient] = true;

        emit AddedRecipientToWhitelist(_recipient);
    }
/**
 * @dev Add recipient to the whitelist.
 * @param _recipient address of the recipient
 */