contract OperationalControl {
    /// Facilitates access & control for the game.
    /// Roles:
    ///  -The Managers (Primary/Secondary): Has universal control of all elements (No ability to withdraw)
    ///  -The Banker: The Bank can withdraw funds and adjust fees / prices.
    ///  -otherManagers: Contracts that need access to functions for gameplay

    /// @dev Emited when contract is upgraded
    event ContractUpgrade(address newContract);

    /// @dev The addresses of the accounts (or contracts) that can execute actions within each roles.
    address public managerPrimary;
    address public managerSecondary;
    address public bankManager;

    // Contracts that require access for gameplay
    mapping(address => uint8) public otherManagers;

    // @dev Keeps track whether the contract is paused. When that is true, most actions are blocked
    bool public paused = false;

    // @dev Keeps track whether the contract erroredOut. When that is true, most actions are blocked & refund can be claimed
    bool public error = false;

    /**
     * @dev Operation modifiers for limiting access only to Managers
     */
    modifier onlyManager() {
        require (msg.sender == managerPrimary || msg.sender == managerSecondary);
        _;
    }

    /**
     * @dev Operation modifiers for limiting access to only Banker
     */
    modifier onlyBanker() {
        require (msg.sender == bankManager);
        _;
    }

    /**
     * @dev Operation modifiers for any Operators
     */
    modifier anyOperator() {
        require (
            msg.sender == managerPrimary ||
            msg.sender == managerSecondary ||
            msg.sender == bankManager ||
            otherManagers[msg.sender] == 1
        );
        _;
    }

    /**
     * @dev        Operation modifier for any Other Manager
     */
    modifier onlyOtherManagers() {
        require (otherManagers[msg.sender] == 1);
        _;
    }

    /**
     * @dev Assigns a new address to act as the Primary Manager.
     * @param _newGM    New primary manager address
     */
    function setPrimaryManager(address _newGM) external onlyManager {
        require (_newGM != address(0));

        managerPrimary = _newGM;
    }

    /**
     * @dev Assigns a new address to act as the Secondary Manager.
     * @param _newGM    New Secondary Manager Address
     */
    function setSecondaryManager(address _newGM) external onlyManager {
        require (_newGM != address(0));

        managerSecondary = _newGM;
    }

    /**
     * @dev Assigns a new address to act as the Banker.
     * @param _newBK    New Banker Address
     */
    function setBanker(address _newBK) external onlyManager {
        require (_newBK != address(0));

        bankManager = _newBK;
    }

    /// @dev Assigns a new address to act as the Other Manager. (State = 1 is active, 0 is disabled)
    function setOtherManager(address _newOp, uint8 _state) external onlyManager {
        require (_newOp != address(0));

        otherManagers[_newOp] = _state;
    }

    /*** Pausable functionality adapted from OpenZeppelin ***/

    /// @dev Modifier to allow actions only when the contract IS NOT paused
    modifier whenNotPaused() {
        require (!paused);
        _;
    }

    /// @dev Modifier to allow actions only when the contract IS paused
    modifier whenPaused {
        require (paused);
        _;
    }

    /// @dev Modifier to allow actions only when the contract has Error
    modifier whenError {
        require (error);
        _;
    }

    /**
     * @dev Called by any Operator role to pause the contract.
     * Used only if a bug or exploit is discovered (Here to limit losses / damage)
     */
    function pause() external onlyManager whenNotPaused {
        paused = true;
    }

    /**
     * @dev Unpauses the smart contract. Can only be called by the Game Master
     */
    function unpause() public onlyManager whenPaused {
        // can't unpause if contract was upgraded
        paused = false;
    }

    /**
     * @dev Errors out the contract thus mkaing the contract non-functionable
     */
    function hasError() public onlyManager whenPaused {
        error = true;
    }

    /**
     * @dev Removes the Error Hold from the contract and resumes it for working
     */
    function noError() public onlyManager whenPaused {
        error = false;
    }
}
/** Controls state and access rights for contract functions
 * @title Operational Control
 * @author Fazri Zubair & Farhan Khwaja (Lucid Sight, Inc.)
 * Inspired and adapted from contract created by OpenZeppelin 
 * Ref: https://github.com/OpenZeppelin/zeppelin-solidity/
 */
function unpause() public onlyManager whenPaused {
        // can't unpause if contract was upgraded
        paused = false;
    }
/**
 * @dev Unpauses the smart contract. Can only be called by the Game Master
 */