contract SwapProposal is Proposal {
    address[] public tokens;
    uint256[] public amounts; // unit: qToken
    bool[] public toVault;

    uint256 constant WEIGHT_SCALE = uint256(10)**18; // unit: aqToken / qToken

    constructor(address _proposer,
                address[] memory _tokens,
                uint256[] memory _amounts, // unit: qToken
                bool[] memory _toVault )
        Proposal(_proposer) public
    {
        require(_tokens.length > 0, "proposal cannot be empty");
        require(_tokens.length == _amounts.length && _amounts.length == _toVault.length,
                "unequal array lengths");
        tokens = _tokens;
        amounts = _amounts;
        toVault = _toVault;
    }

    /// Return the newly-proposed basket, based on the current vault and the old basket.
    function _newBasket(IRSV trustedRSV, Basket trustedOldBasket) internal returns(Basket) {

        uint256[] memory weights = new uint256[](tokens.length);
        // unit: aqToken/RSV

        uint256 scaleFactor = WEIGHT_SCALE.mul(uint256(10)**(trustedRSV.decimals()));
        // unit: aqToken/qToken * qRSV/RSV

        uint256 rsvSupply = trustedRSV.totalSupply();
        // unit: qRSV

        for (uint256 i = 0; i < tokens.length; i++) {
            uint256 oldWeight = trustedOldBasket.weights(tokens[i]);
            // unit: aqToken/RSV

            if (toVault[i]) {
                // We require that the execution of a SwapProposal takes in no more than the funds
                // offered in its proposal -- that's part of the premise. It turns out that,
                // because we're rounding down _here_ and rounding up in
                // Manager._executeBasketShift(), it's possible for the naive implementation of
                // this mechanism to overspend the proposer's tokens by 1 qToken. We avoid that,
                // here, by making the effective proposal one less. Yeah, it's pretty fiddly.
                
                weights[i] = oldWeight.add( (amounts[i].sub(1)).mul(scaleFactor).div(rsvSupply) );
                //unit: aqToken/RSV == aqToken/RSV == [qToken] * [aqToken/qToken*qRSV/RSV] / [qRSV]
            } else {
                weights[i] = oldWeight.sub( amounts[i].mul(scaleFactor).div(rsvSupply) );
                //unit: aqToken/RSV
            }
        }

        return new Basket(trustedOldBasket, tokens, weights);
        // unit check for weights: aqToken/RSV
    }
}
// On "unit" comments, see comment at top of Manager.sol.
function _newBasket(IRSV trustedRSV, Basket trustedOldBasket) internal returns(Basket) {

    uint256[] memory weights = new uint256[](tokens.length);
    // unit: aqToken/RSV

    uint256 scaleFactor = WEIGHT_SCALE.mul(uint256(10)**(trustedRSV.decimals()));
    // unit: aqToken/qToken * qRSV/RSV

    uint256 rsvSupply = trustedRSV.totalSupply();
    // unit: qRSV

    for (uint256 i = 0; i < tokens.length; i++) {
        uint256 oldWeight = trustedOldBasket.weights(tokens[i]);
        // unit: aqToken/RSV

        if (toVault[i]) {
            // We require that the execution of a SwapProposal takes in no more than the funds
            // offered in its proposal -- that's part of the premise. It turns out that,
            // because we're rounding down _here_ and rounding up in
            // Manager._executeBasketShift(), it's possible for the naive implementation of
            // this mechanism to overspend the proposer's tokens by 1 qToken. We avoid that,
            // here, by making the effective proposal one less. Yeah, it's pretty fiddly.
                
            weights[i] = oldWeight.add( (amounts[i].sub(1)).mul(scaleFactor).div(rsvSupply) );
            //unit: aqToken/RSV == aqToken/RSV == [qToken] * [aqToken/qToken*qRSV/RSV] / [qRSV]
        } else {
            weights[i] = oldWeight.sub( amounts[i].mul(scaleFactor).div(rsvSupply) );
            //unit: aqToken/RSV
        }
    }

    return new Basket(trustedOldBasket, tokens, weights);
    // unit check for weights: aqToken/RSV
}

/// Return the newly-proposed basket, based on the current vault and the old basket.