contract AdminUpgradeable is RequestUid {
    
    /**
     * Event
     * @dev After requesting of admin change, emit an event.
     */
    event AdminChangeRequested(bytes32 _uid, address _msgSender, address _newAdmin);
    
    /**
     * Event
     * @dev After confirming a request of admin change, emit an event.
     */
    event AdminChangeConfirmed(bytes32 _uid, address _newAdmin);
    
    /**
     * STRUCT: A struct defined to store an request of admin change.
     */
    struct AdminChangeRequest {
        address newAdminAddress;
    }
    
    /**
     * MEMBER: admin address(account address or contract address) which
     * is authorize by the inheritor.
     */
    address public admin;
    
    /**
     * MEMBER: a list of requests submitted.
     */
    mapping (bytes32 => AdminChangeRequest) public adminChangeReqs;
    
    /**
     * MODIFIER: The operations from admin is allowed only.
     */
    modifier adminOperations {
        require(msg.sender == admin, "admin can call this method only");
        _;
    }
    
    /**
     * CONSTRUCTOR: Initialize with an admin address.
     */
    constructor (address _admin) public RequestUid() {
        admin = _admin;
    }
    
    /**
     * METHOD: Upgrade the admin ---- request.
     * @dev Request changing the admin address authorized.
     * Anyone can call this method to submit a request to change
     * the admin address. It will be pending until admin address
     * comfirming the request, and the admin changes.
     * @param _newAdmin The address of new admin, account or contract.
     * @return uid The unique id of the request.
     */
    function requestAdminChange(address _newAdmin) public returns (bytes32 uid) {
        require(_newAdmin != address(0), "admin is not 0 address");

        uid = generateRequestUid();

        adminChangeReqs[uid] = AdminChangeRequest({
            newAdminAddress: _newAdmin
            });

        emit AdminChangeRequested(uid, msg.sender, _newAdmin);
    }
    
    /**
     * METHOD: Upgrade the admin ---- confirm.
     * @dev Confirm a reqeust of admin change storing in the mapping
     * of `adminChangeReqs`. The operation is authorized to the old
     * admin only. The new admin will be authorized after the method
     * called successfully.
     * @param _uid The uid of request to change admin.
     */
    function confirmAdminChange(bytes32 _uid) public adminOperations {
        admin = getAdminChangeReq(_uid);

        delete adminChangeReqs[_uid];

        emit AdminChangeConfirmed(_uid, admin);
    }
    
    /**
     * METHOD: Get the address of an admin request by uid.
     * @dev It is a private method which gets address of an admin
     * in the mapping `adminChangeReqs`
     * @param _uid The uid of request to change admin.
     * @return _newAdminAddress The address of new admin in the pending requests
     */
    function getAdminChangeReq(bytes32 _uid) private view returns (address _newAdminAddress) {
        AdminChangeRequest storage changeRequest = adminChangeReqs[_uid];

        require(changeRequest.newAdminAddress != address(0));

        return changeRequest.newAdminAddress;
    }
}
/**
 * @dev This contract makes the inheritor have the functionality if the
 * inheritor authorize the admin.
 */
function requestAdminChange(address _newAdmin) public returns (bytes32 uid) {
    require(_newAdmin != address(0), "admin is not 0 address");

    uid = generateRequestUid();

    adminChangeReqs[uid] = AdminChangeRequest({
        newAdminAddress: _newAdmin
        });

    emit AdminChangeRequested(uid, msg.sender, _newAdmin);
}

/**
 * METHOD: Upgrade the admin ---- request.
 * @dev Request changing the admin address authorized.
 * Anyone can call this method to submit a request to change
 * the admin address. It will be pending until admin address
 * comfirming the request, and the admin changes.
 * @param _newAdmin The address of new admin, account or contract.
 * @return uid The unique id of the request.
 */