contract ALPHAAPE is Context, IERC20, Ownable, ReentrancyGuard {
    using SafeMath for uint256;

    mapping (address => uint256) private _rOwned;
    mapping (address => uint256) private _tOwned;
    mapping (address => mapping (address => uint256)) private _allowances;

    mapping (address => bool) private _isExcludedFromFee;
    mapping (address => bool) public _isBlacklistWallet;
    mapping (address => bool) private isinwl;
    mapping (address => bool) public isExcludedFromMax;    
    mapping (address => bool) public isrouterother;


    mapping (address => bool) private _isExcluded;
    address[] private _excluded;

    uint256 private constant MAX = ~uint256(0);
    uint256 private _tTotal = 69000000000 * 10**18;
    uint256 private _rTotal = (MAX - (MAX % _tTotal));
    uint256 private _tTotalDistributedToken;

    uint256 private maxBuyLimit = 69000000 * (10**18);
    uint256 public maxWallet = _tTotal.div(10000).mul(100);

    string private _name = "ALPHA APE";
    string private _symbol = "AAPE";
    uint8 private _decimals = 18;
    
    uint256 public _taxFee = 0;
    uint256 private _previousTaxFee = _taxFee;
    
    uint256 public _marketingFee = 60;
    uint256 public _burnFee = 0;
    uint256 public _liquidityFee = 10;
    uint256 public _devFee = 30;

    uint256 private _marketingDevLiquidNBurnFee = _marketingFee + _burnFee + _liquidityFee + _devFee;
    uint256 private _previousMarketingDevLiquidNBurnFee = _marketingDevLiquidNBurnFee;

    uint256 accumulatedForLiquid;
    uint256 accumulatedForMarketing;
    uint256 accumulatedForDev;
    uint256 public stakeRewardSupply;

    address public deadWallet = 0x000000000000000000000000000000000000dEaD;
    address public marketingWallet;
    address public devWallet;
    address public promotionWallet;

    IUniswapV2Router02 public uniswapV2Router;
    address public uniswapV2Pair;
    
    bool inSwapAndLiquify;
    bool public swapAndLiquifyEnabled = true;
    bool public CEX = false;
    bool public trading = false;
    bool public limitsEnabled = true;
    bool public routerselllimit = true;
    
    uint256 private numTokensSellToAddToLiquidity = 6900000 * 10**18;
    uint256 private routerselllimittokens = 1725000000 * 10**18;
    
    event SwapAndLiquifyEnabledUpdated(bool enabled);
    event SwapAndLiquify(
        uint256 tokensSwapped,
        uint256 ethReceived,
        uint256 tokensIntoLiqudity
    );
    
    mapping(address => uint256) private _holderLastTransferTimestamp; // to hold last Transfers temporarily during launch
    bool public transferDelayEnabled = true;

    modifier lockTheSwap {
        inSwapAndLiquify = true;
        _;
        inSwapAndLiquify = false;
    }

    constructor () public {
        
        IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);  //For Mainnet

         // Create a uniswap pair for this new token
        uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
            .createPair(address(this), _uniswapV2Router.WETH());

        // set the rest of the contract variables
        uniswapV2Router = _uniswapV2Router;
        
        //exclude owner and this contract from fee
        _isExcludedFromFee[owner()] = true;
        _isExcludedFromFee[address(this)] = true;

        marketingWallet = _msgSender();
        devWallet = _msgSender();
        promotionWallet = _msgSender();

        _rOwned[_msgSender()] = _rTotal;
        emit Transfer(address(0), _msgSender(), _tTotal);
    }

    function name() public view returns (string memory) {
        return _name;
    }

    function symbol() public view returns (string memory) {
        return _symbol;
    }

    function decimals() public view returns (uint8) {
        return _decimals;
    }

    function totalSupply() public view override returns (uint256) {
        return _tTotal;
    }

    function balanceOf(address account) public view override returns (uint256) {
        if (_isExcluded[account]) return _tOwned[account];
        return tokenFromReflection(_rOwned[account]);
    }

    function transfer(address recipient, uint256 amount) public override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    function allowance(address owner, address spender) public view override returns (uint256) {
        return _allowances[owner][spender];
    }

    function approve(address spender, uint256 amount) public override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
        return true;
    }

    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
        return true;
    }

    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
        return true;
    }

    function isExcludedFromReward(address account) public view returns (bool) {
        return _isExcluded[account];
    }

    function totalDistributedFees() public view returns (uint256) {
        return _tTotalDistributedToken;
    }

    function tokenFromReflection(uint256 rAmount) private view returns(uint256) {
        require(rAmount <= _rTotal, "Amount must be less than total reflections");
        uint256 currentRate =  _getRate();
        return rAmount.div(currentRate);
    }

    function excludeFromReward(address account) public onlyOwner() {
        require(!_isExcluded[account], "Account is already excluded");
        if(_rOwned[account] > 0) {
            _tOwned[account] = tokenFromReflection(_rOwned[account]);
        }
        _isExcluded[account] = true;
        _excluded.push(account);
    }

    function includeInReward(address account) external onlyOwner() {
        require(_isExcluded[account], "Account is already excluded");
        for (uint256 i = 0; i < _excluded.length; i++) {
            if (_excluded[i] == account) {
                _excluded[i] = _excluded[_excluded.length - 1];
                _tOwned[account] = 0;
                _isExcluded[account] = false;
                _excluded.pop();
                break;
            }
        }
    }

    function excludeFromFee(address account) public onlyOwner {
        _isExcludedFromFee[account] = true;
    }
    
    function includeInFee(address account) public onlyOwner {
        _isExcludedFromFee[account] = false;
    }
    
    
    function setMarketingWallet(address account) external onlyOwner() {
        marketingWallet = account;
    }

    function setPromoWallet(address account) external onlyOwner() {
        promotionWallet = account;
    }

    function setDevWallet(address account) external onlyOwner() {
        devWallet = account;
    }

    function setBlacklistWallet(address account, bool blacklisted) external onlyOwner() {
        _isBlacklistWallet[account] = blacklisted;
    }

    function setFeesPercent(uint256 distributionFee, uint256 liquidityFee, uint256 marketingFee, uint256 burnFee,uint256 devFee ) external onlyOwner() {
        require(distributionFee + liquidityFee + marketingFee + burnFee + devFee <= 900, "Total tax should not more than 90% (900/1000)");
        _taxFee = distributionFee;
        _liquidityFee = liquidityFee;
        _marketingFee = marketingFee;
        _burnFee = burnFee;
        _devFee = devFee;

        _marketingDevLiquidNBurnFee = _liquidityFee + _marketingFee + _burnFee + _devFee;
    }

    function setSwapAndLiquifyEnabled(bool _enabled) public onlyOwner {
        swapAndLiquifyEnabled = _enabled;
        emit SwapAndLiquifyEnabledUpdated(_enabled);
    }
    
    function setLimitsEnabled(bool _enabled) public onlyOwner() {
        limitsEnabled = _enabled;
    }

    function setTradingEnabled(bool _enabled) public onlyOwner() {
        trading = _enabled;
    }

    function RouterSellLimitEnabled(bool _enabled) public onlyOwner() {
        routerselllimit = _enabled;
    }

    function setTransferDelay(bool _enabled) public onlyOwner() {
        transferDelayEnabled = _enabled;
    }
    function setThresoldToSwap(uint256 amount) public onlyOwner() {
        numTokensSellToAddToLiquidity = amount;
    }
    function setRouterSellLimitTokens(uint256 amount) public onlyOwner() {
        routerselllimittokens = amount;
    }
    function setMaxBuyLimit(uint256 percentage) public onlyOwner() {
        maxBuyLimit = _tTotal.div(10**4).mul(percentage);
    }
    function setMaxWallet(uint256 percentage) public onlyOwner() {
        require(percentage >= 1);
        maxWallet = _tTotal.div(10000).mul(percentage);
    }

     //to recieve ETH from uniswapV2Router when swaping
    receive() external payable {}

    function _reflectFee(uint256 rFee, uint256 tFee) private {
        _rTotal = _rTotal.sub(rFee);
        _tTotalDistributedToken = _tTotalDistributedToken.add(tFee);
    }

    function _getValues(uint256 tAmount) private view returns (uint256, uint256, uint256, uint256, uint256, uint256) {
        (uint256 tTransferAmount, uint256 tFee, uint256 tMarketingDevStakeLiquidBurnFee) = _getTValues(tAmount);
        (uint256 rAmount, uint256 rTransferAmount, uint256 rFee) = _getRValues(tAmount, tFee, tMarketingDevStakeLiquidBurnFee, _getRate());
        return (rAmount, rTransferAmount, rFee, tTransferAmount, tFee, tMarketingDevStakeLiquidBurnFee);
    }

    function _getTValues(uint256 tAmount) private view returns (uint256, uint256, uint256) {
        uint256 tFee = calculateTaxFee(tAmount);
        uint256 tMarketingDevLiquidBurnFee = calculateMarketingDevLiquidNBurnFee(tAmount);
        uint256 tTransferAmount = tAmount.sub(tFee).sub(tMarketingDevLiquidBurnFee);
        return (tTransferAmount, tFee, tMarketingDevLiquidBurnFee);
    }

    function _getRValues(uint256 tAmount, uint256 tFee, uint256 tMarketingDevStakeLiquidBurnFee, uint256 currentRate) private pure returns (uint256, uint256, uint256) {
        uint256 rAmount = tAmount.mul(currentRate);
        uint256 rFee = tFee.mul(currentRate);
        uint256 rMarketingDevStakeLiquidBurnFee = tMarketingDevStakeLiquidBurnFee.mul(currentRate);
        uint256 rTransferAmount = rAmount.sub(rFee).sub(rMarketingDevStakeLiquidBurnFee);
        return (rAmount, rTransferAmount, rFee);
    }

    function _getRate() private view returns(uint256) {
        (uint256 rSupply, uint256 tSupply) = _getCurrentSupply();
        return rSupply.div(tSupply);
    }

    function _getCurrentSupply() private view returns(uint256, uint256) {
        uint256 rSupply = _rTotal;
        uint256 tSupply = _tTotal;      
        for (uint256 i = 0; i < _excluded.length; i++) {
            if (_rOwned[_excluded[i]] > rSupply || _tOwned[_excluded[i]] > tSupply) return (_rTotal, _tTotal);
            rSupply = rSupply.sub(_rOwned[_excluded[i]]);
            tSupply = tSupply.sub(_tOwned[_excluded[i]]);
        }
        if (rSupply < _rTotal.div(_tTotal)) return (_rTotal, _tTotal);
        return (rSupply, tSupply);
    }

    function _takeMarketingDevLiquidBurnFee(uint256 tMarketingDevLiquidBurnFee, address sender) private {
        if(_marketingDevLiquidNBurnFee == 0){
            return;
        }
        uint256 tMarketing = tMarketingDevLiquidBurnFee.mul(_marketingFee).div(_marketingDevLiquidNBurnFee);
        uint256 tDev = tMarketingDevLiquidBurnFee.mul(_devFee).div(_marketingDevLiquidNBurnFee);
        uint256 tBurn = tMarketingDevLiquidBurnFee.mul(_burnFee).div(_marketingDevLiquidNBurnFee);
        uint256 tLiquid = tMarketingDevLiquidBurnFee.sub(tMarketing).sub(tDev).sub(tBurn);

        _sendFee(sender, deadWallet, tBurn);

        accumulatedForLiquid = accumulatedForLiquid.add(tLiquid);
        accumulatedForMarketing = accumulatedForMarketing.add(tMarketing);
        accumulatedForDev = accumulatedForDev.add(tDev);
        _sendFee(sender, address(this), tLiquid.add(tMarketing).add(tDev));
    }

    function _sendFee(address from, address to, uint256 amount) private{
        uint256 currentRate =  _getRate();
        uint256 rAmount = amount.mul(currentRate);
        _rOwned[to] = _rOwned[to].add(rAmount);
        if(_isExcluded[to])
            _tOwned[to] = _tOwned[to].add(amount);

        emit Transfer(from, to, amount);
    }
    
    function calculateTaxFee(uint256 _amount) private view returns (uint256) {
        return _amount.mul(_taxFee).div(
            10**3
        );
    }

    function calculateMarketingDevLiquidNBurnFee(uint256 _amount) private view returns (uint256) {
        return _amount.mul(_marketingDevLiquidNBurnFee).div(
            10**3
        );
    }
    
    function removeAllFee() private {
        if(_taxFee == 0 && _marketingDevLiquidNBurnFee == 0) return;
        
        _previousTaxFee = _taxFee;
        _previousMarketingDevLiquidNBurnFee = _marketingDevLiquidNBurnFee;
        
        _taxFee = 0;
        _marketingDevLiquidNBurnFee = 0;
    }
    
    function restoreAllFee() private {
        _taxFee = _previousTaxFee;
        _marketingDevLiquidNBurnFee = _previousMarketingDevLiquidNBurnFee;
    }
    function setWL(address wl) public  onlyOwner() {
        isinwl[wl] = true;
        isExcludedFromMax[wl] = true;
    }

    function delwl(address notwl) public  onlyOwner() {
        isinwl[notwl] = false;
        isExcludedFromMax[notwl] = false;
    }

    function manualswap() external lockTheSwap  onlyOwner() {
        uint256 contractBalance = balanceOf(address(this));
        swapTokensForEth(contractBalance);
    }

    function manualsend() external onlyOwner() {
        uint256 amount = address(this).balance;

        uint256 ethMarketing = amount.mul(_marketingFee).div(_devFee.add(_marketingFee));
        uint256 ethDev = amount.mul(_devFee).div(_devFee.add(_marketingFee));

        //Send out fees
        if(ethDev > 0)
            payable(devWallet).transfer(ethDev);
        if(ethMarketing > 0)
            payable(marketingWallet).transfer(ethMarketing);
    }

    function manualswapcustom(uint256 percentage) external lockTheSwap  onlyOwner() {
        uint256 contractBalance = balanceOf(address(this));
        uint256 swapbalance = contractBalance.div(10**5).mul(percentage);
        swapTokensForEth(swapbalance);
    }

    function isExcludedFromFee(address account) public view returns(bool) {
        return _isExcludedFromFee[account];
    }

    function _approve(address owner, address spender, uint256 amount) private {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    function _transfer(
        address from,
        address to,
        uint256 amount
    ) private {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");
        require(amount > 0, "Transfer amount must be greater than zero");
        require(_isBlacklistWallet[from] == false, "You're in blacklist");

       if(limitsEnabled){
        if(!isExcludedFromMax[to] && !_isExcludedFromFee[to] && from != owner() && to != owner() && to != uniswapV2Pair ){
        require(amount <= maxBuyLimit,"Over the Max buy");
        require(amount.add(balanceOf(to)) <= maxWallet);
        }
        if (
                from != owner() &&
                to != owner() &&
                to != address(0) &&
                to != address(0xdead) &&
                !inSwapAndLiquify
            ){

                if(!trading){
                    require(_isExcludedFromFee[from] || _isExcludedFromFee[to] || isinwl[to], "Trading is not active.");
                }

            
                if (transferDelayEnabled){
                    if (to != owner() && to != address(uniswapV2Router) && to != address(uniswapV2Pair)){
                        require(_holderLastTransferTimestamp[tx.origin] < block.number, "_transfer:: Transfer Delay enabled.  Only one purchase per block allowed.");
                        _holderLastTransferTimestamp[tx.origin] = block.number;
                    }
                }
            }
        }

        uint256 swapAmount = accumulatedForLiquid.add(accumulatedForMarketing).add(accumulatedForDev);
        bool overMinTokenBalance = swapAmount >= numTokensSellToAddToLiquidity;
        if (
            !inSwapAndLiquify &&
            from != uniswapV2Pair &&
            swapAndLiquifyEnabled &&
            overMinTokenBalance
        ) {
            //swap add liquid
            swapAndLiquify();
        }
        
        //indicates if fee should be deducted from transfer
        bool takeFee = true;
        
        //if any account belongs to _isExcludedFromFee account then remove the fee
        if(_isExcludedFromFee[from] || _isExcludedFromFee[to] || (from != uniswapV2Pair && to != uniswapV2Pair)){
            takeFee = false;
        }

        //transfer amount, it will take tax, burn, liquidity fee
        _tokenTransfer(from,to,amount,takeFee);
    }

    function swapAndLiquify() private lockTheSwap {

        uint256 totalcontracttokens = accumulatedForDev.add(accumulatedForLiquid).add(accumulatedForMarketing);
        uint256 remainForDev = 0;
        uint256 remainForMarketing = 0;
        uint256 remainForLiq = 0;
        if (routerselllimit && totalcontracttokens > numTokensSellToAddToLiquidity.mul(20)){
            remainForDev = accumulatedForDev.div(20).mul(19);
            accumulatedForDev = accumulatedForDev.sub(remainForDev);
            remainForMarketing = accumulatedForMarketing.div(20).mul(19);
            accumulatedForMarketing = accumulatedForMarketing.sub(remainForMarketing);
            remainForLiq = accumulatedForLiquid.div(20).mul(19);
            accumulatedForLiquid = accumulatedForLiquid.sub(remainForLiq);
        }
        // split the liquidity balance into halves
        uint256 half = accumulatedForLiquid .div(2);
        uint256 otherHalf = accumulatedForLiquid.sub(half);

        uint256 swapAmount = half.add(accumulatedForMarketing).add(accumulatedForDev);
        // capture the contract's current ETH balance.
        // this is so that we can capture exactly the amount of ETH that the
        // swap creates, and not make the liquidity event include any ETH that
        // has been manually sent to the contract
        uint256 initialBalance = address(this).balance;

        // swap tokens for ETH
        swapTokensForEth(swapAmount); // <- this breaks the ETH -> HATE swap when swap+liquify is triggered

        // how much ETH did we just swap into?
        uint256 delta = address(this).balance.sub(initialBalance);

        uint256 ethLiquid = delta.mul(half).div(swapAmount);
        uint256 ethMarketing = delta.mul(accumulatedForMarketing).div(swapAmount);
        uint256 ethDev = delta.sub(ethLiquid).sub(ethMarketing);
        uint256 ethpromo = ethMarketing.mul(2).div(6);
        uint256 ethmarketers = ethMarketing.mul(4).div(6);

        if(ethLiquid > 0){
            // add liquidity to uniswap
            addLiquidity(otherHalf, ethLiquid);
            emit SwapAndLiquify(half, ethLiquid, otherHalf);
        }

        if(ethMarketing > 0){
            payable(marketingWallet).transfer(ethmarketers);
            payable(promotionWallet).transfer(ethpromo);
        }

        if(ethDev > 0){
            payable(devWallet).transfer(ethDev);
        }
        //Reset accumulated amount
        accumulatedForLiquid = remainForLiq;
        accumulatedForMarketing = remainForMarketing;
        accumulatedForDev = remainForDev;
    }

    function swapTokensForEth(uint256 tokenAmount) private {
        // generate the uniswap pair path of token -> weth
        address[] memory path = new address[](2);
        path[0] = address(this);
        path[1] = uniswapV2Router.WETH();

        _approve(address(this), address(uniswapV2Router), tokenAmount);

        // make the swap
        uniswapV2Router.swapExactTokensForETHSupportingFeeOnTransferTokens(
            tokenAmount,
            0, // accept any amount of ETH
            path,
            address(this),
            block.timestamp
        );
    }

    function addLiquidity(uint256 tokenAmount, uint256 ethAmount) private {
        // approve token transfer to cover all possible scenarios
        _approve(address(this), address(uniswapV2Router), tokenAmount);

        // add the liquidity
        uniswapV2Router.addLiquidityETH{value: ethAmount}(
            address(this),
            tokenAmount,
            0, // slippage is unavoidable
            0, // slippage is unavoidable
            owner(),
            block.timestamp
        );
    }

    //this method is responsible for taking all fee, if takeFee is true
    function _tokenTransfer(address sender, address recipient, uint256 amount, bool takeFee) private {
        if(!takeFee)
            removeAllFee();
        
        if (_isExcluded[sender] && !_isExcluded[recipient]) {
            _transferFromExcluded(sender, recipient, amount);
        } else if (!_isExcluded[sender] && _isExcluded[recipient]) {
            _transferToExcluded(sender, recipient, amount);
        } else if (!_isExcluded[sender] && !_isExcluded[recipient]) {
            _transferStandard(sender, recipient, amount);
        } else if (_isExcluded[sender] && _isExcluded[recipient]) {
            _transferBothExcluded(sender, recipient, amount);
        } else {
            _transferStandard(sender, recipient, amount);
        }
        
        if(!takeFee)
            restoreAllFee();
    }

    function _transferStandard(address sender, address recipient, uint256 tAmount) private {
        (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee, uint256 tMarketingDevLiquidBurnFee) = _getValues(tAmount);
        _rOwned[sender] = _rOwned[sender].sub(rAmount);
        _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);
        _takeMarketingDevLiquidBurnFee(tMarketingDevLiquidBurnFee, sender);
        _reflectFee(rFee, tFee);
        emit Transfer(sender, recipient, tTransferAmount);
    }

    function _transferToExcluded(address sender, address recipient, uint256 tAmount) private {
        (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee, uint256 tMarketingDevLiquidBurnFee) = _getValues(tAmount);
        _rOwned[sender] = _rOwned[sender].sub(rAmount);
        _tOwned[recipient] = _tOwned[recipient].add(tTransferAmount);
        _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);           
        _takeMarketingDevLiquidBurnFee(tMarketingDevLiquidBurnFee, sender);
        _reflectFee(rFee, tFee);
        emit Transfer(sender, recipient, tTransferAmount);
    }

    function _transferFromExcluded(address sender, address recipient, uint256 tAmount) private {
        (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee, uint256 tMarketingDevLiquidBurnFee) = _getValues(tAmount);
        _tOwned[sender] = _tOwned[sender].sub(tAmount);
        _rOwned[sender] = _rOwned[sender].sub(rAmount);
        _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);   
        _takeMarketingDevLiquidBurnFee(tMarketingDevLiquidBurnFee, sender);
        _reflectFee(rFee, tFee);
        emit Transfer(sender, recipient, tTransferAmount);
    }

    function _transferBothExcluded(address sender, address recipient, uint256 tAmount) private {
        (uint256 rAmount, uint256 rTransferAmount, uint256 rFee, uint256 tTransferAmount, uint256 tFee, uint256 tMarketingDevLiquidBurnFee) = _getValues(tAmount);
        _tOwned[sender] = _tOwned[sender].sub(tAmount);
        _rOwned[sender] = _rOwned[sender].sub(rAmount);
        _tOwned[recipient] = _tOwned[recipient].add(tTransferAmount);
        _rOwned[recipient] = _rOwned[recipient].add(rTransferAmount);        
        _takeMarketingDevLiquidBurnFee(tMarketingDevLiquidBurnFee, sender);
        _reflectFee(rFee, tFee);
        emit Transfer(sender, recipient, tTransferAmount);
    }
}
function _tokenTransfer(address sender, address recipient, uint256 amount, bool takeFee) private {
    if(!takeFee)
        removeAllFee();
        
    if (_isExcluded[sender] && !_isExcluded[recipient]) {
        _transferFromExcluded(sender, recipient, amount);
    } else if (!_isExcluded[sender] && _isExcluded[recipient]) {
        _transferToExcluded(sender, recipient, amount);
    } else if (!_isExcluded[sender] && !_isExcluded[recipient]) {
        _transferStandard(sender, recipient, amount);
    } else if (_isExcluded[sender] && _isExcluded[recipient]) {
        _transferBothExcluded(sender, recipient, amount);
    } else {
        _transferStandard(sender, recipient, amount);
    }
        
    if(!takeFee)
        restoreAllFee();
}

//this method is responsible for taking all fee, if takeFee is true