contract PictosisGenesisExchanger is Ownable {
using SafeMath for uint256;

mapping (address => uint256) public collected;
uint256 public totalCollected;

PictosisGenesisToken public genesis;
PictosisToken public picto;

constructor(address _genesis, address _picto) public {
genesis = PictosisGenesisToken(_genesis);
picto = PictosisToken(_picto);
}

/// @notice Can collect tokens;
function canCollect() public view returns(bool) {
return picto.areTransfersEnabled();
}

/// @notice This method should be called by the genesis holders to collect their picto token. Requires approval
function collect() public {
require(picto.areTransfersEnabled(), "Cannot collect tokens yet");

uint balance = genesis.balanceOf(msg.sender);
uint256 amountToSend = balance.sub(collected[msg.sender]);

require(balance >= collected[msg.sender], "Balance must be greater than collected amount");
require(amountToSend > 0, "No tokens available or already exchanged");
require(picto.balanceOf(address(this)) >= amountToSend, "Exchanger does not have funds available");

totalCollected = totalCollected.add(amountToSend);
collected[msg.sender] = collected[msg.sender].add(amountToSend);

require(picto.transfer(msg.sender, amountToSend), "Transfer failure");

emit TokensCollected(msg.sender, amountToSend);
}

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

ERC20 token = ERC20(_token);
uint256 balance = token.balanceOf(address(this));

if(_token == address(picto)){
if(balance > genesis.totalSupply()){
balance = balance.sub(genesis.totalSupply());
}
require(balance >= genesis.totalSupply(), "Cannot withdraw PICTO until everyone exchanges the tokens");
}

token.transfer(msg.sender, balance);
emit ClaimedTokens(_token, msg.sender, balance);
}

event ClaimedTokens(address indexed _token, address indexed _controller, uint256 _amount);
event TokensCollected(address indexed _holder, uint256 _amount);
}
function claimTokens(address _token) public onlyOwner {
if (_token == address(0)) {
msg.sender.transfer(address(this).balance);
return;
}

ERC20 token = ERC20(_token);
uint256 balance = token.balanceOf(address(this));

if(_token == address(picto)){
if(balance > genesis.totalSupply()){
balance = balance.sub(genesis.totalSupply());
}
require(balance >= genesis.totalSupply(), "Cannot withdraw PICTO until everyone exchanges the tokens");
}

token.transfer(msg.sender, balance);
emit ClaimedTokens(_token, msg.sender, balance);
}

/// @notice This method can be used by the minter to extract mistakenly
/// sent tokens to this contract.
/// @param _token The address of the token contract that you want to recover
/// set to 0x0000...0000 in case you want to extract ether.