contract DEFOEWFPools is UniswapOracle, Ownable, ReentrancyGuard {
	using SafeMath for uint256;
	using SafeERC20 for IERC20;
	
	// The Uniswap v2 Router
    IUniswapV2Router02 internal uniswapRouter = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
		
	
	address private devAddress; // Dev Address
	
	uint256 public LONGESTFARMINGPOOLTIME; // Longest Farming pool time
	uint256 public LONGESTSTAKINGPOOLTIME; // Longest Staking pool time
	uint256 public LONGESTFARMINGPOOLID; // Longest Farming pool id
	uint256 public LONGESTSTAKINGPOOLID; // Longest Staking pool id
	uint256 public FARMPOOLCOUNT; // Farming pool Count
	uint256 public STAKINGPOOLCOUNT; // Staking pool Count
	uint256 public tokenCount;
	
	uint256 private _decimal = 18; //pool decimal
	uint256 private _decimalConverter = 10**18; //pool decimal converter
	uint256 private _divRate = 10000; // Using for div precentage rate
	
	// All pools will be available at any time (i.e. there will be no commencement date). 
	// Each investor can join the desired pool whenever he wants. 
	// The end of his lock-up period will be calculated automatically by the Smart Contract.
	// Moreover, each time a pool reaches the lock-up period of a faster pool, investorsâ€™ funds will be automatically transferred into the faster pool 
	// (in this case the EWF and rewards will automatically change to match those of the pool in which the tokens are transferred).
	
	// Info of each pool.
	struct PoolLists{
		bool is_farming; // true is farming pool, false is staking pool
		string pool_name; // Pool Name
		uint256 EWFTime; // Early Withdraw Fee Time limit in second
		uint256 EWFRate; // Early Withdraw Fee Rate with mul 10000
		uint256 totalUsers; // Total User Join
		uint256 activeAmount; // Total active amount
		uint256 overTimeAmount; // Total over time amount
		uint256 totalAmount; // Total amount
		uint256 activeDeposit; // total of active Farming deposit 
		uint256 depositCount; // total of Farming deposit 
		uint256 depositIndex; // last over time deposit index
		uint256 fasterPoolTime; // faster pool time
		uint256 fasterPoolId; // faster pool id
		uint256 pendingEWFReward; // Pending EWFReward
	}
	PoolLists[] public poolLists;
			
	// Info of active deposit .
	struct DepositList {
		address account; // User address
		uint256 amount; // amount of deposit
		uint256 timeStart; // Farming started 
		uint256 timeEnd; // Farming ended 
		bool is_active; // 1 = active deposite
		mapping(address => uint256)  tokenAmount;
	}
	mapping (uint256 => mapping (uint256 => DepositList)) public depositList;
	
	// Info of each user on pool.
	struct UserList {
		uint256 activeAmount; // active amount
        uint256 overTimeAmount; // over time amount
        uint256 totalAmount; // total amount
		uint256 pendingReward; // claimable reward 
		uint256 pendingRewardLP; // claimable reward 
        uint256 claimReward; // total claim DEFO reward
        uint256 claimRewardLP; // total claim LP token reward
		mapping(address => uint256)  tokenActiveAmount;
		mapping(address => uint256)  tokenOverTimeAmount;
    }
	
	mapping (uint256 => mapping (address => UserList)) public userList;
	mapping(uint => address[]) private poolDatas;
		
	struct PoolTemp {
		uint256 pid;
		uint256 poolCount;
		uint256 tokenAmount;
		uint256 depositAmount;
		uint256 defholdAmount;
		uint256 depositCount;
		address account;
		uint256 timeStart;
		uint256 timeEnd;
		uint256 amount;
		uint256 counter;
		uint256 counter2;
		uint256 counter3;
		uint256 fasterPoolTime;
		uint256 fasterPoolId;
		uint256 remainTime;
		uint256 pendingReward;
		uint256 pendingRewardLP;
		uint256 activeAmount;
		uint256 penaltyAmount;
		uint256 withdrawAmount;
		uint256 overTimeAmount;
		uint256 farmAmount;
		uint256 stakeAmount;
		uint256 farmRewardAmount;
		uint256 stakeRewardAmount;
		uint256 devRewardAmount;
		uint256 farmUsers;
		uint256 stakeUsers;
		uint256 totalAmount;
		uint256 rewardShare;
		uint256 rewardAmount;
		uint256 pendingEWFReward;
		uint256 tokenDecimal;
		uint256 decimalDiff;
		uint256 decimalDiffConverter;
		uint256 beforeTransaction;
		uint256 afterTransaction;
		uint256 swapAmount;
		uint256 tokenPriceRate;
		uint256 tokenPrice;
		uint256 amountChange;
		uint256 realTokenAmount;
		uint256 getAmountsOut;
		bool is_active;
		IERC20 tokenAddress;
	}
		
	constructor(address _defholdLP, address _defhold, address _devAddress, address _weth) public Ownable() {	
		defholdLP = IERC20(_defholdLP);
		defhold = IERC20(_defhold);
		weth = IERC20(_weth);
		devAddress = _devAddress;
		
		_initialPool();
	}
	
	function _initialPool() internal {
		_addPool(false, "1st Pool", 864000, 100);
		_addPool(false, "2nd Pool", 2592000, 350);
		_addPool(false, "3rd Pool", 5184000, 820);
		_addPool(false, "4th Pool", 7776000, 1430);
		_addPool(false, "5th Pool", 15552000, 3330);
		
		_addPool(true, "1st Pool", 864000, 200);
		_addPool(true, "2nd Pool", 2592000, 700);
		_addPool(true, "3rd Pool", 5184000, 1630);
		_addPool(true, "4th Pool", 7776000, 2860);
		_addPool(true, "5th Pool", 15552000, 6660);
		
		_updateToken(address(defholdLP), true);
		_updateToken(address(defhold), true);
	}
	
	function _addPool(bool _is_farming, string memory _pool_name, uint256 _EWFTime, uint256 _EWFRate) internal {
		PoolTemp memory temp;
		
		temp.poolCount = poolLists.length;
				
		if(_is_farming){
			if(FARMPOOLCOUNT == 0){
				temp.fasterPoolId = 5;
				temp.fasterPoolTime = 0;
			} else {
				temp.fasterPoolId = LONGESTFARMINGPOOLID;
				temp.fasterPoolTime = LONGESTFARMINGPOOLTIME;
			}
			
			FARMPOOLCOUNT += 1;
			LONGESTFARMINGPOOLID = temp.poolCount;
			LONGESTFARMINGPOOLTIME = _EWFTime;
		} else {
			if(STAKINGPOOLCOUNT == 0){
				temp.fasterPoolId = 0;
				temp.fasterPoolTime = 0;
			} else {
				temp.fasterPoolId = LONGESTSTAKINGPOOLID;
				temp.fasterPoolTime = LONGESTSTAKINGPOOLTIME;
			}
			
			STAKINGPOOLCOUNT += 1;
			LONGESTSTAKINGPOOLID = temp.poolCount;
			LONGESTSTAKINGPOOLTIME = _EWFTime;
		}
		
		poolLists.push(PoolLists(_is_farming, _pool_name, _EWFTime, _EWFRate, 0, 0, 0, 0, 0, 0, 0, temp.fasterPoolTime, temp.fasterPoolId, 0));
	}
	
	// function addPool(bool _is_farming, string calldata _pool_name, uint256 _EWFTime, uint256 _EWFRate) external onlyOwner {
		// _addPool(_is_farming, _pool_name, _EWFTime, _EWFRate);
	// }
	
	function updateToken(address tokenAddress, bool tokenStatus) external onlyOwner {
		_updateToken(tokenAddress, tokenStatus);
	}

	function _updateToken(address tokenAddress, bool tokenStatus) internal {
		if(existingToken[tokenAddress] != true){
			existingToken[tokenAddress] = true;
			tokenIndex[tokenAddress] = tokenCount;
			tokenCount += 1;
			
			tokenList.push(TokenList(tokenAddress, tokenStatus, 0, 0, 0));
			
			if(tokenAddress != address(defholdLP)){
				if(tokenAddress == address(defhold)){
					_updateDefoPrice();
				} else {
					_updateTokenPrice(tokenIndex[tokenAddress]);
				}
			}
		} else {
			tokenList[tokenIndex[tokenAddress]].tokenStatus = tokenStatus;
		}
	}
		
	 // Deposits in the specified pool to start
	function deposit(uint256 _pid, uint256 _amount, address tokenAddress) external nonReentrant {    
		PoolTemp memory temp;
		require(existingToken[tokenAddress], "Token not yet registered");
		//Check Deposit amount
		require(_amount > 0, "deposit something");
		//Check Pool
		uint256 countPool = poolLists.length;
		require(_pid < countPool, "Not a valid Pool");
		
		_updatePool(_pid);
			
		if(userList[_pid][msg.sender].totalAmount == 0){
			poolLists[_pid].totalUsers += 1;
			poolDatas[_pid].push(msg.sender);
		}
		
		if(poolLists[_pid].is_farming){
			defholdLP.safeTransferFrom(msg.sender, address(this), _amount);
			temp.depositAmount = _amount;
			temp.tokenAmount = _amount;
		} else {
			temp.beforeTransaction = IERC20(tokenAddress).balanceOf(address(this));
			IERC20(tokenAddress).safeTransferFrom(msg.sender, address(this), _getTokenAmount(address(tokenAddress), _amount));
			temp.afterTransaction = IERC20(tokenAddress).balanceOf(address(this));
			temp.tokenAmount = temp.afterTransaction - temp.beforeTransaction;
			temp.tokenAmount = _getReverseTokenAmount(address(tokenAddress), temp.tokenAmount);
			
			if(address(tokenAddress) != address(defhold)){				
				_updateDefoPrice();
				_updateTokenPrice(tokenIndex[tokenAddress]);
				
				temp.swapAmount = _getTokenAmount(address(tokenAddress), temp.tokenAmount);
				temp.getAmountsOut = getAmountOut(tokenIndex[tokenAddress], temp.swapAmount);
				temp.depositAmount = _getReverseTokenAmount(address(defhold), temp.getAmountsOut);	
			} else {
				temp.depositAmount = _amount;
			}
		}
						
		temp.timeStart = now;
		temp.timeEnd = now + poolLists[_pid].EWFTime;
		temp.depositCount = poolLists[_pid].depositCount;
		
		tokenList[tokenIndex[tokenAddress]].totalAmount += temp.tokenAmount;
		userList[_pid][msg.sender].tokenActiveAmount[tokenAddress] += temp.tokenAmount;
		depositList[_pid][temp.depositCount].tokenAmount[tokenAddress] = temp.tokenAmount;
		
		depositList[_pid][temp.depositCount].account = msg.sender;
		depositList[_pid][temp.depositCount].timeStart = temp.timeStart;
		depositList[_pid][temp.depositCount].timeEnd = temp.timeEnd;
		depositList[_pid][temp.depositCount].amount = temp.depositAmount;
		depositList[_pid][temp.depositCount].is_active = true;
				
		poolLists[_pid].activeDeposit += 1;
		poolLists[_pid].depositCount += 1;
		poolLists[_pid].totalAmount += temp.depositAmount;
		poolLists[_pid].activeAmount += temp.depositAmount;
		
		temp.pendingEWFReward = poolLists[_pid].pendingEWFReward;
		
		userList[_pid][msg.sender].activeAmount += temp.depositAmount;
		userList[_pid][msg.sender].totalAmount += temp.depositAmount;
		if(temp.pendingEWFReward > 0){
			poolLists[_pid].pendingEWFReward = 0;
			EWFReward(_pid, temp.pendingEWFReward);
		}
		emit Deposit(msg.sender, _pid, temp.timeStart, temp.timeEnd ,temp.depositAmount);
	}
		
	function _updatePool(uint256 _pid) internal {
		PoolTemp memory temp;
		
		temp.fasterPoolTime = poolLists[_pid].fasterPoolTime;
		temp.fasterPoolId = poolLists[_pid].fasterPoolId;
		
		if(poolLists[_pid].activeDeposit > 0){
			for(temp.counter = poolLists[_pid].depositIndex; temp.counter < poolLists[_pid].depositCount;temp.counter++){
				temp.is_active = depositList[_pid][temp.counter].is_active;
				temp.remainTime = 0;
				
				if(temp.is_active){
					temp.account = depositList[_pid][temp.counter].account;
					temp.timeStart = depositList[_pid][temp.counter].timeStart;
					temp.timeEnd = depositList[_pid][temp.counter].timeEnd;
					temp.amount = depositList[_pid][temp.counter].amount;
					
					if(temp.timeEnd > now){
						temp.remainTime = temp.timeEnd - now;
					}
					
					if(temp.fasterPoolTime >= temp.remainTime){
						poolLists[_pid].activeDeposit -= 1;
						poolLists[_pid].depositIndex = temp.counter + 1;
						poolLists[_pid].activeAmount -= temp.amount;
						
						delete depositList[_pid][temp.counter];
						
						if(_pid == temp.fasterPoolId){
							poolLists[_pid].overTimeAmount += temp.amount;
							userList[_pid][temp.account].overTimeAmount += temp.amount;
							userList[_pid][temp.account].activeAmount -= temp.amount;
							
								for(temp.counter2 = 0; temp.counter2 < tokenCount; temp.counter2++){
									temp.tokenAmount = depositList[_pid][temp.counter].tokenAmount[tokenList[temp.counter2].token];

									userList[_pid][msg.sender].tokenActiveAmount[tokenList[temp.counter2].token] -= temp.tokenAmount;
									userList[_pid][msg.sender].tokenOverTimeAmount[tokenList[temp.counter2].token] += temp.tokenAmount;
								}
								
						} else {
							
							temp.pendingReward = userList[_pid][temp.account].pendingReward;	
							temp.pendingRewardLP = userList[_pid][temp.account].pendingRewardLP;	
							
							poolLists[_pid].totalAmount -= temp.amount;
							userList[_pid][temp.account].activeAmount -= temp.amount;						
							userList[_pid][temp.account].totalAmount -= temp.amount;						
							userList[_pid][temp.account].pendingReward -= temp.pendingReward;
							userList[_pid][temp.account].pendingRewardLP -= temp.pendingRewardLP;
							
							if(userList[_pid][temp.account].totalAmount == 0){
								poolLists[_pid].totalUsers -= 1;
								if(poolLists[_pid].totalUsers  > 0){
									for(uint256 i = 0; i < poolDatas[_pid].length; i++) {
										if(poolDatas[_pid][i] == msg.sender){
											delete poolDatas[_pid][i];
											i = poolDatas[_pid].length;
										}
									}
								} else {
									delete poolDatas[_pid];
								}			
							}
							
							temp.depositCount = poolLists[temp.fasterPoolId].depositCount;
							
							if(userList[temp.fasterPoolId][temp.account].totalAmount == 0){
								poolLists[temp.fasterPoolId].totalUsers += 1;
								poolDatas[temp.fasterPoolId].push(temp.account);
							}
							
							poolLists[temp.fasterPoolId].activeDeposit += 1;
							poolLists[temp.fasterPoolId].depositCount += 1;
							poolLists[temp.fasterPoolId].totalAmount += temp.amount;
							poolLists[temp.fasterPoolId].activeAmount += temp.amount;
							
							depositList[temp.fasterPoolId][temp.depositCount].account = temp.account;
							depositList[temp.fasterPoolId][temp.depositCount].timeStart = temp.timeStart;
							depositList[temp.fasterPoolId][temp.depositCount].timeEnd = temp.timeEnd;
							depositList[temp.fasterPoolId][temp.depositCount].amount = temp.amount;
							depositList[temp.fasterPoolId][temp.depositCount].is_active = true;
							
							for(temp.counter2 = 0; temp.counter2 < tokenCount; temp.counter2++){
								temp.tokenAmount = depositList[_pid][temp.counter].tokenAmount[tokenList[temp.counter2].token];
								depositList[temp.fasterPoolId][temp.depositCount].tokenAmount[tokenList[temp.counter2].token] = temp.tokenAmount;
								
								userList[_pid][msg.sender].tokenActiveAmount[tokenList[temp.counter2].token] -= temp.tokenAmount;
								userList[temp.fasterPoolId][msg.sender].tokenActiveAmount[tokenList[temp.counter2].token] += temp.tokenAmount;
							}
							
							userList[temp.fasterPoolId][temp.account].activeAmount += temp.amount;
							userList[temp.fasterPoolId][temp.account].totalAmount += temp.amount;
							userList[temp.fasterPoolId][temp.account].pendingReward += temp.pendingReward;
							userList[temp.fasterPoolId][temp.account].pendingRewardLP += temp.pendingRewardLP;
						
						}
					}
				}
			}
		}
	}
		
	function TotalPool() public view returns (uint256) {
		return poolLists.length;
	}
		
	function UserTokenAmount(uint256 _pid, address _user, uint256 _tokenIndex) public view returns (
		uint256 tokenActiveAmount,
		uint256 tokenOverTimeAmount
	) {
		
		return (
			userList[_pid][_user].tokenActiveAmount[tokenList[_tokenIndex].token],
			userList[_pid][_user].tokenOverTimeAmount[tokenList[_tokenIndex].token]
		);
	}
	
	function percent(uint numerator, uint denominator, uint precision) internal pure returns(uint quotient) {
		uint _numerator  = numerator * 10 ** (precision+1);
		uint _quotient =  ((_numerator / denominator) + 5) / 10;
		return ( _quotient);
	}
	
	function claim() public nonReentrant {	
		PoolTemp memory temp;
		
		for(temp.counter = poolLists.length; temp.counter > 0;temp.counter--){
			temp.pid = temp.counter - 1;
			_updatePool(temp.pid);
		}
		
		_claim();
	}
	
	function _claim() internal {
		PoolTemp memory temp;
		
		temp.pendingReward = 0;
		temp.pendingRewardLP = 0;
		for(temp.counter = 0; temp.counter < poolLists.length;temp.counter++){
			temp.pendingReward += userList[temp.counter][msg.sender].pendingReward;
			temp.pendingRewardLP += userList[temp.counter][msg.sender].pendingRewardLP;
			
			userList[temp.counter][msg.sender].claimReward += userList[temp.counter][msg.sender].pendingReward;
			userList[temp.counter][msg.sender].pendingReward = 0;
			
			userList[temp.counter][msg.sender].claimRewardLP += userList[temp.counter][msg.sender].pendingRewardLP;
			userList[temp.counter][msg.sender].pendingRewardLP = 0;
		}
		
		if(temp.pendingReward > 0){
			defhold.safeTransfer(msg.sender, temp.pendingReward);
			emit ClaimReward(msg.sender, temp.pendingReward);
		}
		
		if(temp.pendingRewardLP > 0){
			defholdLP.safeTransfer(msg.sender, temp.pendingRewardLP);
			emit ClaimReward(msg.sender, temp.pendingRewardLP);
		}		
	}
	
	function withdraw(uint256 _pid) public nonReentrant {
		PoolTemp memory temp;
		
		uint256 countPool = poolLists.length;
		require(_pid < countPool, "Not a valid Pool");
		require(userList[_pid][msg.sender].totalAmount > 0, "not have withdrawn balance");
			
		_updatePool(_pid);
		_claim();
		
		temp.activeAmount = userList[_pid][msg.sender].activeAmount;		
		temp.totalAmount = userList[_pid][msg.sender].totalAmount;		
		temp.overTimeAmount = userList[_pid][msg.sender].overTimeAmount;		
		
		if(temp.overTimeAmount > 0){
			for(temp.counter2 = 0; temp.counter2 < tokenCount; temp.counter2++){
				temp.withdrawAmount = userList[_pid][msg.sender].tokenOverTimeAmount[tokenList[temp.counter2].token];
				
				if(temp.withdrawAmount > 0){
					userList[_pid][msg.sender].tokenOverTimeAmount[tokenList[temp.counter2].token] -= temp.withdrawAmount;

					if(poolLists[_pid].is_farming){
						defholdLP.safeTransfer(msg.sender, temp.withdrawAmount);
					} else {
						temp.withdrawAmount = _getTokenAmount(address(tokenList[temp.counter2].token), temp.withdrawAmount);
						IERC20(tokenList[temp.counter2].token).safeTransfer(msg.sender, temp.withdrawAmount);
						temp.withdrawAmount = _getReverseTokenAmount(address(tokenList[temp.counter2].token), temp.withdrawAmount);
					}
					tokenList[temp.counter2].totalAmount -= temp.withdrawAmount;
					emit Withdraw(msg.sender, _pid ,temp.withdrawAmount);
				}
					
			}
		}
				
		if(temp.activeAmount > 0){
			uint256 deadline = block.timestamp + 5 minutes;		
			address[] memory uniswapPath;
		
			for(temp.counter2 = 0; temp.counter2 < tokenCount; temp.counter2++){
				temp.tokenAmount = userList[_pid][msg.sender].tokenActiveAmount[tokenList[temp.counter2].token];
				temp.withdrawAmount = temp.tokenAmount;
									
				if(temp.withdrawAmount > 0){
					if(poolLists[_pid].is_farming){
						temp.penaltyAmount = (temp.withdrawAmount * poolLists[_pid].EWFRate) / _divRate;
						temp.withdrawAmount -= temp.penaltyAmount;
						defholdLP.safeTransfer(msg.sender, temp.withdrawAmount);
					} else {
						temp.realTokenAmount = IERC20(tokenList[temp.counter2].token).balanceOf(address(this));
						temp.amountChange = percent(tokenList[temp.counter2].totalAmount, _getReverseTokenAmount(tokenList[temp.counter2].token, temp.realTokenAmount), 4);
						temp.withdrawAmount = temp.withdrawAmount * temp.amountChange / _divRate;
						temp.swapAmount = (temp.withdrawAmount * poolLists[_pid].EWFRate) / _divRate;
						temp.withdrawAmount -= temp.swapAmount;
						temp.withdrawAmount = _getTokenAmount(address(tokenList[temp.counter2].token), temp.withdrawAmount);
						IERC20(tokenList[temp.counter2].token).safeTransfer(msg.sender, temp.withdrawAmount);
						
						if(address(tokenList[temp.counter2].token) != address(defhold)){
							temp.beforeTransaction = defhold.balanceOf(address(this));
							temp.swapAmount = _getTokenAmount(address(tokenList[temp.counter2].token), temp.swapAmount);
							
							uniswapPath = new address[](3);
							uniswapPath[0] = address(tokenList[temp.counter2].token);
							uniswapPath[1] = address(weth);
							uniswapPath[2] = address(defhold);
							IERC20(tokenList[temp.counter2].token).safeApprove(address(uniswapRouter), 0);
							IERC20(tokenList[temp.counter2].token).safeApprove(address(uniswapRouter), temp.swapAmount);
							uniswapRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(temp.swapAmount, 0, uniswapPath, address(this), deadline);
							
							temp.afterTransaction = defhold.balanceOf(address(this));
							temp.penaltyAmount = _getReverseTokenAmount(address(defhold), temp.afterTransaction - temp.beforeTransaction);

						} else {
							temp.penaltyAmount = temp.swapAmount;
						}
					}
					userList[_pid][msg.sender].tokenActiveAmount[tokenList[temp.counter2].token] -= temp.tokenAmount;
					tokenList[temp.counter2].totalAmount -= temp.tokenAmount;
					emit Withdraw(msg.sender, _pid ,temp.withdrawAmount);	
					emit PenaltyFee(msg.sender, _pid, poolLists[_pid].EWFRate, temp.penaltyAmount);
					EWFReward(_pid, temp.penaltyAmount);
				}				
			}
		}
		
		for(temp.counter = poolLists[_pid].depositIndex; temp.counter < poolLists[_pid].depositCount;temp.counter++){
			temp.account = depositList[_pid][temp.counter].account;
			temp.is_active = depositList[_pid][temp.counter].is_active;
			temp.remainTime = 0;
			
			if(temp.is_active){
				if(temp.account == msg.sender){
					delete depositList[_pid][temp.counter];
					poolLists[_pid].activeDeposit -= 1;
				}
			}
		}
		
		userList[_pid][msg.sender].activeAmount -= temp.activeAmount;
		userList[_pid][msg.sender].totalAmount -= temp.totalAmount;
		userList[_pid][msg.sender].overTimeAmount -= temp.overTimeAmount;
				
		poolLists[_pid].activeAmount -= temp.activeAmount;
		poolLists[_pid].totalAmount -= temp.totalAmount;
		poolLists[_pid].overTimeAmount -= temp.overTimeAmount;
		
		if(userList[_pid][temp.account].totalAmount == 0){
			poolLists[_pid].totalUsers -= 1;
			if(poolLists[_pid].totalUsers  > 0){
				for(uint256 i = 0; i < poolDatas[_pid].length; i++) {
					if(poolDatas[_pid][i] == msg.sender){
						delete poolDatas[_pid][i];
						i = poolDatas[_pid].length;
					}
				}
			} else {
				delete poolDatas[_pid];
			}			
		}
	}
		
	function withdrawOverTime(uint256 _pid) public nonReentrant {
		PoolTemp memory temp;
		
		uint256 countPool = poolLists.length;
		require(_pid < countPool, "Not a valid Pool");
		require(userList[_pid][msg.sender].overTimeAmount > 0, "not have withdrawn balance");
			
		_updatePool(_pid);
		_claim();
		
		temp.overTimeAmount = userList[_pid][msg.sender].overTimeAmount;
		if(temp.overTimeAmount > 0){
			for(temp.counter2 = 0; temp.counter2 < tokenCount; temp.counter2++){
				temp.withdrawAmount = userList[_pid][msg.sender].tokenOverTimeAmount[tokenList[temp.counter2].token];
				
				if(temp.withdrawAmount > 0){
					userList[_pid][msg.sender].tokenOverTimeAmount[tokenList[temp.counter2].token] -= temp.withdrawAmount;

					if(poolLists[_pid].is_farming){
						defholdLP.safeTransfer(msg.sender, temp.withdrawAmount);
					} else {
						temp.withdrawAmount = _getTokenAmount(address(tokenList[temp.counter2].token), temp.withdrawAmount);
						IERC20(tokenList[temp.counter2].token).safeTransfer(msg.sender, temp.withdrawAmount);
						temp.withdrawAmount = _getReverseTokenAmount(address(tokenList[temp.counter2].token), temp.withdrawAmount);
					}
					tokenList[temp.counter2].totalAmount -= temp.withdrawAmount;
					emit Withdraw(msg.sender, _pid ,temp.withdrawAmount);
				}
					
			}
			
			userList[_pid][msg.sender].totalAmount -= temp.overTimeAmount;
			userList[_pid][msg.sender].overTimeAmount -= temp.overTimeAmount;
					
			poolLists[_pid].totalAmount -= temp.overTimeAmount;
			poolLists[_pid].overTimeAmount -= temp.overTimeAmount;
		}
		
		for(temp.counter = poolLists[_pid].depositIndex; temp.counter < poolLists[_pid].depositCount;temp.counter++){
			temp.account = depositList[_pid][temp.counter].account;
			temp.is_active = depositList[_pid][temp.counter].is_active;
			temp.remainTime = 0;
			
			if(temp.is_active){
				if(temp.account == msg.sender){
					delete depositList[_pid][temp.counter];
					poolLists[_pid].activeDeposit -= 1;
				}
			}
		}
	}
	
	function EWFReward(uint _pid, uint256 _amount) internal {
		PoolTemp memory temp;
		
		if(poolLists[_pid].totalUsers > 0){
			for(temp.counter = 0; temp.counter < poolDatas[_pid].length;temp.counter++){
				temp.account = poolDatas[_pid][temp.counter];
				if(temp.account != address(0)){
					temp.rewardShare = percent(userList[_pid][temp.account].activeAmount, poolLists[_pid].activeAmount, 4);
					temp.rewardAmount = _amount * temp.rewardShare / _divRate;
					
					if(poolLists[_pid].is_farming){
						userList[_pid][temp.account].pendingRewardLP += temp.rewardAmount;
					} else {
						userList[_pid][temp.account].pendingReward += temp.rewardAmount;
					}
				}
			}	
		} else {
			poolLists[_pid].pendingEWFReward = _amount;
		}		
	}
	
	function externalReward(uint256 _amount) external nonReentrant {
		PoolTemp memory temp;
		
		defhold.safeTransferFrom(msg.sender, address(this), _amount);

		temp.farmRewardAmount = (_amount * 55) / 100; // 55% of reward supply
		temp.stakeRewardAmount = (_amount * 40) / 100; // 40% of reward supply
		temp.devRewardAmount = _amount - temp.farmRewardAmount - temp.stakeRewardAmount; // 5% of reward supply
		
		temp.farmAmount = 0;
		temp.stakeAmount = 0;
		
		temp.farmUsers = 0;
		temp.stakeUsers = 0;
		
		for(temp.counter = poolLists.length; temp.counter > 0;temp.counter--){
			temp.pid = temp.counter - 1;
			_updatePool(temp.pid);
			if(poolLists[temp.pid].is_farming){
				temp.farmAmount += poolLists[temp.pid].activeAmount;
				temp.farmUsers += poolLists[temp.pid].totalUsers;
			} else {
				temp.stakeAmount += poolLists[temp.pid].activeAmount;
				temp.stakeUsers += poolLists[temp.pid].totalUsers;
			}
		}
		
		if(temp.farmAmount == 0){
			temp.devRewardAmount += temp.farmRewardAmount;
			temp.farmRewardAmount = 0;
		}
		
		if(temp.stakeAmount == 0){
			temp.devRewardAmount += temp.stakeRewardAmount;
			temp.stakeRewardAmount = 0;
		}
		
		for(temp.counter = 0; temp.counter < poolLists.length;temp.counter++){
			for(temp.counter2 = 0; temp.counter2 < poolDatas[temp.counter].length;temp.counter2++){
				temp.account = poolDatas[temp.counter][temp.counter2];
				
				if(temp.account != address(0)){
					temp.activeAmount = userList[temp.counter][temp.account].activeAmount;
					if(temp.activeAmount > 0){
						if(poolLists[temp.counter].is_farming){
							if(temp.farmAmount > 0){
								temp.rewardShare = percent(userList[temp.counter][temp.account].activeAmount, temp.farmAmount, 4);
								temp.rewardAmount = temp.farmRewardAmount * temp.rewardShare / _divRate;
							}							
						} else {
							if(temp.stakeAmount > 0){
								temp.rewardShare = percent(userList[temp.counter][temp.account].activeAmount, temp.stakeAmount, 4);
								temp.rewardAmount = temp.stakeRewardAmount * temp.rewardShare / _divRate;
							}
						}
						
						userList[temp.counter][temp.account].pendingReward += temp.rewardAmount;
					}
				}
			}
		}
		
		if(temp.devRewardAmount > 0){
			defhold.safeTransfer(devAddress, temp.devRewardAmount);
		}
	}
	
	function updatePool(uint _pid) public nonReentrant {
		_updatePool(_pid);
	}
	
	function updateAllPool() public nonReentrant {
		PoolTemp memory temp;
		
		for(temp.counter = poolLists.length; temp.counter > 0;temp.counter--){
			temp.pid = temp.counter - 1;
			_updatePool(temp.pid);
		}
		
	}
	
	function _getTokenAmount(address _tokenAddress, uint256 _amount) internal view returns (uint256 quotient) {
		PoolTemp memory temp;
		
		temp.tokenAddress = IERC20(_tokenAddress);
		temp.tokenDecimal = temp.tokenAddress.decimals();
			
		if(_decimal != temp.tokenDecimal){
			if(_decimal > temp.tokenDecimal){
				temp.decimalDiff = _decimal - temp.tokenDecimal;
				temp.decimalDiffConverter = 10**temp.decimalDiff;
				temp.amount = _amount.div(temp.decimalDiffConverter);
			} else {
				temp.decimalDiff = temp.tokenDecimal - _decimal;
				temp.decimalDiffConverter = 10**temp.decimalDiff;
				temp.amount = _amount.mul(temp.decimalDiffConverter);
			}		
		} else {
			temp.amount = _amount;
		}
		
		uint256 _quotient = temp.amount;
		
		return (_quotient);
    }
	
	function _getReverseTokenAmount(address _tokenAddress, uint256 _amount) internal view returns (uint256 quotient) {
		PoolTemp memory temp;
		
		temp.tokenAddress = IERC20(_tokenAddress);
		temp.tokenDecimal = temp.tokenAddress.decimals();
			
		if(_decimal != temp.tokenDecimal){
			if(_decimal > temp.tokenDecimal){
				temp.decimalDiff = _decimal - temp.tokenDecimal;
				temp.decimalDiffConverter = 10**temp.decimalDiff;
				temp.amount = _amount.mul(temp.decimalDiffConverter);
			} else {
				temp.decimalDiff = temp.tokenDecimal - _decimal;
				temp.decimalDiffConverter = 10**temp.decimalDiff;
				temp.amount = _amount.div(temp.decimalDiffConverter);
			}		
		} else {
			temp.amount = _amount;
		}
		
		uint256 _quotient = temp.amount;
		
		return (_quotient);
    }
		
	event Deposit(address indexed user, uint256 pool_id, uint256 timeStart, uint256 timeEnd, uint256 amount);
	event ClaimReward(address indexed user, uint256 amount);
	event PenaltyFee(address indexed user, uint256 pool_id, uint256 fee, uint256 amount);
	event Withdraw(address indexed user, uint256 pool_id, uint256 amount);
	event WithdrawOverTime(address indexed user, uint256 pool_id, uint256 amount);
}
function updateToken(address tokenAddress, bool tokenStatus) external onlyOwner {
	_updateToken(tokenAddress, tokenStatus);
}

// function addPool(bool _is_farming, string calldata _pool_name, uint256 _EWFTime, uint256 _EWFRate) external onlyOwner {
// _addPool(_is_farming, _pool_name, _EWFTime, _EWFRate);
// }