// SPDX-License-Identifier: MIT
pragma solidity =0.8.13;

import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';

library Calculator {
  uint256 private constant E5 = 1e5;
  using SafeERC20 for IERC20;

  function duration(
    uint256 _rentalStartTimestamp,
    uint256 _rentalDurationByDay,
    uint256 _lockStartTime,
    uint256 _lockExpireTime,
    uint256 _maxRentalDuration,
    uint256 _minRentalDuration
  ) public view returns (uint256 _rentalStartTime, uint256 _rentalExpireTime) {
    _rentalStartTime = block.timestamp;

    // Check to see if the number of days or date conditions set by lend are met.
    require(
      _rentalExpireTime < _lockExpireTime || _lockExpireTime - _lockStartTime == 0,
      'RentalExpireAfterLockExpire'
    );
    require(
      _minRentalDuration <= _rentalDurationByDay && _rentalDurationByDay <= _maxRentalDuration,
      'RentalDurationIsOutOfRange'
    );

    // For Reservation
    if (_rentalStartTimestamp != 0) {
      require(_rentalStartTimestamp > _rentalStartTime, 'rentalStartShouldBeNow/Later');
      _rentalStartTime = _rentalStartTimestamp;
    }
    // Arguments are passed in days, so they are converted to seconds
    _rentalExpireTime = _rentalStartTime + (_rentalDurationByDay * 1 days);
  }

  function fee(
    uint256 _dailyRentalPrice,
    uint64 _lockStartTime,
    uint64 _lockExpireTime,
    address _lender,
    address _paymentToken,
    uint256 _adminFeeRatio,
    uint256 _rentalDurationByDay,
    uint256 _amount,
    uint256 _collectionOwnerFeeRatio
  )
    public
    returns (
      uint256 _lenderBenefit,
      uint256 _collectionOwnerFee,
      uint256 _adminFee
    )
  {
    /*
     * If the amount is greater than 1 in ERC721,
     * the renter will only pay more than necessary,
     * so we do not revert here to save on gas costs.
     */
    //_rentalFeeは、1日あたりの価格と数量、日数によって計算される
    uint256 _rentalFee = _dailyRentalPrice * _amount * _rentalDurationByDay; // dailyRentalPrice per Unit * Rental Amount * rentalDuration(days)
    // adminFeeは、レンタル料金に対してプロトコルロイヤリティの割合で計算される
    _adminFee = (_rentalFee * _adminFeeRatio) / E5;
    // コレクションオーナーへの収益は、コレクションオーナーロイヤリティの割合と、レンタル料金で計算される
    _collectionOwnerFee = (_rentalFee * _collectionOwnerFeeRatio) / E5;
    //貸し手の収益は、上記の残額分
    uint256 _lenderFee = _rentalFee - _adminFee - _collectionOwnerFee;

    require(_rentalFee == _adminFee + _collectionOwnerFee + _lenderFee, 'invalidCalc');
    // If the lockDuration is Zero, fee is sent to lender this time
    if (_lockStartTime < _lockExpireTime) _lenderBenefit = _lenderFee;

    // Native token
    if (_paymentToken == address(0)) {
      require(msg.value >= _rentalFee, 'InsufficientFunds');
      if (msg.value > _rentalFee) payable(msg.sender).transfer(msg.value - _rentalFee);
      // If No Locked
      if (_lockStartTime == _lockExpireTime) payable(_lender).transfer(_lenderFee); //lenderに送るのは、_lenderFeeのみ。 adminFeeとCollectionOwnerFeeはmsg.valueで送られている
      // If Loked, protocol received fee by msg.value. so no method required.
    }
    //ERC20 token
    else {
      // If No Locked
      if (_lockStartTime == _lockExpireTime) {
        IERC20(_paymentToken).safeTransferFrom(msg.sender, address(_lender), _lenderFee); //lenderに送るのは、_lenderFeeのみ
        IERC20(_paymentToken).safeTransferFrom(
          msg.sender,
          address(this),
          _collectionOwnerFee + _adminFee
        );
      }
      // If Locked, pay all fee to protocol
      else {
        IERC20(_paymentToken).safeTransferFrom(msg.sender, address(this), _rentalFee);
      }
    }
  }
}
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyReserved","type":"error"},{"inputs":[],"name":"NotAvailable","type":"error"},{"inputs":[],"name":"overLimits","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"lockId","type":"uint256"}],"name":"Canceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"lockId","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"}],"name":"ClaimedRoyalty","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"lockId","type":"uint256"},{"indexed":true,"internalType":"address","name":"lender","type":"address"},{"components":[{"internalType":"uint64","name":"minRentalDuration","type":"uint64"},{"internalType":"uint64","name":"maxRentalDuration","type":"uint64"},{"internalType":"uint64","name":"lockStartTime","type":"uint64"},{"internalType":"uint64","name":"lockExpireTime","type":"uint64"},{"internalType":"uint256","name":"dailyRentalPrice","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"privateAddress","type":"address"},{"internalType":"enum IMarket.PaymentMethod","name":"paymentMethod","type":"uint8"}],"indexed":false,"internalType":"struct IMarket.Lend","name":"lend","type":"tuple"}],"name":"Listed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rentId","type":"uint256"},{"indexed":true,"internalType":"address","name":"renter","type":"address"},{"indexed":false,"internalType":"uint256","name":"lockId","type":"uint256"},{"components":[{"internalType":"address","name":"renterAddress","type":"address"},{"internalType":"uint256","name":"rentId","type":"uint256"},{"internalType":"uint256","name":"rentalStartTime","type":"uint256"},{"internalType":"uint256","name":"rentalExpireTime","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"indexed":false,"internalType":"struct IMarket.Rent","name":"rent","type":"tuple"}],"name":"Rented","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":true,"internalType":"address","name":"vault","type":"address"}],"name":"WhiteListed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"lockId","type":"uint256"}],"name":"Withdrawn","type":"event"},{"inputs":[{"internalType":"uint256","name":"_lockId","type":"uint256"},{"internalType":"uint256","name":"_rentId","type":"uint256"}],"name":"activate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lockId","type":"uint256"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lockId","type":"uint256"}],"name":"checkAvailability","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lockId","type":"uint256"}],"name":"claimFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lockId","type":"uint256"}],"name":"claimNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_paymentTokens","type":"address[]"}],"name":"claimProtocolFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vaultAddress","type":"address"}],"name":"claimRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"collectionOwnerBenefit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lockId","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lockId","type":"uint256"}],"name":"getLendRent","outputs":[{"components":[{"components":[{"internalType":"uint64","name":"minRentalDuration","type":"uint64"},{"internalType":"uint64","name":"maxRentalDuration","type":"uint64"},{"internalType":"uint64","name":"lockStartTime","type":"uint64"},{"internalType":"uint64","name":"lockExpireTime","type":"uint64"},{"internalType":"uint256","name":"dailyRentalPrice","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"privateAddress","type":"address"},{"internalType":"enum IMarket.PaymentMethod","name":"paymentMethod","type":"uint8"}],"internalType":"struct IMarket.Lend","name":"lend","type":"tuple"},{"components":[{"internalType":"address","name":"renterAddress","type":"address"},{"internalType":"uint256","name":"rentId","type":"uint256"},{"internalType":"uint256","name":"rentalStartTime","type":"uint256"},{"internalType":"uint256","name":"rentalExpireTime","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IMarket.Rent[]","name":"rent","type":"tuple[]"}],"internalType":"struct IMarket.LendRent","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"lendRent","outputs":[{"components":[{"internalType":"uint64","name":"minRentalDuration","type":"uint64"},{"internalType":"uint64","name":"maxRentalDuration","type":"uint64"},{"internalType":"uint64","name":"lockStartTime","type":"uint64"},{"internalType":"uint64","name":"lockExpireTime","type":"uint64"},{"internalType":"uint256","name":"dailyRentalPrice","type":"uint256"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"vault","type":"address"},{"internalType":"address","name":"paymentToken","type":"address"},{"internalType":"address","name":"lender","type":"address"},{"internalType":"address","name":"privateAddress","type":"address"},{"internalType":"enum IMarket.PaymentMethod","name":"paymentMethod","type":"uint8"}],"internalType":"struct IMarket.Lend","name":"lend","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"lenderBenefit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_lockDuration","type":"uint256"},{"internalType":"uint256","name":"_minRentalDuration","type":"uint256"},{"internalType":"uint256","name":"_maxRentalDuration","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_dailyRentalPrice","type":"uint256"},{"internalType":"address","name":"_privateAddress","type":"address"},{"internalType":"address","name":"_vaultAddress","type":"address"},{"internalType":"address","name":"_paymentToken","type":"address"},{"internalType":"enum IMarket.PaymentMethod","name":"_paymentMethod","type":"uint8"}],"name":"mintAndCreateList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"paymentTokenWhiteList","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"protocolAdminBenefit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolAdminFeeRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lockId","type":"uint256"},{"internalType":"uint256","name":"_rentalStartTimestamp","type":"uint256"},{"internalType":"uint256","name":"_rentalDurationByDay","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"rent","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"reservationLimits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_bool","type":"uint256"}],"name":"setPaymentTokenWhiteList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_protocolAdminFeeRatio","type":"uint256"}],"name":"setProtocolAdminFeeRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_days","type":"uint256"}],"name":"setReservationLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_vaultAddress","type":"address"},{"internalType":"uint256","name":"_allowed","type":"uint256"}],"name":"setVaultWhiteList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_lockId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"vaultWhiteList","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]