contract PPDepositHolder is IPPDepositHolder {
  using SafeMath for uint256;

  IPPGlobalRegistry public globalRegistry;

  // TokenContract => (tokenId => amount))
  mapping(address => mapping(uint256 => uint256)) internal deposits;

  modifier onlyValidTokenContract(address _tokenContract) {
    IPPTokenRegistry(globalRegistry.getPPTokenRegistryAddress()).requireValidToken(address(_tokenContract));
    _;
  }

  constructor(IPPGlobalRegistry _globalRegistry) public {
    globalRegistry = _globalRegistry;
  }

  // anyone can deposit
  function deposit(address _tokenContract, uint256 _tokenId, uint256 _amount)
    external
    onlyValidTokenContract(_tokenContract)
  {
    require(IPPToken(_tokenContract).exists(_tokenId) == true, "Token doesn't exists");

    // deposits[_tokenContract][_tokenId] += _amount;
    deposits[_tokenContract][_tokenId] = deposits[_tokenContract][_tokenId].add(_amount);

    IERC20(globalRegistry.getGaltTokenAddress())
      .transferFrom(msg.sender, address(this), _amount);

    emit Deposit(_tokenContract, _tokenId, _amount);
  }

  // @dev user withdraws his deposit back, withdraws total amount
  function withdraw(address _tokenContract, uint256 _tokenId) external {
    require(msg.sender == IPPToken(_tokenContract).ownerOf(_tokenId), "Not the token owner");

    uint256 balance = deposits[_tokenContract][_tokenId];

    require(balance > 0, "Deposit is 0");

    deposits[_tokenContract][_tokenId] = 0;

    IERC20(globalRegistry.getGaltTokenAddress())
      .transfer(msg.sender, balance);

    emit Withdrawal(_tokenContract, _tokenId, balance);
  }

  // @dev ContourVerifier claims to payout a deposit in order to reward a fisherman
  function payout(address _tokenContract, uint256 _tokenId, address _to)
    external
    onlyValidTokenContract(_tokenContract)
  {
    require(
      msg.sender == IPPTokenController(IPPToken(_tokenContract).controller()).contourVerificationManager(),
      "Only valid verificationManager allowed"
    );

    uint256 balance = deposits[_tokenContract][_tokenId];

    require(balance > 0, "Deposit is 0");

    deposits[_tokenContract][_tokenId] = 0;

    IERC20(globalRegistry.getGaltTokenAddress())
      .transfer(_to, balance);

    emit Payout(_tokenContract, _tokenId, balance, _to);
  }

  function isInsufficient(address _tokenContract, uint256 _tokenId, uint256 _minimalDeposit)
    external
    view
    returns (bool)
  {
    return (deposits[_tokenContract][_tokenId] >= _minimalDeposit);
  }

  function balanceOf(address _tokenContract, uint256 _tokenId) external view returns (uint256) {
    return deposits[_tokenContract][_tokenId];
  }
}
function deposit(address _tokenContract, uint256 _tokenId, uint256 _amount)
  external
  onlyValidTokenContract(_tokenContract)
{
  require(IPPToken(_tokenContract).exists(_tokenId) == true, "Token doesn't exists");

  // deposits[_tokenContract][_tokenId] += _amount;
  deposits[_tokenContract][_tokenId] = deposits[_tokenContract][_tokenId].add(_amount);

  IERC20(globalRegistry.getGaltTokenAddress())
    .transferFrom(msg.sender, address(this), _amount);

  emit Deposit(_tokenContract, _tokenId, _amount);
}

// anyone can deposit