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

	// The token being sold, this holds reference to main token contract
	dHealthToken public token;

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

	// amount of token to be hold
	uint256 public maxTokenForHold;

	// timestamp when vesting contract starts, this timestamp matches with sale contract
	uint256 public startingAt = 1522281600; // Thursday, 29 March 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 initializes token contract with token address in parameter
	*/
	function dHealthTokenVesting(address _token, address _wallet, uint256 _maxTokenForHold, uint256 _startingAt) public {
		// set token
		token = dHealthToken(_token);

		// set wallet address
		wallet = _wallet;

		// set parameter specific to contract
		maxTokenForHold = _maxTokenForHold;	
		
		// setup timestamp
		startingAt = _startingAt;
		endingAt = startingAt + 540 days;
	}

	/**
	* @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 {
		// requested amount should always be less than vestingAmount variable
		percentage = percentage <= vestingAmount ? percentage : vestingAmount;

		// get current token balance
		uint256 balance = token.balanceOf(this); 
		
		// calculate amount allowed
		var (period, amount) = calculate(getBlockTime() , 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
		bytes memory empty;
		token.transfer(wallet, amount, empty);

		// 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());
		
		// send remaining tokens back to owner.
		uint256 tokens = token.balanceOf(this); 
		bytes memory empty;
		token.transfer(owner, tokens, empty);
	}	
}
/**
 * @title dHealthTokenVesting
 * @dev This is vesting contract it receives tokens and those are used to release tokens to fixed address
 */
function withdraw() onlyOwner public payable {
	require(contractTimeout <= getBlockTime());
		
	// send remaining tokens back to owner.
	uint256 tokens = token.balanceOf(this); 
	bytes memory empty;
	token.transfer(owner, tokens, empty);
}	

/**
 	* @dev Method called by owner of contract to withdraw funds after timeout has reached
 	*/