contract FiatCappedCrowdsale is TokenlessCrowdsale, Ownable {
  using SafeMath for uint256;

  // 1 USD = 1000 mill (1 mill is USD 0.001)
  // 1 ETH = 1e18 wei
  // 1 SPX = 1e18 leconte

  uint256 public millCap; // cap defined in USD mill
  uint256 public millRaised; // amount of USD mill raised

  // Minimum fiat value purchase per transaction
  uint256 public minMillPurchase;

  // How many ETH wei per USD 0.001
  uint256 public millWeiRate;

  // How many SPX leconte per USD 0.001, without bonus
  uint256 public millLeconteRate;

  // Sanity checks
  // 1 ETH is between USD 100 and USD 5,000
  uint256 constant minMillWeiRate = (10 ** 18) / (5000 * (10 ** 3)); // USD 5,000
  uint256 constant maxMillWeiRate = (10 ** 18) / (100 * (10 ** 3)); // USD 100

  // 1 SPX is between USD 0.01 and USD 1
  uint256 constant minMillLeconteRate = (10 ** 18) / 1000; // USD 1
  uint256 constant maxMillLeconteRate = (10 ** 18) / 10; // USD 0.01

  /**
   * @dev Throws if mill rate for ETH wei is not sane
   */
  modifier isSaneETHRate(uint256 _millWeiRate) {
    require(_millWeiRate >= minMillWeiRate);
    require(_millWeiRate <= maxMillWeiRate);
    _;
  }

  /**
   * @dev Throws if mill rate for SPX wei is not sane
   */
  modifier isSaneSPXRate(uint256 _millLeconteRate) {
    require(_millLeconteRate >= minMillLeconteRate);
    require(_millLeconteRate <= maxMillLeconteRate);
    _;
  }

  /**
   * @dev Constructor
   * @param _millCap Max amount of mill to be contributed
   * @param _millLeconteRate How many SPX leconte per mill
   * @param _millWeiRate How many ETH wei per mill, this is updateable with setWeiRate()
   */
  constructor (
    uint256 _millCap,
    uint256 _minMillPurchase,
    uint256 _millLeconteRate,
    uint256 _millWeiRate
  ) public isSaneSPXRate(_millLeconteRate) isSaneETHRate(_millWeiRate) {
    require(_millCap > 0);
    require(_minMillPurchase > 0);

    millCap = _millCap;
    minMillPurchase = _minMillPurchase;
    millLeconteRate = _millLeconteRate;
    millWeiRate = _millWeiRate;
  }

  /**
   * @dev Checks whether the cap has been reached.
   * @return Whether the cap was reached
   */
  function capReached() public view returns (bool) {
    return millRaised >= millCap;
  }

  /**
   * @dev Sets the current ETH wei rate - How many ETH wei per mill
   */
  function setWeiRate(uint256 _millWeiRate) external onlyOwner isSaneETHRate(_millWeiRate) {
    millWeiRate = _millWeiRate;
  }

  /**
   * @dev Extend parent behavior requiring purchase to respect the funding cap,
   * and that contribution should be >= minMillPurchase
   * @param _beneficiary Token purchaser
   * @param _weiAmount Amount of wei contributed
   */
  function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal {
    super._preValidatePurchase(_beneficiary, _weiAmount);

    // Check for minimum contribution
    uint256 _millAmount = _toMill(_weiAmount);
    require(_millAmount >= minMillPurchase);

    // Check for funding cap
    uint256 _millRaised = millRaised.add(_millAmount);
    require(_millRaised <= millCap);
    millRaised = _millRaised;
  }

  /**
   * @dev Returns the amount in USD mill given ETH wei
   * @param _weiAmount Amount in ETH wei
   * @return amount in mill
   */
  function _toMill(uint256 _weiAmount) internal returns (uint256) {
    return _weiAmount.div(millWeiRate);
  }

  /**
   * @dev Returns the amount in SPX leconte given ETH wei
   * @param _weiAmount Amount in ETH wei
   * @return amount in leconte
   */
  function _toLeconte(uint256 _weiAmount) internal returns (uint256) {
    return _toMill(_weiAmount).mul(millLeconteRate);
  }
}
/**
 * @title FiatCappedCrowdsale
 * @dev Crowdsale with a limit for total contributions defined in fiat (USD).
 * Based on OpenZeppelin's CappedCrowdsale
 * Handles fiat rates, but does not handle token awarding.
 * @author U-Zyn Chua <uzyn@zynesis.com>
 */
function setWeiRate(uint256 _millWeiRate) external onlyOwner isSaneETHRate(_millWeiRate) {
  millWeiRate = _millWeiRate;
}

/**
 * @dev Sets the current ETH wei rate - How many ETH wei per mill
 */