contract InTokenWrapper is ReentrancyGuard {

    using SafeMath for uint256;
    using SafeERC20 for IToken;
    using Address for address;

    IToken public inToken;

    uint256 private _totalSupply;
    mapping (uint256 => uint256) private _historyTotalSupply;
    mapping(address => uint256) private _balances;
    //mapping to save period user last deposited tokens;
    mapping (address => uint256) private _userPeriod;    

    event RequestedExchange(address indexed user, uint256 amount);
    event RequestedWithdraw(address indexed user, uint256 amount);
    event ExecutedExchange(address indexed user, uint256 outAmount, uint256 inAmount);

    /**
     * @dev TokenWrapper constructor
     * @param _inToken Wrapped token to be exchanged
     */
    constructor(address _inToken) internal {
        require(_inToken.isContract(), "address must be a contract");
        inToken = IToken(_inToken);
    }

    /**
     * @dev Get the total amount of deposited token
     * @return uint256 total supply
     */
    function totalSupply()
        public
        view
        returns (uint256)
    {
        return _totalSupply;
    }

    /**
     * @dev Get the total amount of token at given period
     * @param _period Period for which total supply returned
     * @return uint256 total supply
     */
    function historyTotalSupply(uint256 _period)
        public
        view
        returns (uint256)
    {
        return _historyTotalSupply[_period];
    }

    /**
     * @dev Get the balance of a given account
     * @param _address User for which to retrieve balance
     */
    function balanceOf(address _address)
        public
        view
        returns (uint256)
    {
        return _balances[_address];
    }

    /**
     * @dev Deposits a given amount of inToken from user
     * @param _user User's address     
     * @param _amount Units of inToken
     * @param _period Current period
     */
    function _deposit(address _user, uint256 _amount, uint256 _period)
        internal
        nonReentrant
    {
        _balances[_user] = _balances[_user].add(_amount);
        _totalSupply = _totalSupply.add(_amount);
        _historyTotalSupply[_period] = _historyTotalSupply[_period].add(_amount);
        _userPeriod[_user] = _period;
        inToken.safeTransferFrom(_user, address(this), _amount);
        emit RequestedExchange(_user, _amount);
    }

    /**
     * @dev Withdraws a given amount of inToken from user
     * @param _user User's address
     * @param _amount Units of inToken
     * @param _period Current period
     */
    function _withdraw(address _user, uint256 _amount, uint256 _period)
        internal
        nonReentrant
    {
        _balances[_user] = _balances[_user].sub(_amount, "Not enough balance");
        _totalSupply = _totalSupply.sub(_amount);
        _historyTotalSupply[_period] = _historyTotalSupply[_period].sub(_amount);
        inToken.safeTransfer(_user, _amount);
        emit RequestedWithdraw(_user, _amount);
    }
    
    /**
     * @dev Withdraw In Tokens (balance - _out) & burn (_out) after executeExchange
     * @param _user User's address 
     * @param _out Amount of Out Tokens paid
     */
    function _withdrawExecute(address _user, uint256 _out)
        internal
        nonReentrant
    {
        uint256 _amount = balanceOf(_user);
        _totalSupply = _totalSupply.sub(_amount);
        _balances[_user] = 0;
        if(_amount > _out)
            inToken.safeTransfer(_user, _amount.sub(_out));
        inToken.burn(_out);
        emit ExecutedExchange(_user, _out, _amount.sub(_out));
    }

    /**
     * @dev Returns Period user last deposited tokens
     * @param _address address of the User
     */
     function userPeriod(address _address)
        public
        view
        returns (uint256)
    {
        return _userPeriod[_address];
    }

}
function historyTotalSupply(uint256 _period)
    public
    view
    returns (uint256)
{
    return _historyTotalSupply[_period];
}

/**
 * @dev Get the total amount of token at given period
 * @param _period Period for which total supply returned
 * @return uint256 total supply
 */