contract Activity is Ownable, Linkable {
  
  struct Event {
    uint id;
    uint gameId;
    address source;
    address[] winners;
    uint winningNumber;
    uint amount;
    uint timestamp;
  }

  /*
   * Get an event by it's id (index)
   */
  Event[] public events;

  /*
   * Add a new event
   */
  function newEvent(uint _gameId, address[] _winners, uint _winningNumber, uint _amount) public onlyLinked {
    require(_gameId > 0);
    events.push(Event(events.length, _gameId, msg.sender, _winners, _winningNumber, _amount, now));
  }

  /*
   * Get the activity feed for all games
   *
   * NOTE: set gameId to 0 for a feed of all games
   *
   * RETURNS:
   * (ids[], gameIds[], sources[], winners[] (index 0 OR msg.sender if they won), numWinners[], winningNums[], jackpots[], timestamps[])
   */
  function getFeed(uint _gameId, uint _page, uint _pageSize) public view
    returns (uint[], uint[], address[], uint[], uint[], uint[], uint[]) {
    
    return constructResponse(getFiltered(_gameId, _page - 1, _pageSize));
  }

  // ------------------------------------------------------------
  // Private Helpers

  function constructResponse(Event[] _events) private view
    returns (uint[], uint[], address[], uint[], uint[], uint[], uint[]) {
    
    uint[] memory _ids = new uint[](_events.length);
    uint[] memory _gameIds = new uint[](_events.length);
    uint[] memory _amounts = new uint[](_events.length);
    uint[] memory _timestamps = new uint[](_events.length);

    for (uint i = 0; i < _events.length; i++) {
      _ids[i] = _events[i].id;
      _gameIds[i] = _events[i].gameId;
      _amounts[i] = _events[i].amount;
      _timestamps[i] = _events[i].timestamp;
    }

    WinData memory _win = contructWinData(_events);

    return (_ids, _gameIds, _win.winners, _win.numWinners, _win.winningNumbers, _amounts, _timestamps);
  }

  struct WinData {
    address[] winners;
    uint[] numWinners;
    uint[] winningNumbers;
  }

  function contructWinData(Event[] _events) private view returns (WinData) {
    address[] memory _winners = new address[](_events.length);
    uint[] memory _numWinners = new uint[](_events.length);
    uint[] memory _winningNumbers = new uint[](_events.length);

    for (uint i = 0; i < _events.length; i++) {
      _winners[i] = chooseWinnerToDisplay(_events[i].winners, msg.sender);
      _numWinners[i] = _events[i].winners.length;
      _winningNumbers[i] = _events[i].winningNumber;
    }

    return WinData(_winners, _numWinners, _winningNumbers);
  }

  function chooseWinnerToDisplay(address[] _winners, address _user) private pure returns (address) {
    if (_winners.length < 1) return address(0);
    address _picked = _winners[0];
    if (_winners.length == 1) return _picked;
    for (uint i = 1; i < _winners.length; i++)
      if (_winners[i] == _user) _picked = _user;
    return _picked;
  }

  function getFiltered(uint _gameId, uint _page, uint _pageSize) private view returns (Event[]) {
    Event[] memory _filtered = new Event[](_pageSize);
    uint _filteredIndex;
    uint _minIndex = _page * _pageSize;
    uint _maxIndex = _minIndex + _pageSize;
    uint _count;

    for (uint i = events.length; i > 0; i--) {
      if (_gameId == 0 || events[i - 1].gameId == _gameId) {
        if (_filteredIndex >= _minIndex && _filteredIndex < _maxIndex) {
          _filtered[_count] = events[i - 1];
          _count++;
        }
        _filteredIndex++;
      }
    }

    Event[] memory _events = new Event[](_count);
    for (uint b = 0; b < _count; b++)
      _events[b] = _filtered[b];

    return _events;
  }

}
function newEvent(uint _gameId, address[] _winners, uint _winningNumber, uint _amount) public onlyLinked {
  require(_gameId > 0);
  events.push(Event(events.length, _gameId, msg.sender, _winners, _winningNumber, _amount, now));
}

/*
 * Add a new event
 */