contract ETOVotes is ETOToken {
	event VoteOpen(uint256 _id, uint _deadline);
	event VoteFinished(uint256 _id, bool _result);

	// How many blocks should we wait before the vote can be closed
	mapping (uint256 => Vote) private votes;

	struct Voter {
		address id;
		bool vote;
	}

	struct Vote {
		uint256 deadline;
		Voter[] voters;
		mapping(address => uint) votersIndex;
		uint256 documentHash;
	}

	constructor() public {}

	function vote(uint256 _id, bool _vote) public {
		// Allow changing opinion until vote deadline
		require (votes[_id].deadline > 0, "Vote not available");
		require(now <= votes[_id].deadline, "Vote deadline exceeded");
		if (didCastVote(_id)) {
			uint256 currentIndex = votes[_id].votersIndex[msg.sender];
			Voter memory newVoter = Voter(msg.sender, _vote);
			votes[_id].voters[currentIndex - 1] = newVoter;
		} else {
			votes[_id].voters.push(Voter(msg.sender, _vote));
			votes[_id].votersIndex[msg.sender] = votes[_id].voters.length;
		}
	}

	function getVoteDocumentHash(uint256 _id) public view returns (uint256) {
		return votes[_id].documentHash;
	}

	function openVote(uint256 _id, uint256 documentHash, uint256 voteDuration) onlyOwner external {
		require(votes[_id].deadline == 0, "Vote already ongoing");
		votes[_id].deadline = now + (voteDuration * 1 seconds);
		votes[_id].documentHash = documentHash;
		emit VoteOpen(_id, votes[_id].deadline);
	}

	/**
	* @dev Once the deadline is reached this function should be called to get decision.
	* @param _id data source id.
		*/
	function triggerDecision(uint256 _id) external {
		require(votes[_id].deadline > 0, "Vote not available");
		require(now > votes[_id].deadline, "Vote deadline not reached");
		// prevent method to be called again before its done
		votes[_id].deadline = 0;
		bool result = (getCurrentPositives(_id) > getCurrentNegatives(_id));
		emit VoteFinished(_id, result);
	}

	/**
	* @dev get vote status.
	* @param _id data source id.
		*/
	function isVoteOpen(uint256 _id) external view returns (bool) {
		return (votes[_id].deadline > 0) && (now <= votes[_id].deadline);
	}

	/**
	* @dev check if address voted already.
	* @param _id data source identifier.
	*/
	function didCastVote(uint256 _id) public view returns (bool) {
		return (votes[_id].votersIndex[msg.sender] > 0);
	}

	function getOwnVote(uint256 _id) public view returns (bool) {
		uint voterId = votes[_id].votersIndex[msg.sender];
		return votes[_id].voters[voterId-1].vote;
	}

	function getCurrentPositives(uint256 _id) public view returns (uint256) {
		uint adder = 0;
		uint256 arrayLen = votes[_id].voters.length;
		for (uint256 i = 0; i < arrayLen; i++) {
			if (votes[_id].voters[i].vote == true) {
				adder += balanceOf(votes[_id].voters[i].id);
			}
		}
		return adder;
	}

	function getCurrentNegatives(uint256 _id) public view returns (uint256) {
		uint adder = 0;
		uint256 arrayLen = votes[_id].voters.length;
		for (uint256 i = 0; i < arrayLen; i++) {
			if (votes[_id].voters[i].vote == false) {
				adder += balanceOf(votes[_id].voters[i].id);
			}
		}
		return adder;
	}
}
function triggerDecision(uint256 _id) external {
	require(votes[_id].deadline > 0, "Vote not available");
	require(now > votes[_id].deadline, "Vote deadline not reached");
	// prevent method to be called again before its done
	votes[_id].deadline = 0;
	bool result = (getCurrentPositives(_id) > getCurrentNegatives(_id));
	emit VoteFinished(_id, result);
}

/**
 	* @dev Once the deadline is reached this function should be called to get decision.
 	* @param _id data source id.
 		*/