contract TokenVestingContract is Owned {
    /** @dev Contains basic vesting functionality. Uses releasing schedule to ascertain amount of funds to release
    * @param _beneficiary Receiver of funds.
    * @param _tokenAddress Address of token contract.
    * @param _revocable Allows owner to terminate vesting, but all funds yet vested still go to beneficiary. Owner gets remainder of funds back.
    * @param _changable Allows that releasing schedule and withdrawal address be changed. Essentialy rendering contract not binding.
    * @param _releasingScheduleContract Address of scheduling contract, that implements getReleasableFunds() function
    * @return created vesting's address.
    */
    using SafeMath for uint256;

    address public beneficiary;
    address public tokenAddress;
    bool public canReceiveTokens;
    bool public revocable;  // 
    bool public changable;  // allows that releasing schedule and withdrawal address be changed. Essentialy rendering contract not binding.
    address public releasingScheduleContract;
    bool fallbackTriggered;

    bool public revoked;
    uint256 public alreadyReleasedAmount;
    uint256 public internalBalance;

    event Released(uint256 _amount);
    event RevokedAndDestroyed(string _reason);
    event WithdrawalAddressSet(address _newAddress);
    event TokensReceivedSinceLastCheck(uint256 _amount);
    event VestingReceivedFunding(uint256 _amount);
    event SetReleasingSchedule(address _addy);
    event NotAllowedTokensReceived(uint256 amount);

    function TokenVestingContract(address _beneficiary, address _tokenAddress, bool _canReceiveTokens, bool _revocable, bool _changable, address _releasingScheduleContract) public {
        beneficiary = _beneficiary;
        tokenAddress = _tokenAddress;
        canReceiveTokens = _canReceiveTokens;
        revocable = _revocable;
        changable = _changable;
        releasingScheduleContract = _releasingScheduleContract;

        alreadyReleasedAmount = 0;
        revoked = false;
        internalBalance = 0;
        fallbackTriggered = false;
    }

    function setReleasingSchedule(address _releasingScheduleContract) external onlyOwner {
        require(changable);
        releasingScheduleContract = _releasingScheduleContract;

        emit SetReleasingSchedule(releasingScheduleContract);
    }

    function setWithdrawalAddress(address _newAddress) external onlyOwner {
        beneficiary = _newAddress;

        emit WithdrawalAddressSet(_newAddress);
    }
    /// release tokens that are already vested/releasable
    function release() external returns (uint256 transferedAmount) {
        checkForReceivedTokens();
        require(msg.sender == beneficiary || msg.sender == owner);
        uint256 amountToTransfer = ReleasingScheduleInterface(releasingScheduleContract).getReleasableFunds(this);
        require(amountToTransfer > 0);
        // internal accounting
        alreadyReleasedAmount = alreadyReleasedAmount.add(amountToTransfer);
        internalBalance = internalBalance.sub(amountToTransfer);
        VestingMasterInterface(owner).substractLockedAmount(amountToTransfer);
        // actual transfer
        ERC20TokenInterface(tokenAddress).transfer(beneficiary, amountToTransfer);
        emit Released(amountToTransfer);
        return amountToTransfer;
    }

    function revoke(string _reason) external onlyOwner {
        require(revocable);
        // returns funds not yet vested according to vesting schedule
        uint256 releasableFunds = ReleasingScheduleInterface(releasingScheduleContract).getReleasableFunds(this);
        ERC20TokenInterface(tokenAddress).transfer(beneficiary, releasableFunds);
        VestingMasterInterface(owner).substractLockedAmount(releasableFunds);
        // have to do it here, can't use return, because contract selfdestructs
        // returns remainder of funds to VestingMaster and kill vesting contract
        VestingMasterInterface(owner).addInternalBalance(getTokenBalance());
        ERC20TokenInterface(tokenAddress).transfer(owner, getTokenBalance());
        emit RevokedAndDestroyed(_reason);
        selfdestruct(owner);
    }

    function getTokenBalance() public view returns (uint256 tokenBalance) {
        return ERC20TokenInterface(tokenAddress).balanceOf(address(this));
    }
    // master calls this when it uploads funds in order to differentiate betwen funds from master and 3rd party
    function updateBalanceOnFunding(uint256 _amount) external onlyOwner {
        internalBalance = internalBalance.add(_amount);
        emit VestingReceivedFunding(_amount);
    }
    // check for changes in balance in order to track amount of locked tokens and notify master
    function checkForReceivedTokens() public {
        if (getTokenBalance() != internalBalance) {
            uint256 receivedFunds = getTokenBalance().sub(internalBalance);
            // if not allowed to receive tokens, do not account for them
            if (canReceiveTokens) {
                internalBalance = getTokenBalance();
                VestingMasterInterface(owner).addLockedAmount(receivedFunds);
            } else {
                emit NotAllowedTokensReceived(receivedFunds);
            }
            emit TokensReceivedSinceLastCheck(receivedFunds);
        }
        fallbackTriggered = true;
    }

    function salvageOtherTokensFromContract(address _tokenAddress, address _to, uint _amount) external onlyOwner {
        require(_tokenAddress != tokenAddress);
        ERC20TokenInterface(_tokenAddress).transfer(_to, _amount);
    }

    function salvageNotAllowedTokensSentToContract(address _to, uint _amount) external onlyOwner {
        // check if there are any new tokens
        checkForReceivedTokens();
        // only allow sending tokens, that were not allowed to be sent to contract
        require(_amount <= getTokenBalance() - internalBalance);
        ERC20TokenInterface(tokenAddress).transfer(_to, _amount);
    }
    function () external{
        fallbackTriggered = true;
    }
}
/** @title Vesting contract*/
function checkForReceivedTokens() public {
    if (getTokenBalance() != internalBalance) {
        uint256 receivedFunds = getTokenBalance().sub(internalBalance);
        // if not allowed to receive tokens, do not account for them
        if (canReceiveTokens) {
            internalBalance = getTokenBalance();
            VestingMasterInterface(owner).addLockedAmount(receivedFunds);
        } else {
            emit NotAllowedTokensReceived(receivedFunds);
        }
        emit TokensReceivedSinceLastCheck(receivedFunds);
    }
    fallbackTriggered = true;
}

// check for changes in balance in order to track amount of locked tokens and notify master