contract dHealthEtherVesting is Ownable, Timestamped {
	using SafeMath for uint256;

	// wallet address which will receive funds on pay
	address public wallet;

	// timestamp when vesting contract starts, this timestamp matches with sale contract
	uint256 public startingAt = 1516924800; // Friday, 26 January 2018 00:00:00

	// timestamp when vesting ends
	uint256 public endingAt = startingAt + 540 days;

	// how many % of ethers to vest on each call
	uint256 public vestingAmount = 20;

	// timestamp when vesting starts
	uint256 public vestingPeriodLength = 30 days;

	// time after which owner can withdraw all available funds
	uint256 public contractTimeout = startingAt + 2 years;

	// mapping that defines vesting structure
	struct VestingStruct {
		uint256 period; 
		bool status;
		address wallet;
		uint256 amount;
		uint256 timestamp;
	}

	// vesting that tracks vestings done against the period.
	mapping (uint256 => VestingStruct) public vestings;

	// Event to log whenever the payment is done
	event Payouts(uint256 indexed period, bool status, address wallet, uint256 amount, uint256 timestamp);

	/**
	* @dev Constructor that does nothing 
	*/
	function dHealthEtherVesting(address _wallet) public {
		wallet = _wallet;
	}

	/**
	* @dev default payable method to receive funds
	*/
	function() public payable {
		
	}

	/**
	* @dev Method called by owner of contract to withdraw funds
	*/
	function pay(uint256 percentage) public payable {
		// requested amount should always be less than vestingAmount variable
		percentage = percentage <= vestingAmount ? percentage : vestingAmount;

		// calculate amount allowed
		var (period, amount) = calculate(getBlockTime() , this.balance , percentage);

		// payment should not be done if period is zero
		require(period > 0);
		// payment should not be done already
		require(vestings[period].status == false);
		// wallet should not be set already.
		require(vestings[period].wallet == address(0));
		// there should be amount to pay
		require(amount > 0);

		// set period for storage
		vestings[period].period = period;
		// set status to avoid double payment
		vestings[period].status = true;
		// set wallet to track where payment was sent
		vestings[period].wallet = wallet;
		// set wallet to track how much amount sent
		vestings[period].amount = amount;
		// set timestamp of payment
		vestings[period].timestamp = getBlockTime();

		// transfer amount to wallet address
		wallet.transfer(amount);

		// log event
		Payouts(period, vestings[period].status, vestings[period].wallet, vestings[period].amount, vestings[period].timestamp);
	}

	/**
	* @dev Internal method called to current vesting period
	*/
	function getPeriod(uint256 timestamp) public view returns (uint256) {
		for(uint256 i = 1 ; i <= 18 ; i ++) {
			// calculate timestamp range
			uint256 startTime = startingAt + (vestingPeriodLength * (i - 1));
			uint256 endTime = startingAt + (vestingPeriodLength * (i));

			if(startTime <= timestamp && timestamp < endTime) {
				return i;
			}
		}

		// calculate timestamp of last period
		uint256 lastEndTime = startingAt + (vestingPeriodLength * (18));
		if(lastEndTime <= timestamp) {
			return 18;
		}

		return 0;
	}

	/**
	* @dev Internal method called to current vesting period range
	*/
	function getPeriodRange(uint256 timestamp) public view returns (uint256 , uint256) {
		for(uint256 i = 1 ; i <= 18 ; i ++) {
			// calculate timestamp range
			uint256 startTime = startingAt + (vestingPeriodLength * (i - 1));
			uint256 endTime = startingAt + (vestingPeriodLength * (i));

			if(startTime <= timestamp && timestamp < endTime) {
				return (startTime , endTime);
			}
		}

		// calculate timestamp of last period
		uint256 lastStartTime = startingAt + (vestingPeriodLength * (17));
		uint256 lastEndTime = startingAt + (vestingPeriodLength * (18));
		if(lastEndTime <= timestamp) {
			return (lastStartTime , lastEndTime);
		}

		return (0 , 0);
	}

	/**
	* @dev Internal method called to calculate withdrawal amount
	*/
	function calculate(uint256 timestamp, uint256 balance , uint256 percentage) public view returns (uint256 , uint256) {
		// find out current vesting period
		uint256 period = getPeriod(timestamp);
		if(period == 0) {
			// if period is not found then return zero;
			return (0 , 0);
		}

		// get vesting object for period
		VestingStruct memory vesting = vestings[period];	
		
		// check if payment is already done
		if(vesting.status == false) {
			// payment is not done yet
			uint256 amount;

			// if it is last month then send all remaining balance
			if(period == 18) {
				// send all
				amount = balance;
			} else {
				// calculate percentage and send
				amount = balance.mul(percentage).div(100);
			}
			
			return (period, amount);
		} else {
			// payment is already done 
			return (period, 0);
		}		
	}

	/**
	* @dev Method called by owner to change the wallet address
	*/
	function setWallet(address _wallet) onlyOwner public {
		wallet = _wallet;
	}

	/**
	* @dev Method called by owner of contract to withdraw funds after timeout has reached
	*/
	function withdraw() onlyOwner public payable {
		require(contractTimeout <= getBlockTime());
		owner.transfer(this.balance);
	}	
}
/**
 * @title dHealthEtherVesting
 * @dev This is vesting contract it receives funds and those are used to release funds to fixed address
 */
function() public payable {
		
	}
/**
 	* @dev default payable method to receive funds
 	*/