contract Arroundtoken is ERC20, Claimable {
    using SafeMath for uint256;

    uint64 public constant TDE_FINISH = 1542326400;//!!!!Check before deploy
    // 1542326400  GMT: 16 November 2018 г., 00:00:00
    // 1542326399  GMT: 15 November 2018 г., 23:59:59


    //////////////////////
    // State var       ///
    //////////////////////
    string  public name;
    string  public symbol;
    uint8   public decimals;
    address public accTDE;
    address public accFoundCDF;
    address public accFoundNDF1;
    address public accFoundNDF2;
    address public accFoundNDF3;
    address public accTeam;
    address public accBounty;
  
    // Implementation of frozen funds
    mapping(address => uint64) public frozenAccounts;

    //////////////
    // EVENTS    //
    ///////////////
    event NewFreeze(address _acc, uint64 _timestamp);
    event BatchDistrib(uint8 cnt, uint256 batchAmount);
    
    /**
     * @param _accTDE - main address for token distribution
     * @param _accFoundCDF  - address for CDF Found tokens (WP)
     * @param _accFoundNDF1 - address for NDF Found tokens (WP)
     * @param _accFoundNDF2 - address for NDF Found tokens (WP)
     * @param _accFoundNDF3 - address for NDF Found tokens (WP)
     * @param _accTeam - address for team tokens, will frozzen by one year
     * @param _accBounty - address for bounty tokens 
     * @param _initialSupply - subj
     */  
    constructor (
        address _accTDE, 
        address _accFoundCDF,
        address _accFoundNDF1,
        address _accFoundNDF2,
        address _accFoundNDF3,
        address _accTeam,
        address _accBounty, 
        uint256 _initialSupply
    )
    public 
    {
        require(_accTDE       != address(0));
        require(_accFoundCDF  != address(0));
        require(_accFoundNDF1 != address(0));
        require(_accFoundNDF2 != address(0));
        require(_accFoundNDF3 != address(0));
        require(_accTeam      != address(0));
        require(_accBounty    != address(0));
        require(_initialSupply > 0);
        name           = "Arround";
        symbol         = "ARR";
        decimals       = 18;
        accTDE         = _accTDE;
        accFoundCDF    = _accFoundCDF;
        accFoundNDF1   = _accFoundNDF1;
        accFoundNDF2   = _accFoundNDF2;
        accFoundNDF3   = _accFoundNDF3;
        
        accTeam        = _accTeam;
        accBounty      = _accBounty;
        _totalSupply   = _initialSupply * (10 ** uint256(decimals));// All ARR tokens in the world
        
       //Initial token distribution
        _balances[_accTDE]       = 1104000000 * (10 ** uint256(decimals)); // TDE,      36.8%=28.6+8.2 
        _balances[_accFoundCDF]  = 1251000000 * (10 ** uint256(decimals)); // CDF,      41.7%
        _balances[_accFoundNDF1] =  150000000 * (10 ** uint256(decimals)); // 0.50*NDF, 10.0%
        _balances[_accFoundNDF2] =  105000000 * (10 ** uint256(decimals)); // 0.35*NDF, 10.0%
        _balances[_accFoundNDF3] =   45000000 * (10 ** uint256(decimals)); // 0.15*NDF, 10.0%
        _balances[_accTeam]      =  300000000 * (10 ** uint256(decimals)); // team,     10.0%
        _balances[_accBounty]    =   45000000 * (10 ** uint256(decimals)); // Bounty,    1.5%
        require(  _totalSupply ==  3000000000 * (10 ** uint256(decimals)), "Total Supply exceeded!!!");
        emit Transfer(address(0), _accTDE,       1104000000 * (10 ** uint256(decimals)));
        emit Transfer(address(0), _accFoundCDF,  1251000000 * (10 ** uint256(decimals)));
        emit Transfer(address(0), _accFoundNDF1,  150000000 * (10 ** uint256(decimals)));
        emit Transfer(address(0), _accFoundNDF2,  105000000 * (10 ** uint256(decimals)));
        emit Transfer(address(0), _accFoundNDF3,   45000000 * (10 ** uint256(decimals)));
        emit Transfer(address(0), _accTeam,       300000000 * (10 ** uint256(decimals)));
        emit Transfer(address(0), _accBounty,      45000000 * (10 ** uint256(decimals)));
        //initisl freeze
        frozenAccounts[_accTeam]      = TDE_FINISH + 31536000; //+3600*24*365 sec
        frozenAccounts[_accFoundNDF2] = TDE_FINISH + 31536000; //+3600*24*365 sec
        frozenAccounts[_accFoundNDF3] = TDE_FINISH + 63158400; //+(3600*24*365)*2 +3600*24(leap year 2020)
        emit NewFreeze(_accTeam,        TDE_FINISH + 31536000);
        emit NewFreeze(_accFoundNDF2,   TDE_FINISH + 31536000);
        emit NewFreeze(_accFoundNDF3,   TDE_FINISH + 63158400);

    }
    
    modifier onlyTokenKeeper() {
        require(
            msg.sender == accTDE || 
            msg.sender == accFoundCDF ||
            msg.sender == accFoundNDF1 ||
            msg.sender == accBounty
        );
        _;
    }

    function() external { } 

    /**
     * @dev Returns standart ERC20 result with frozen accounts check
     */
    function transfer(address _to, uint256 _value) public  returns (bool) {
        require(frozenAccounts[msg.sender] < now);
        return super.transfer(_to, _value);
    }

    /**
     * @dev Returns standart ERC20 result with frozen accounts check
     */
    function transferFrom(address _from, address _to, uint256 _value) public  returns (bool) {
        require(frozenAccounts[_from] < now);
        return super.transferFrom(_from, _to, _value);
    }

    /**
     * @dev Returns standart ERC20 result with frozen accounts check
     */
    function approve(address _spender, uint256 _value) public  returns (bool) {
        require(frozenAccounts[msg.sender] < now);
        return super.approve(_spender, _value);
    }

    /**
     * @dev Returns standart ERC20 result with frozen accounts check
     */
    function increaseAllowance(address _spender, uint _addedValue) public  returns (bool success) {
        require(frozenAccounts[msg.sender] < now);
        return super.increaseAllowance(_spender, _addedValue);
    }
    
    /**
     * @dev Returns standart ERC20 result with frozen accounts check
     */
    function decreaseAllowance(address _spender, uint _subtractedValue) public  returns (bool success) {
        require(frozenAccounts[msg.sender] < now);
        return super.decreaseAllowance(_spender, _subtractedValue);
    }

    
    /**
     * @dev Batch transfer function. Allow to save up 50% of gas
     */
    function multiTransfer(address[] calldata  _investors, uint256[] calldata   _value )  
        external 
        onlyTokenKeeper 
        returns (uint256 _batchAmount)
    {
        require(_investors.length <= 255); //audit recommendation
        require(_value.length == _investors.length);
        uint8      cnt = uint8(_investors.length);
        uint256 amount = 0;
        for (uint i=0; i<cnt; i++){
            amount = amount.add(_value[i]);
            require(_investors[i] != address(0));
            _balances[_investors[i]] = _balances[_investors[i]].add(_value[i]);
            emit Transfer(msg.sender, _investors[i], _value[i]);
        }
        require(amount <= _balances[msg.sender]);
        _balances[msg.sender] = _balances[msg.sender].sub(amount);
        emit BatchDistrib(cnt, amount);
        return amount;
    }
  
    /**
     * @dev Owner can claim any tokens that transfered to this contract address
     */
    function reclaimToken(ERC20 token) external onlyOwner {
        require(address(token) != address(0));
        uint256 balance = token.balanceOf(address(this));
        token.transfer(owner, balance);
    }
}
/**
 * @title Arroundtoken
 * @dev The Arroundtoken contract is ERC20-compatible token processing contract
 * with additional  features like multiTransfer and reclaimTokens
 *
 */
function multiTransfer(address[] calldata  _investors, uint256[] calldata   _value )  
    external 
    onlyTokenKeeper 
    returns (uint256 _batchAmount)
{
    require(_investors.length <= 255); //audit recommendation
    require(_value.length == _investors.length);
    uint8      cnt = uint8(_investors.length);
    uint256 amount = 0;
    for (uint i=0; i<cnt; i++){
        amount = amount.add(_value[i]);
        require(_investors[i] != address(0));
        _balances[_investors[i]] = _balances[_investors[i]].add(_value[i]);
        emit Transfer(msg.sender, _investors[i], _value[i]);
    }
    require(amount <= _balances[msg.sender]);
    _balances[msg.sender] = _balances[msg.sender].sub(amount);
    emit BatchDistrib(cnt, amount);
    return amount;
}

/**
 * @dev Batch transfer function. Allow to save up 50% of gas
 */