contract Deliver is Ownable{
	using SafeMath for uint256;

	mapping(address => uint256) public waiting_plate;
	mapping(bytes32 => uint256) public token_deliver_date_plate;
	mapping(bytes32 => uint256) public token_deliver_plate;
	mapping(bytes32 => bool) public already_deliver_token;
	mapping(address => uint256) public deliver_balance;
	mapping(bytes32 => address) public hash_mapping;
	mapping(bytes32 => bool) public deliver_suspending;

	event UpdateWaitingPlate(address indexed updater, address indexed user, uint256 waiting_time);
	event UpdateTokenDeliverPlate(address indexed updater, bytes32 indexed hash_id, uint256 token_amount);
	event UpdateTokenDeliverCheck(address indexed updater, bytes32 indexed hash_id, bool flag);
	event UpdateTokenDeliverBalance(address indexed updater, address indexed user, uint256 pending_token_amount);
	event UpdateHashMapping(address indexed updater, bytes32 indexed hash_id, address indexed user);
	event UpdateDeliverSuspending(address indexed updater, bytes32 indexed hash_id, bool deliver_suspending);

	/**
	* @dev called for get user waiting time
	* @param _user Address
	* @return A uint256 that if the operation was successful.
	*/
	function getWaitingPlate(address _user) public view returns(uint256){
		return waiting_plate[_user];
	}
	
	/**
	* @dev called for get user deliver date
	* @param _hash_id transaction unique hash id
	* @return A uint256 that if the operation was successful.
	*/
	function getTokenDeliverDatePlate(bytes32 _hash_id) public view returns(uint256){
		return token_deliver_date_plate[_hash_id];
	}

	/**
	* @dev called for get user waiting time
	* @param _hash_id transaction unique hash id
	* @return A uint256 that if the operation was successful.
	*/
	function getTokenDeliverPlate(bytes32 _hash_id) public view returns(uint256){
		return token_deliver_plate[_hash_id];
	}

	/**
	* @dev called for get user total pending token amount
	* @param _user user address
	* @return A uint256 that if the operation was successful.
	*/
	function getPendingDeliverToken(address _user) public view returns(uint256){
		return deliver_balance[_user];
	}

	/**
	* @dev called for get user address from hash_id
	* @param _hash_id transaction unique hash id
	* @return A address that if the operation was successful.
	*/
	function getHashMappingAddress(bytes32 _hash_id) public view returns(address){
		return hash_mapping[_hash_id];
	}

	/**
	* @dev called for get user token deliver suspending status
	* @param _hash_id transaction unique hash id
	* @return A bool that if the operation was successful.
	*/
	function getDeliverSuspending(bytes32 _hash_id) public view returns(bool){
		return deliver_suspending[_hash_id];
	}

	/**
	* @dev called for get user total pending token amount
	* @param _hash_id transaction unique hash id
	* @return A bool that if the operation was successful.
	*/
	function deliverCheck(bytes32 _hash_id) public view returns(bool){
		return already_deliver_token[_hash_id];
	}

	/**
	* @dev called for insert user waiting time
	* @param _users Address list
	* @param _waiting_times 時期申告時間リスト
	* @return A bool that if the operation was successful.
	*/
	function pushWaitingPlate(address[] _users, uint256[] _waiting_times)onlyOwner public returns(bool){

		require(_users.length > 0 && _waiting_times.length > 0);
		require(_users.length == _waiting_times.length);

		address user;
		uint256 waiting_time;

        for(uint i = 0; i < _users.length; i++) {
        	user = _users[i];
        	waiting_time = _waiting_times[i];

            waiting_plate[user] = waiting_time;

            emit UpdateWaitingPlate(msg.sender, user, waiting_time);
        }		

		return true;

	}

	/**
	* @dev called for insert user waiting time
	* @param _hash_id transaction unique hash id
	* @param _suspending ユーザーのトークン配布禁止フラグ
	* @return A bool that if the operation was successful.
	*/
	function updateDeliverSuspending(bytes32 _hash_id, bool _suspending)onlyOwner public returns(bool){
		deliver_suspending[_hash_id] = _suspending;

		emit UpdateDeliverSuspending(msg.sender, _hash_id, _suspending);
		return true;
	}

	/**
	* @dev called for insert user token info in the mapping
	* @param _hash_id transaction unique hash id
	* @param _total_token_amount the token amount that include bonus
	* @return A bool that if the operation was successful.
	*/
	function pushTokenDeliverPlate(address _beneficiary, bytes32 _hash_id, uint256 _total_token_amount, uint256 _deliver_date)onlyOwner public returns(bool){

		require(_total_token_amount > 0);

		token_deliver_plate[_hash_id] = _total_token_amount;
		already_deliver_token[_hash_id] = false;
		deliver_balance[_beneficiary] = deliver_balance[_beneficiary].add(_total_token_amount);
		hash_mapping[_hash_id] = _beneficiary;
		token_deliver_date_plate[_hash_id] = _deliver_date;

		emit UpdateTokenDeliverPlate(msg.sender, _hash_id, _total_token_amount);
		emit UpdateTokenDeliverCheck(msg.sender, _hash_id, true);
		emit UpdateTokenDeliverBalance(msg.sender, _beneficiary, deliver_balance[_beneficiary]);
		emit UpdateHashMapping(msg.sender, _hash_id, _beneficiary);
		return true;
	}

	/**
	* @dev called for reset user token info in the mapping
	* @param _hash_id transaction unique hash id
	* @return A bool that if the operation was successful.
	*/
	function resetTokenDeliverPlate(address _beneficiary, bytes32 _hash_id, uint256 _token_amount)onlyOwner public returns(bool){

		require(_token_amount > 0);

		token_deliver_plate[_hash_id] = 0;
		already_deliver_token[_hash_id] = true;
		deliver_balance[_beneficiary] = deliver_balance[_beneficiary].sub(_token_amount);

		emit UpdateTokenDeliverPlate(msg.sender, _hash_id, 0);
		emit UpdateTokenDeliverCheck(msg.sender, _hash_id, false);
		emit UpdateTokenDeliverBalance(msg.sender, _beneficiary, deliver_balance[_beneficiary]);
		return true;
	}

}
function deliverCheck(bytes32 _hash_id) public view returns(bool){
	return already_deliver_token[_hash_id];
}

/**
 	* @dev called for get user total pending token amount
 	* @param _hash_id transaction unique hash id
 	* @return A bool that if the operation was successful.
 	*/