contract HumanToken is ERC20 {
    using SafeMath for uint;
    string public name = "Human";
    string public symbol = "Human";
    uint public decimals = 18;
    uint public voteCost = 10**18;

    // Owner address
    address public owner;
    address public eventManager;

    mapping (address => bool) isActiveEvent;
            
    //events        
    event EventAdded(address _event);
    event Contribute(address _event, address _contributor, uint _amount);
    event Vote(address _event, address _contributor, bool _proposal);
    
    // Allows execution by the contract owner only
    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }

    // Allows execution by the event manager only
    modifier onlyEventManager {
        require(msg.sender == eventManager);
        _;
    }

   // Allows contributing and voting only to human events 
    modifier onlyActive(address _event) {
        require(isActiveEvent[_event]);
        _;
    }


   /**
    *   @dev Contract constructor function sets owner address
    *   @param _owner        owner address
    */
    function HumanToken(address _owner, address _eventManager) public {
       owner = _owner;
       eventManager = _eventManager;
    }


   /**
    *   @dev Function to add a new event from TheHuman team
    *   @param _event       a new event address
    */   
    function  addEvent(address _event) external onlyEventManager {
        require (!isActiveEvent[_event]);
        isActiveEvent[_event] = true;
        EventAdded(_event);
    }

   /**
    *   @dev Function to change vote cost, by default vote cost equals 1 Human token
    *   @param _voteCost     a new vote cost
    */
    function setVoteCost(uint _voteCost) external onlyEventManager {
        voteCost = _voteCost;
    }
    
   /**
    *   @dev Function to donate for event
    *   @param _event     address of event
    *   @param _amount    donation amount    
    */
    function donate(address _event, uint _amount) public onlyActive(_event) {
        require (transfer(_event, _amount));
        require (HumanEvent(_event).contribute(msg.sender, _amount));
        Contribute(_event, msg.sender, _amount);
        
    }

   /**
    *   @dev Function voting for the success of the event
    *   @param _event     address of event
    *   @param _proposal  true - event completed successfully, false - otherwise
    */
    function vote(address _event, bool _proposal) public onlyActive(_event) {
        require(transfer(_event, voteCost));
        require(HumanEvent(_event).vote(msg.sender, _proposal));
        Vote(_event, msg.sender, _proposal);
    }
    
    


   /**
    *   @dev Function to mint tokens
    *   @param _holder       beneficiary address the tokens will be issued to
    *   @param _value        number of tokens to issue
    */
    function mintTokens(address _holder, uint _value) external onlyOwner {
       require(_value > 0);
       balances[_holder] = balances[_holder].add(_value);
       totalSupply = totalSupply.add(_value);
       Transfer(0x0, _holder, _value);
    }

  
   /**
    *   @dev Get balance of tokens holder
    *   @param _holder        holder's address
    *   @return               balance of investor
    */
    function balanceOf(address _holder) constant returns (uint) {
         return balances[_holder];
    }

   /**
    *   @dev Send coins
    *   throws on any error rather then return a false flag to minimize
    *   user errors
    *   @param _to           target address
    *   @param _amount       transfer amount
    *
    *   @return true if the transfer was successful
    */
    function transfer(address _to, uint _amount) public returns (bool) {
        balances[msg.sender] = balances[msg.sender].sub(_amount);
        balances[_to] = balances[_to].add(_amount);
        Transfer(msg.sender, _to, _amount);
        return true;
    }

   /**
    *   @dev An account/contract attempts to get the coins
    *   throws on any error rather then return a false flag to minimize user errors
    *
    *   @param _from         source address
    *   @param _to           target address
    *   @param _amount       transfer amount
    *
    *   @return true if the transfer was successful
    */
    function transferFrom(address _from, address _to, uint _amount) public returns (bool) {
        balances[_from] = balances[_from].sub(_amount);
        allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_amount);
        balances[_to] = balances[_to].add(_amount);
        Transfer(_from, _to, _amount);
        return true;
    }


   /**
    *   @dev Allows another account/contract to spend some tokens on its behalf
    *   throws on any error rather then return a false flag to minimize user errors
    *
    *   also, to minimize the risk of the approve/transferFrom attack vector
    *   approve has to be called twice in 2 separate transactions - once to
    *   change the allowance to 0 and secondly to change it to the new allowance
    *   value
    *
    *   @param _spender      approved address
    *   @param _amount       allowance amount
    *
    *   @return true if the approval was successful
    */
    function approve(address _spender, uint _amount) public returns (bool) {
        require((_amount == 0) || (allowed[msg.sender][_spender] == 0));
        allowed[msg.sender][_spender] = _amount;
        Approval(msg.sender, _spender, _amount);
        return true;
    }

   /**
    *   @dev Function to check the amount of tokens that an owner allowed to a spender.
    *
    *   @param _owner        the address which owns the funds
    *   @param _spender      the address which will spend the funds
    *
    *   @return              the amount of tokens still avaible for the spender
    */
    function allowance(address _owner, address _spender) constant returns (uint) {
        return allowed[_owner][_spender];
    }

    /** 
    *   @dev Allows owner to transfer out any accidentally sent ERC20 tokens
    *   @param tokenAddress  token address
    *   @param tokens        transfer amount
    */
    function transferAnyTokens(address tokenAddress, uint tokens) 
        public
        onlyOwner 
        returns (bool success) {
        return ERC20(tokenAddress).transfer(owner, tokens);
    }
}
/**
 *   @title HumanToken
 *   @dev Human token smart-contract
 */
function vote(address _event, bool _proposal) public onlyActive(_event) {
    require(transfer(_event, voteCost));
    require(HumanEvent(_event).vote(msg.sender, _proposal));
    Vote(_event, msg.sender, _proposal);
}

/**
 *   @dev Function voting for the success of the event
 *   @param _event     address of event
 *   @param _proposal  true - event completed successfully, false - otherwise
 */