contract TokenVault is Ownable {
    using SafeMath for uint;

    // Modifier that requires the teams tokens to be unlocked
    modifier teamTokensUnlocked() {
        require((block.timestamp > teamUnlockTime) && teamUnlockTime > 0, "Team's tokens are still locked");
        _;
    }

    // Modifier that requires the reward tokens to be unlocked
    modifier rewardTokensUnlocked() {
        require((block.timestamp > rewardUnlockTime) && rewardUnlockTime > 0, "Team's tokens are still locked");
        _;
    }

    // Modifier that requires funding to not yet be active
    modifier lockNotActive() {
        require(teamUnlockTime == 0, "Unlock time already started");
        _;
    }

    // Start time of lock
    uint public startTime;

    // Team related variables
    uint public teamTokens;
    uint public teamUnlockTime;
    uint public teamLockLength;
    bool public teamWithdraw;

    // Reward related variables
    uint public rewardTokens;
    uint public rewardUnlockTime;
    uint public rewardLockLength;
    bool public rewardWithdraw;

    // Variable that will store the token contract
    NFY public token;

    // Variable that will keep track of the contract address
    address public contractAddress = address(this);

    event AmountOfTeamTokens(uint _teamTokens);

    event TeamWithdraw(uint _tokensSent, address _receiver);

    event RewardTokensTransferred(address _sentTo, uint _amount);


    // Constructor will set:
    // The address of token
    // The tokens allotted to team
    // team lock length
    // reward tokens
    // reward tokens lock length
    constructor( address _tokenAddress, uint _teamTokens, uint _teamLockLength, uint _rewardTokens, uint _rewardLockLength) Ownable() public {
        // Variable 'token' is the address of token being sold
        token = NFY(_tokenAddress);

        // Set the amount of tokens the team will receive
        teamTokens = _teamTokens;

        // Set the length the team's tokens will be locked
        teamLockLength = _teamLockLength;

        // Set reward tokens delegated
        rewardTokens = _rewardTokens;

        // Set length reward tokens will be locked
        rewardLockLength = _rewardLockLength;

        emit AmountOfTeamTokens(_teamTokens);
    }


    // Call function to start the lock time.. Once called timer will start
    function startLock() external onlyOwner() lockNotActive() {
        startTime = block.timestamp;

        // Variable set to the current timestamp of block + length of team's tokens locked
        teamUnlockTime = block.timestamp.add(teamLockLength);

        // Variable set to the current timestamp of block + length of reward's tokens locked
        rewardUnlockTime = block.timestamp.add(rewardLockLength);

    }

    // Function that will allow the team to withdraw their tokens
    function withdrawTeamTokens() external onlyOwner() teamTokensUnlocked() {

        // Require that team has not withdrawn their tokens
        require(teamWithdraw == false, "Team has withdrawn their tokens");

        // Transfer team tokens to msg.sender (owner)
        token.transfer(_msgSender(), teamTokens);

        // Set bool that tracks if team has withdrawn tokens to true
        teamWithdraw = true;

        // Emit event that confirms team has withdrawn their tokens
        emit TeamWithdraw(teamTokens, _msgSender());
    }

    // Transfer rewards tokens to vault once it is deployed
    function transferRewardTokens(address _to) public onlyOwner() rewardTokensUnlocked() {
        require(rewardTokens > 0, "Reward tokens already sent");

        uint _rewardTokens = rewardTokens;
        rewardTokens = 0;

        token.transfer(_to, _rewardTokens);
        emit RewardTokensTransferred(_to, _rewardTokens);
    }

}
// Contract that will keep track of funding and distribution for token sale
function withdrawTeamTokens() external onlyOwner() teamTokensUnlocked() {

    // Require that team has not withdrawn their tokens
    require(teamWithdraw == false, "Team has withdrawn their tokens");

    // Transfer team tokens to msg.sender (owner)
    token.transfer(_msgSender(), teamTokens);

    // Set bool that tracks if team has withdrawn tokens to true
    teamWithdraw = true;

    // Emit event that confirms team has withdrawn their tokens
    emit TeamWithdraw(teamTokens, _msgSender());
}

// Function that will allow the team to withdraw their tokens