contract Voting is Ownable {
  // Number of candidates. NOTE Candidates IDs sequience starts at 1.
  uint8 public candidates;
  // An interface to a token contract to check the balance
  Token public msp;
  // The last block that the voting period is active
  uint public endBlock;

  // A map to store voting candidate for each user address
  mapping(address => uint8) public votes;
  // A list of all voters
  address[] public voters;

  /// @dev Constructor to create a Voting
  /// @param _candidatesCount Number of cadidates for the voting
  /// @param _msp Address of the MSP token contract
  /// @param _endBlock The last block that the voting period is active
  function Voting(uint8 _candidatesCount, address _msp, uint _endBlock) {
    candidates = _candidatesCount;
    msp = Token(_msp);
    endBlock = _endBlock;
  }

  /// @dev A method to signal a vote for a given `_candidate`
  /// @param _candidate Voting candidate ID
  function vote(uint8 _candidate) {
    require(_candidate > 0 && _candidate <= candidates);
    assert(endBlock == 0 || getBlockNumber() <= endBlock);
    if (votes[msg.sender] == 0) {
      voters.push(msg.sender);
    }
    votes[msg.sender] = _candidate;
    Vote(msg.sender, _candidate);
  }

  /// @return Number of voters
  function votersCount()
    constant
    returns(uint) {
    return voters.length;
  }

  /// @dev Queries the list with `_offset` and `_limit` of `voters`, candidates
  ///  choosen and MSP amount at the current block
  /// @param _offset The offset at the `voters` list
  /// @param _limit The number of voters to return
  /// @return The voters, candidates and MSP amount at current block
  function getVoters(uint _offset, uint _limit)
    constant
    returns(address[] _voters, uint8[] _candidates, uint[] _amounts) {
    return getVotersAt(_offset, _limit, getBlockNumber());
  }

  /// @dev Queries the list with `_offset` and `_limit` of `voters`, candidates
  ///  choosen and MSP amount at a specific `_blockNumber`
  /// @param _offset The offset at the `voters` list
  /// @param _limit The number of voters to return
  /// @param _blockNumber The block number when the voters's MSP balances is queried
  /// @return The voters, candidates and MSP amount at `_blockNumber`
  function getVotersAt(uint _offset, uint _limit, uint _blockNumber)
    constant
    returns(address[] _voters, uint8[] _candidates, uint[] _amounts) {

    if (_offset < voters.length) {
      uint count = 0;
      uint resultLength = voters.length - _offset > _limit ? _limit : voters.length - _offset;
      uint _block = _blockNumber > endBlock ? endBlock : _blockNumber;
      _voters = new address[](resultLength);
      _candidates = new uint8[](resultLength);
      _amounts = new uint[](resultLength);
      for(uint i = _offset; (i < voters.length) && (count < _limit); i++) {
        _voters[count] = voters[i];
        _candidates[count] = votes[voters[i]];
        _amounts[count] = msp.balanceOfAt(voters[i], _block);
        count++;
      }

      return(_voters, _candidates, _amounts);
    }
  }

  function getSummary() constant returns (uint8[] _candidates, uint[] _summary) {
    uint _block = getBlockNumber() > endBlock ? endBlock : getBlockNumber();

    // Fill the candidates IDs list
    _candidates = new uint8[](candidates);
    for(uint8 c = 1; c <= candidates; c++) {
      _candidates[c - 1] = c;
    }

    // Get MSP impact map for each candidate
    _summary = new uint[](candidates);
    uint8 _candidateIndex;
    for(uint i = 0; i < voters.length; i++) {
      _candidateIndex = votes[voters[i]] - 1;
      _summary[_candidateIndex] = _summary[_candidateIndex] + msp.balanceOfAt(voters[i], _block);
    }

    return (_candidates, _summary);
  }

  /// @dev This method can be used by the owner to extract mistakenly
  ///  sent tokens to this contract.
  /// @param _token The address of the token contract that you want to recover
  ///  set to 0 in case you want to extract ether.
  function claimTokens(address _token) onlyOwner {
    if (_token == 0x0) {
      owner.transfer(this.balance);
      return;
    }

    ERC20Basic token = ERC20Basic(_token);
    uint balance = token.balanceOf(this);
    token.transfer(owner, balance);
    ClaimedTokens(_token, owner, balance);
  }

  /// @dev This function is overridden by the test Mocks.
  function getBlockNumber() internal constant returns (uint) {
    return block.number;
  }

  event Vote(address indexed _voter, uint indexed _candidate);
  event ClaimedTokens(address indexed _token, address indexed _controller, uint _amount);
}
function vote(uint8 _candidate) {
  require(_candidate > 0 && _candidate <= candidates);
  assert(endBlock == 0 || getBlockNumber() <= endBlock);
  if (votes[msg.sender] == 0) {
    voters.push(msg.sender);
  }
  votes[msg.sender] = _candidate;
  Vote(msg.sender, _candidate);
}

/// @dev A method to signal a vote for a given `_candidate`
/// @param _candidate Voting candidate ID