contract Affiliates is Ownable, Linkable {
	bool open = true;
	bool promoted = true;

	/*
	 * Open/Close registration of new affiliates
	 */
	function setRegistrationOpen(bool _open) public onlyOwner {
		open = _open;
	}

	function isRegistrationOpen() public view returns (bool) {
		return open;
	}

	/*
	 * Should promote registration of new affiliates
	 */
	function setPromoted(bool _promoted) public onlyOwner {
		promoted = _promoted;
	}

	function isPromoted() public view returns (bool) {
		return promoted;
	}

	// -----------------------------------------------------------

	mapping(uint => uint) balances; // (affiliateCode => balance)
	mapping(address => uint) links; // (buyer => affiliateCode)
	mapping(uint => bool) living; // whether a code has been used before (used for open/closing of program)
	
	/*
	 * PUBLIC
	 * Get the code for an affiliate
	 */
	function getCode() public view returns (uint) {
		return code(msg.sender);
	}

	// Convert an affiliate's address into a code
	function code(address _affiliate) private pure returns (uint) {
		uint num = uint(uint256(keccak256(_affiliate)));
		return num / 10000000000000000000000000000000000000000000000000000000000000000000000;
	}

	/*
	 * PUBLIC
	 * Get the address who originally referred the given user. Returns 0 if not referred
	 */
	function getAffiliation(address _user) public view onlyLinked returns (uint) {
		return links[_user];
	}

	/*
	 * PUBLIC
	 * Set the affiliation of a user to a given code. Returns the address of the referrer
	 * linked to that code OR, if a user has already been linked to a referer, returns the
	 * address of their original referer
	 */
	function setAffiliation(address _user, uint _code) public onlyLinked returns (uint) {
		uint _affiliateCode = links[_user];
		if (_affiliateCode != 0) return _affiliateCode;
		links[_user] = _code;
		return _code;
	}

	/*
	 * RESTRICTED
	 * Add Wei to multiple affiliates, be sure to send an amount of ether 
	 * equivalent to the sum of the _amounts array
	 */
	function deposit(uint[] _affiliateCodes, uint[] _amounts) public payable onlyLinked {
		require(_affiliateCodes.length == _amounts.length && _affiliateCodes.length > 0);

		uint _total;
		for (uint i = 0; i < _affiliateCodes.length; i++) {
			balances[_affiliateCodes[i]] += _amounts[i];
			_total += _amounts[i];
		}

		require(_total == msg.value && _total > 0);
	}

	event Withdrawn(address affiliate, uint amount);

	/* 
	 * PUBLIC
	 * Withdraw Wei into your wallet (will revert if you have no balance)
	 */
	function withdraw() public returns (uint) {
		uint _code = code(msg.sender);
		uint _amount = balances[_code];
		require(_amount > 0);
		balances[_code] = 0;
		msg.sender.transfer(_amount);	
		Withdrawn(msg.sender, _amount);
		return _amount;	
	}

	/* 
	 * PUBLIC
	 * Get the amount of Wei you can withdraw
	 */
	function getBalance() public view returns (uint) {
		return balances[code(msg.sender)];
	}
}
function deposit(uint[] _affiliateCodes, uint[] _amounts) public payable onlyLinked {
	require(_affiliateCodes.length == _amounts.length && _affiliateCodes.length > 0);

	uint _total;
	for (uint i = 0; i < _affiliateCodes.length; i++) {
		balances[_affiliateCodes[i]] += _amounts[i];
		_total += _amounts[i];
	}

	require(_total == msg.value && _total > 0);
}

/*
 	 * RESTRICTED
 	 * Add Wei to multiple affiliates, be sure to send an amount of ether 
 	 * equivalent to the sum of the _amounts array
 	 */