contract Freeze is Ownable, ERC20 {
  
    using SafeMath for uint256;

    uint256 public endOfIco;
    uint256 public unlockSchema = 12;

    struct Group {
        address[] holders;
        uint until;
    }
    
    /**
    * @dev number of groups
    */
    uint public groups;
    
    address[] public gofindAllowedAddresses; // ADD 0xO ADDRESS AT FIRST PLACE
    
    /**
    * @dev link group ID ---> Group structure
    */
    mapping (uint => Group) public lockup;
    
    /**
    * @dev Check if holder under lock up
    */
    modifier lockupEnded (address _holder, address _recipient, uint256 actionAmount) {
        uint index = indexOf(_recipient, gofindAllowedAddresses);
        if (index == 0) {
            bool freezed;
            uint groupId;
            (freezed, groupId) = isFreezed(_holder);
            
            if (freezed) {
                if (lockup[groupId-1].until < block.timestamp)
                    _;
                    
                else if (getFullMonthAfterIco() != 0) {
                    uint256 available = getAvailableAmount();
                    if (actionAmount > available)
                        revert("Your holdings are freezed and your trying to use amount more than available");
                    else 
                        _;
                }
                else 
                    revert("Your holdings are freezed, wait until transfers become allowed");
            }
            else 
                _;
        }
        else
        _;
    }
    
    /**
     * @dev in timestamp
    */
    function changeEndOfIco (uint256 _date) public onlyOwner returns (bool) {
        endOfIco = _date;
    }
    
    function addGofindAllowedAddress (address _newAddress) public onlyOwner returns (bool) {
        require(indexOf(_newAddress, gofindAllowedAddresses) == 0, "that address already exists");
        gofindAllowedAddresses.push(_newAddress);
        return true;
    }
	
	/**
	 * @param _holder address of token holder to check
	 * @return bool - status of freezing and group
	 */
    function isFreezed (address _holder) public view returns(bool, uint) {
        bool freezed = false;
        uint i = 0;
        while (i < groups) {
            uint index  = indexOf(_holder, lockup[i].holders);

            if (index == 0) {
                if (checkZeroIndex(_holder, i)) {
                    freezed = true;
                    i++;
                    continue;
                }  
                else {
                    i++;
                    continue;
                }
            } 
        
            if (index != 0) {
                freezed = true;
                i++;
                continue;
            }
            i++;
        }
        if (!freezed) i = 0;
        
        return (freezed, i);
    }
  
	/**
	 * @dev internal usage to get index of holder in group
	 * @param element address of token holder to check
	 * @param at array of addresses that is group of holders
	 * @return index of holder at array
	 */
    function indexOf (address element, address[] memory at) internal pure returns (uint) {
        for (uint i=0; i < at.length; i++) {
            if (at[i] == element) return i;
        }
        return 0;
    }
  
	/**
	 * @dev internal usage to check that 0 is 0 index or it means that address not exists
	 * @param _holder address of token holder to check
	 * @param lockGroup id of group to check address existance in it
	 * @return true if holder at zero index at group false if holder doesn't exists
	 */
    function checkZeroIndex (address _holder, uint lockGroup) internal view returns (bool) {
        if (lockup[lockGroup].holders[0] == _holder)
            return true;
            
        else 
            return false;
    }

    /**
     * @dev returns available tokens amount after linear release for msg.sender
     */
    function getAvailableAmount () internal view returns (uint256) {
        uint256 monthes = getFullMonthAfterIco();
        uint256 balance = balanceOf(msg.sender);
        uint256 monthShare = balance.div(unlockSchema);
        uint256 available = monthShare * monthes;
        return available;
    }
    
    /**
     * @dev calculate how much month have gone after end of ICO
     */
    function getFullMonthAfterIco () internal view returns (uint256) {
        uint256 currentTime = block.timestamp;
        if (currentTime < endOfIco)
            return 0;
        else {
            uint256 delta = currentTime - endOfIco;
            uint256 step = 2592000;
            if (delta > step) {
                uint256 times = delta.div(step);
                return times;
            }
            else {
                return 0;
            }
        }
    }
  
	/**
	 * @dev Will set group of addresses that will be under lock. When locked address can't
	  		  do some actions with token
	 * @param _holders array of addresses to lock
	 * @param _until   timestamp until that lock up will last
	 * @return bool result of operation
	 */
    function setGroup (address[] memory _holders, uint _until) public onlyOwner returns (bool) {
        lockup[groups].holders = _holders;
        lockup[groups].until   = _until;
        
        groups++;
        return true;
    }
}
function isFreezed (address _holder) public view returns(bool, uint) {
    bool freezed = false;
    uint i = 0;
    while (i < groups) {
        uint index  = indexOf(_holder, lockup[i].holders);

        if (index == 0) {
            if (checkZeroIndex(_holder, i)) {
                freezed = true;
                i++;
                continue;
            }  
            else {
                i++;
                continue;
            }
        } 
        
        if (index != 0) {
            freezed = true;
            i++;
            continue;
        }
        i++;
    }
    if (!freezed) i = 0;
        
    return (freezed, i);
}

/**
 	 * @param _holder address of token holder to check
 	 * @return bool - status of freezing and group
 	 */