contract Lockable is Adminable, ERC20Basic {
  using SafeMath for uint256;
  // EPOCH TIMESTAMP OF "Tue Jul 02 2019 00:00:00 GMT+0000"
  // @see https://www.unixtimestamp.com/index.php
  uint public globalUnlockTime = 1562025600;
  uint public constant decimals = 18;

  event UnLock(address indexed unlocked);
  event Lock(address indexed locked, uint until, uint256 value, uint count);
  event UpdateGlobalUnlockTime(uint256 epoch);

  struct LockMeta {
    uint256 value;
    uint until;
  }

  mapping(address => LockMeta[]) internal locksMeta;
  mapping(address => bool) locks;

  /**
    * @dev Lock tokens for the address
    * @param _address address The address you want to lock tokens
    * @param _days uint The days count you want to lock untill from now
    * @param _value uint256 the amount of tokens to be locked
    */
  function lock(address _address, uint _days, uint256 _value) onlyOwnerOrAdmin public {
    _value = _value*(10**decimals);
    require(_value > 0);
    require(_days > 0);
    require(_address != owner);
    require(_address != admin);

    uint untilTime = block.timestamp + _days * 1 days;
    locks[_address] = true;
    // check if we have locks
    locksMeta[_address].push(LockMeta(_value, untilTime));
    // fire lock event
    emit Lock(_address, untilTime, _value, locksMeta[_address].length);
  }

  /**
    * @dev Unlock tokens for the address
    * @param _address address The address you want to unlock tokens
    */
  function unlock(address _address) onlyOwnerOrAdmin public {
    locks[_address] = false;
    delete locksMeta[_address];
    emit UnLock(_address);
  }

  /**
    * @dev Gets the locked balance of the specified address and time
    * @param _owner The address to query the locked balance of.
    * @param _time The timestamp seconds to query the locked balance of.
    * @return An uint256 representing the locked amount owned by the passed address.
    */
  function lockedBalanceOf(address _owner, uint _time) public view returns (uint256) {
    LockMeta[] memory locked = locksMeta[_owner];
    uint length = locked.length;
    // if no locks or even not created (takes bdefault) return 0
    if (length == 0) {
      return 0;
    }
    // sum all available locks
    uint256 _result = 0;
    for (uint i = 0; i < length; i++) {
      if (_time <= locked[i].until) {
        _result = _result.add(locked[i].value);
      }
    }
    return _result;
  }

  /**
    * @dev Gets the locked balance of the specified address of the current time
    * @param _owner The address to query the locked balance of.
    * @return An uint256 representing the locked amount owned by the passed address.
    */
  function lockedNowBalanceOf(address _owner) public view returns (uint256) {
    return this.lockedBalanceOf(_owner, block.timestamp);
  }

  /**
    * @dev Gets the unlocked balance of the specified address and time
    * @param _owner The address to query the unlocked balance of.
    * @param _time The timestamp seconds to query the unlocked balance of.
    * @return An uint256 representing the unlocked amount owned by the passed address.
    */
  function unlockedBalanceOf(address _owner, uint _time) public view returns (uint256) {
    return this.balanceOf(_owner).sub(lockedBalanceOf(_owner, _time));
  }

  /**
    * @dev Gets the unlocked balance of the specified address of the current time
    * @param _owner The address to query the unlocked balance of.
    * @return An uint256 representing the unlocked amount owned by the passed address.
    */
  function unlockedNowBalanceOf(address _owner) public view returns (uint256) {
    return this.unlockedBalanceOf(_owner, block.timestamp);
  }

  function updateGlobalUnlockTime(uint256 _epoch) public onlyOwnerOrAdmin returns (bool) {
    require(_epoch >= 0);
    globalUnlockTime = _epoch;
    emit UpdateGlobalUnlockTime(_epoch);
    // Gives owner the ability to update lockup period for all wallets.
    // Owner can pass an epoch timecode into the function to:
    // 1. Extend lockup period,
    // 2. Unlock all wallets by passing '0' into the function
  }

  /**
    * @dev Throws if the value less than the current unlocked balance of.
    */
  modifier onlyUnlocked(uint256 _value) {
    if(block.timestamp > globalUnlockTime) {
      _;
    } else {
      if (locks[msg.sender] == true) {
        require(this.unlockedNowBalanceOf(msg.sender) >= _value);
      }
      _;
    }
  }

  /**
    * @dev Throws if the value less than the current unlocked balance of the given address.
    */
  modifier onlyUnlockedOf(address _address, uint256 _value) {
    if(block.timestamp > globalUnlockTime) {
      _;
    } else {
      if (locks[_address] == true) {
        require(this.unlockedNowBalanceOf(_address) >= _value);
      } else {

      }
      _;
    }
  }
}
/**
 * @title Lockable
 * @dev The Lockable contract has an locks address map, and provides lockable control
 * functions, this simplifies the implementation of "lock transfers".
 *
 * The contents of this Smart Contract and all associated code is owned and operated by Rubiix, a Gibraltar company in formation.
 */
function lockedNowBalanceOf(address _owner) public view returns (uint256) {
  return this.lockedBalanceOf(_owner, block.timestamp);
}

/**
 * @dev Gets the locked balance of the specified address of the current time
 * @param _owner The address to query the locked balance of.
 * @return An uint256 representing the locked amount owned by the passed address.
 */