contract TMTGOwnable {
    address public owner;
    address public centralBanker;
    address public superOwner;
    address public hiddenOwner;
    
    enum Role { owner, centralBanker, superOwner, hiddenOwner }

    mapping(address => bool) public operators;
    
    
    event TMTG_RoleTransferred(
        Role indexed ownerType,
        address indexed previousOwner,
        address indexed newOwner
    );
    
    event TMTG_SetOperator(address indexed operator); 
    event TMTG_DeletedOperator(address indexed operator);
    
    modifier onlyOwner() {
        require(msg.sender == owner);
        _;
    }
    
    modifier onlyOwnerOrOperator() {
        require(msg.sender == owner || operators[msg.sender]);
        _;
    }
    
    modifier onlyNotBankOwner(){
        require(msg.sender != centralBanker);
        _;
    }
    
    modifier onlyBankOwner(){
        require(msg.sender == centralBanker);
        _;
    }
    
    modifier onlySuperOwner() {
        require(msg.sender == superOwner);
        _;
    }
    
    modifier onlyhiddenOwner(){
        require(msg.sender == hiddenOwner);
        _;
    }
    
    constructor() public {
        owner = msg.sender;     
        centralBanker = msg.sender;
        superOwner = msg.sender; 
        hiddenOwner = msg.sender;
    }

    /**
    * @dev Set the address to operator
    * @param _operator has the ability to pause transaction, has the ability to blacklisting & unblacklisting. 
    */
    function setOperator(address _operator) external onlySuperOwner {
        operators[_operator] = true;
        emit TMTG_SetOperator(_operator);
    }

    /**
    * @dev Remove the address from operator
    * @param _operator has the ability to pause transaction, has the ability to blacklisting & unblacklisting. 
    */
    function delOperator(address _operator) external onlySuperOwner {
        operators[_operator] = false;
        emit TMTG_DeletedOperator(_operator);
    }

    /**
    * @dev It is possible to hand over owner’s authority. Only superowner is available.
    * @param newOwner  
    */
    function transferOwnership(address newOwner) public onlySuperOwner {
        emit TMTG_RoleTransferred(Role.owner, owner, newOwner);
        owner = newOwner;
    }

    /**
    * @dev It is possible to hand over centerBanker’s authority. Only superowner is available.
    * @param newBanker centerBanker is a kind of a central bank, transaction is impossible.
    * The amount of money to deposit is determined in accordance with cash reserve ratio and the amount of currency in circulation
    * To withdraw money out of a wallet and give it to owner, audit is inevitable 
    */
    function transferBankOwnership(address newBanker) public onlySuperOwner {
        emit TMTG_RoleTransferred(Role.centralBanker, centralBanker, newBanker);
        centralBanker = newBanker;
    }

    /**
    * @dev It is possible to hand over superOwner’s authority. Only hiddenowner is available.  
    * @param newSuperOwner  SuperOwner manages all authorities except for hiddenOwner and superOwner
    */
    function transferSuperOwnership(address newSuperOwner) public onlyhiddenOwner {
        emit TMTG_RoleTransferred(Role.superOwner, superOwner, newSuperOwner);
        superOwner = newSuperOwner;
    }
    
    /**
    * @dev It is possible to hand over hiddenOwner’s authority. Only hiddenowner is available
    * @param newhiddenOwner NewhiddenOwner and hiddenOwner don’t have many functions, 
    * but they can set and remove authorities of superOwner and hiddenOwner.
    */
    function changeHiddenOwner(address newhiddenOwner) public onlyhiddenOwner {
        emit TMTG_RoleTransferred(Role.hiddenOwner, hiddenOwner, newhiddenOwner);
        hiddenOwner = newhiddenOwner;
    }
}
/**
 * @title TMTGOwnable
 *
 * @dev Due to ownable change in zeppelin, the authorities in TMTGOwnable include hiddenOwner,
 *      superOwner, owner, centerBanker, and operator. 
 *      Each authority has different roles.
 */
function transferOwnership(address newOwner) public onlySuperOwner {
    emit TMTG_RoleTransferred(Role.owner, owner, newOwner);
    owner = newOwner;
}

/**
 * @dev It is possible to hand over owner’s authority. Only superowner is available.
 * @param newOwner  
 */