contract TimedCrowdsale is Crowdsale {
	using SafeMath for uint256;

	uint256 private _openingTime;
	uint256 private _closingTime;

	/**
	 * Event for crowdsale extending
	 * @param newClosingTime new closing time
	 * @param prevClosingTime old closing time
	 */
	event TimedCrowdsaleExtended(
		uint256 prevClosingTime,
		uint256 newClosingTime
	);

	/**
	 * @dev Reverts if not in crowdsale time range.
	 */
	modifier onlyWhileOpen {
		require(isOpen(), "TimedCrowdsale: not open");
		_;
	}

	/**
	 * @dev Constructor, takes crowdsale opening and closing times.
	 * @param openingTime Crowdsale opening time
	 * @param closingTime Crowdsale closing time
	 */
	constructor(uint256 openingTime, uint256 closingTime) public {
		// solhint-disable-next-line not-rely-on-time
		// require(
		// 	openingTime >= block.timestamp,
		// 	"TimedCrowdsale: opening time is before current time"
		// );
		// solhint-disable-next-line max-line-length
		require(
			closingTime > openingTime,
			"TimedCrowdsale: opening time is not before closing time"
		);

		_openingTime = openingTime;
		_closingTime = closingTime;
	}

	/**
	 * @return the crowdsale opening time.
	 */
	function openingTime() public view returns (uint256) {
		return _openingTime;
	}

	/**
	 * @return the crowdsale closing time.
	 */
	function closingTime() public view returns (uint256) {
		return _closingTime;
	}

	/**
	 * @return true if the crowdsale is open, false otherwise.
	 */
	function isOpen() public view returns (bool) {
		// solhint-disable-next-line not-rely-on-time
		return
			block.timestamp >= _openingTime && block.timestamp <= _closingTime;
	}

	/**
	 * @dev Checks whether the period in which the crowdsale is open has already opened.
	 * @return Whether crowdsale period has opened
	 */
	function hasOpened() public view returns (bool) {
		// solhint-disable-next-line not-rely-on-time
		return block.timestamp >= _openingTime;
	}

	/**
	 * @dev Checks whether the period in which the crowdsale is open has already elapsed.
	 * @return Whether crowdsale period has elapsed
	 */
	function hasClosed() public view returns (bool) {
		// solhint-disable-next-line not-rely-on-time
		return block.timestamp > _closingTime;
	}

	/**
	 * @dev Extend parent behavior requiring to be within contributing period.
	 * @param beneficiary Token purchaser
	 * @param tokenAmount Amount of token contributed
	 */
	function _preValidatePurchase(address beneficiary, uint256 tokenAmount)
		internal
		view
		onlyWhileOpen
	{
		super._preValidatePurchase(beneficiary, tokenAmount);
	}

	/**
	 * @dev reschedule crowdsale opening time.
	 * @param newOpeningTime Crowdsale opening time
	 */
	function _rescheduleOpeningTime(uint256 newOpeningTime) internal {
		require(!hasOpened(), "TimedCrowdsale: already opened");
		require(
			_closingTime > newOpeningTime,
			"TimedCrowdsale: new opening time is after current closing time"
		);
		_openingTime = newOpeningTime;
	}

	/**
	 * @dev Extend crowdsale.
	 * @param newClosingTime Crowdsale closing time
	 */
	function _rescheduleClosingTime(uint256 newClosingTime) internal {
		require(!hasClosed(), "TimedCrowdsale: already closed");
		// solhint-disable-next-line max-line-length
		require(
			newClosingTime > block.timestamp,
			"TimedCrowdsale: new closing time is before current time"
		);
		require(
			newClosingTime > _openingTime,
			"TimedCrowdsale: new closing time is before current closing time"
		);

		emit TimedCrowdsaleExtended(_closingTime, newClosingTime);
		_closingTime = newClosingTime;
	}
}
/**
 * @title TimedCrowdsale
 * @dev Crowdsale accepting contributions only within a time frame.
 */
function isOpen() public view returns (bool) {
	// solhint-disable-next-line not-rely-on-time
	return
		block.timestamp >= _openingTime && block.timestamp <= _closingTime;
}

/**
 	 * @return true if the crowdsale is open, false otherwise.
 	 */