contract BICALogicUpgradeable is AdminUpgradeable  {

    /**
     * Event
     * @dev After requesting of logic contract address change, emit an event.
     */
    event LogicChangeRequested(bytes32 _uid, address _msgSender, address _newLogic);

    /**
     * Event
     * @dev After confirming a request of logic contract address change, emit an event.
     */
    event LogicChangeConfirmed(bytes32 _uid, address _newLogic);

    /**
     * STRUCT: A struct defined to store an request of Logic contract address change.
     */
    struct LogicChangeRequest {
        address newLogicAddress;
    }

    /**
     * MEMBER: BICALogic address(a contract address) which implements logics of token.
     */
    BICALogic public bicaLogic;

    /**
     * MEMBER: a list of requests of logic change submitted
     */
    mapping (bytes32 => LogicChangeRequest) public logicChangeReqs;

    /**
     * MODIFIER: The call from bicaLogic is allowed only.
     */
    modifier onlyLogic {
        require(msg.sender == address(bicaLogic), "only logic contract is authorized");
        _;
    }

    /**
     * CONSTRUCTOR: Initialize with an admin address which is authorized to change
     * the value of bicaLogic.
     */
    constructor (address _admin) public AdminUpgradeable(_admin) {
        bicaLogic = BICALogic(0x0);
    }

    /**
     * METHOD: Upgrade the logic contract ---- request.
     * @dev Request changing the logic contract address authorized.
     * Anyone can call this method to submit a request to change
     * the logic address. It will be pending until admin address
     * comfirming the request, and the logic contract address changes, i.e.
     * the value of bicaLogic changes.
     * @param _newLogic The address of new logic contract.
     * @return uid The unique id of the request.
     */
    function requestLogicChange(address _newLogic) public returns (bytes32 uid) {
        require(_newLogic != address(0), "new logic address can not be 0");

        uid = generateRequestUid();

        logicChangeReqs[uid] = LogicChangeRequest({
            newLogicAddress: _newLogic
            });

        emit LogicChangeRequested(uid, msg.sender, _newLogic);
    }

    /**
     * METHOD: Upgrade the logic contract ---- confirm.
     * @dev Confirm a reqeust of logic contract change storing in the
     * mapping of `logicChangeReqs`. The operation is authorized to
     * the admin only.
     * @param _uid The uid of request to change logic contract.
     */
    function confirmLogicChange(bytes32 _uid) public adminOperations {
        bicaLogic = getLogicChangeReq(_uid);

        delete logicChangeReqs[_uid];

        emit LogicChangeConfirmed(_uid, address(bicaLogic));
    }

    /**
     * METHOD: Get the address of an logic contract address request by uid.
     * @dev It is a private method which gets address of an address
     * in the mapping `adminChangeReqs`
     * @param _uid The uid of request to change logic contract address.
     * @return _newLogicAddress The address of new logic contract address
     * in the pending requests
     */
    function getLogicChangeReq(bytes32 _uid) private view returns (BICALogic _newLogicAddress) {
        LogicChangeRequest storage changeRequest = logicChangeReqs[_uid];

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

        return BICALogic(changeRequest.newLogicAddress);
    }
}
/**
 * @dev This is a contract which will be inherited by BICAProxy and BICALedger.
 */
function getLogicChangeReq(bytes32 _uid) private view returns (BICALogic _newLogicAddress) {
    LogicChangeRequest storage changeRequest = logicChangeReqs[_uid];

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

    return BICALogic(changeRequest.newLogicAddress);
}

/**
 * METHOD: Get the address of an logic contract address request by uid.
 * @dev It is a private method which gets address of an address
 * in the mapping `adminChangeReqs`
 * @param _uid The uid of request to change logic contract address.
 * @return _newLogicAddress The address of new logic contract address
 * in the pending requests
 */