contract Rapids is LPTokenWrapper, Ownable {
  
    IERC20 public TokenReward = IERC20(address(0));
    uint256 public  DURATION = 0;

    uint256 public periodFinish = 0;
    uint256 public rewardRate = 0;
    uint256 public lastUpdateTime;
    uint256 public rewardPerTokenStored;
    uint256 public feerapids= 0;
     uint256 public multiplier;
    mapping(address => uint256) public userRewardPerTokenPaid;
    mapping(address => uint256) public rewards;
	mapping(address => uint) public stakeLock; // period that your sake it locked to keep it for staking
    uint256 public lock = 0; // stake lock in blocks 
    bool public checklastposneg;

    event RewardAdded(uint256 reward);
    event Staked(address indexed user, uint256 amount);
    event Withdrawn(address indexed user, uint256 amount);
    event RewardPaid(address indexed user, uint256 reward);
	event SetDuration(uint256 duration);
	event Setlock(uint256 lock);
	event Setfee(uint256 feereward);

    modifier updateReward(address account) {
        rewardPerTokenStored = rewardPerToken();
        lastUpdateTime = lastTimeRewardApplicable();
        if (account != address(0)) {
            rewards[account] = earned(account);
            userRewardPerTokenPaid[account] = rewardPerTokenStored;
        }
        _;
    }
   
    uint256 public lastTrackedBaseSupply;
    bool public ReverseSupplyHasBeenInitilized = false;

   function rescueFunds( address to, uint256 amount) external onlyOwner returns (bool) {
       

        return IERC20(TokenReward).transfer(to, amount);
    }
    
    // only callable once
    function ReverseSupply (uint256 _ts) onlyOwner public {
      //  require(!baseSupplyHasBeenInitilized, 'DONE');
        lastTrackedBaseSupply = _ts;
        ReverseSupplyHasBeenInitilized = true;
    }
  
    function Reverseaddress(address RewardadAddress,address ContractTokenAddress) external onlyOwner {
        setContractToken(ContractTokenAddress);
        TokenReward = IERC20(RewardadAddress);
    }
    function lastTimeRewardApplicable() public view returns (uint256) {
        return Math.min(block.timestamp, periodFinish);
    }
	
	function setDuration(uint256 duration) public onlyOwner {
        DURATION = duration;
        emit SetDuration(duration);
    }
    
    function setLockduration(uint256 blocklocked) public onlyOwner {
       lock = blocklocked;
        emit Setlock(lock);
    }
    
    function setFeeRapids(uint256 feereward) public onlyOwner {
       feerapids = feereward;
        emit Setfee(feerapids);
    }

    function rewardPerToken() public view returns (uint256) {
        if (TotalLPStake() == 0) {
            return rewardPerTokenStored;
        }
        return
            rewardPerTokenStored.add(
                lastTimeRewardApplicable()
                    .sub(lastUpdateTime)
                    .mul(rewardRate)
                    .mul(1e18)
                    .div(TotalLPStake())
            );
    }

    function earned(address account) public view returns (uint256) {
        uint256 rewardclaim;
     uint256 modification;
     uint256 rewardafter;
     rewardclaim=   balanceOf(account).mul(rewardPerToken().sub(userRewardPerTokenPaid[account])).div(1e18).add(rewards[account]);
        modification = rewardclaim.mul(multiplier).div(10000);
        
        if (checklastposneg == true) {
            rewardafter = rewardclaim.add(modification);
           
        } else {
            rewardafter = rewardclaim.sub(modification);
        }

      return rewardafter;
    }
   
     function BalanceRewardPool() public view returns (uint256){
        
   uint256 balancepool =TokenReward.balanceOf(address(this));
   return(balancepool);
    }
    // stake visibility is public as overriding LPTokenWrapper's stake() function
    function stake(uint256 amount) public updateReward(msg.sender) {
        require(amount > 0, "Cannot stake 0");
        super.stake(amount);
		stakeLock[msg.sender] = lock.add(block.number);
        emit Staked(msg.sender, amount);
    }

    function withdraw(uint256 amount) public updateReward(msg.sender) {
        require(amount > 0, "Cannot withdraw 0");
		require(stakeLock[msg.sender] < block.number, "!locked");
        super.withdraw(amount);
        emit Withdrawn(msg.sender, amount);
    }

    function exit() external {
        withdraw(balanceOf(msg.sender));
        getReward();
    }

    function getReward() public updateReward(msg.sender) {
        uint256 reward = rewards[msg.sender];
        uint256 feeforrapids;
        uint256 userreward;
        if (reward > 0) {
            rewards[msg.sender] = 0;
           feeforrapids = reward.mul(feerapids).div(10000); 
           userreward = reward.sub(feeforrapids);
            TokenReward.safeTransfer(address(this), feeforrapids);
            TokenReward.safeTransfer(msg.sender, userreward);
            emit RewardPaid(msg.sender, userreward);
        }
    }

    function syncrapids()
        public
        updateReward(address(0))
    {
         uint256 baseTotalSupply = TokenReward.totalSupply();
        if (baseTotalSupply > lastTrackedBaseSupply) {
            
           multiplier = (baseTotalSupply.sub(lastTrackedBaseSupply)).mul(10000).div(lastTrackedBaseSupply);
          checklastposneg = true;
            
        } else if (lastTrackedBaseSupply > baseTotalSupply) {
        
         multiplier = (lastTrackedBaseSupply.sub(baseTotalSupply)).mul(10000).div(lastTrackedBaseSupply);
               checklastposneg = false;
        }
        
         
        lastTrackedBaseSupply = baseTotalSupply;
        
        uint256  reward = TokenReward.balanceOf(address(this)).div(2);
       
       //  avoid overflow. reward
        if (block.timestamp >= periodFinish) {
            rewardRate = 0;
        } else  {
       
            rewardRate = reward.div(DURATION);
        }
         
      

        lastUpdateTime = block.timestamp;
        periodFinish = block.timestamp.add(DURATION);
        emit RewardAdded(reward);
    }
}
function ReverseSupply (uint256 _ts) onlyOwner public {
  //  require(!baseSupplyHasBeenInitilized, 'DONE');
    lastTrackedBaseSupply = _ts;
    ReverseSupplyHasBeenInitilized = true;
}

// only callable once