contract DeltaFlare is ERC20, Trustable {
    using Address for address;

    uint8 private _decimals = 18;

    IUniswapV2Router02 public uniswapV2Router;
    address public immutable uniswapV2Pair;

    bool public swapping;
    bool public taxSet = true;

    address private marketingWallet;

    uint256 public swapTokensAtAmount;

    uint256 private _buyMarketingFee;
    uint256 private _sellMarketingFee;

    uint256 public _maxBuy;
    uint256 public _maxSell;

    mapping (address => bool) public automatedMarketMakerPairs;
    mapping (address => bool) private _isExcludedFromFees;
    // mapping (address => bool) public _isExcludedFromContractBuyingLimit;

    /*
    modifier onlyNonContract {
        if (_isExcludedFromContractBuyingLimit[msg.sender]) {
            _;
        } else {
            require(!address(msg.sender).isContract(), 'Contract not allowed to call');
            _;
        }
    } */

    event SetAutomatedMarketMakerPair(address indexed pair, bool indexed value);
    event ExcludeFromFees(address indexed account, bool isExcluded);
    event MarketingWalletUpdated(address indexed newMarketingWallet, address indexed oldMarketingWallet);

    constructor(address marketingWallet_) ERC20 ("DeltaFlare", "HONR") {
        _buyMarketingFee = 10;
        _sellMarketingFee = 10;

        _maxBuy = 450000 * (10**_decimals);
        _maxSell = 450000 * (10**_decimals);

        swapTokensAtAmount = 250000 * (10**_decimals);

        taxSet = true;

        marketingWallet = marketingWallet_;

        IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(0x03f7724180AA6b939894B5Ca4314783B0b36b329);

        address _uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
            .createPair(address(this), _uniswapV2Router.WETH());

        // address _uniswapV2Pair = 0xC36442b4a4522E871399CD717aBDD847Ab11FE88;

        uniswapV2Router = _uniswapV2Router;
        uniswapV2Pair = _uniswapV2Pair;       

        _setAutomatedMarketMakerPair(_uniswapV2Pair, true);

        excludeFromFees(marketingWallet, true);
        excludeFromFees(address(this), true);

        /* _isExcludedFromContractBuyingLimit[address(this)] = true;
        _isExcludedFromContractBuyingLimit[0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D] = true;
        _isExcludedFromContractBuyingLimit[address(uniswapV2Pair)] = true; */

        _mint(_msgSender(), 100000000 * (10**_decimals));   
    }

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

   /* function enableContractAddressTrading(address account, bool enabled) external isTrusted {
        require(account.isContract(), 'Only contract address is allowed!');
        _isExcludedFromContractBuyingLimit[account] = enabled;
    } */

    function updateMarketingWallet(address newMarketingWallet) public isTrusted {
        require(newMarketingWallet != marketingWallet, "DeltaFlare: The marketing wallet is already this address");
        excludeFromFees(newMarketingWallet, true);
        emit MarketingWalletUpdated(newMarketingWallet, marketingWallet);
        marketingWallet = newMarketingWallet;
    }

    function updateSwapAmount(uint256 amount) public isTrusted {
	    swapTokensAtAmount = amount * (10**_decimals);
	}   

    function updateUniswapV2Router(address newAddress) public isTrusted {
        require(newAddress != address(uniswapV2Router), "DeltaFlare: The router already has that address");
        uniswapV2Router = IUniswapV2Router02(newAddress);
    }

    function excludeFromFees(address account, bool excluded) public isTrusted {
        require(_isExcludedFromFees[account] != excluded, "DeltaFlare: Account is already the value of 'excluded'");
        _isExcludedFromFees[account] = excluded;

        emit ExcludeFromFees(account, excluded);
    }

    function updateMaxBuySell(uint256 newMaxBuy, uint256 newMaxSell) public isTrusted {
        _maxBuy = newMaxBuy * (10**_decimals);
        _maxSell = newMaxSell * (10**_decimals);
    }

    function updateBuyFees(uint8 newBuyMarketingFee) public isTrusted {
        _buyMarketingFee = newBuyMarketingFee;
    }

    function updateSellFees(uint8 newSellMarketingFee) public isTrusted {
        _sellMarketingFee = newSellMarketingFee; 
    }    

    function updateTaxSet(bool value) public isTrusted {
	    taxSet = value;
	}   

    function setAutomatedMarketMakerPair(address pair, bool value) public isTrusted {
        require(pair != uniswapV2Pair, "DeltaFlare: The Uniswap pair cannot be removed from automatedMarketMakerPairs");
        _setAutomatedMarketMakerPair(pair, value);
    }
    
    receive() external payable {}

    function _setAutomatedMarketMakerPair(address pair, bool value) private {
        require(automatedMarketMakerPairs[pair] != value, "DeltaFlare: Automated market maker pair is already set to that value");
        automatedMarketMakerPairs[pair] = value;
        emit SetAutomatedMarketMakerPair(pair, value);
    }

    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal override {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        if(from != owner() && to != owner() && to != address(0) && to != address(0xdead) && to != uniswapV2Pair && 
        !_isExcludedFromFees[to] && !_isExcludedFromFees[from]) {
            require(amount <= _maxBuy, "Transfer amount exceeds the maxBuyAmount.");            
        }

        if(amount == 0) {
            super._transfer(from, to, 0);
            return;
        }

        if(!swapping && automatedMarketMakerPairs[to] && from != address(uniswapV2Router) && 
        from != owner() && to != owner() && !_isExcludedFromFees[to] && !_isExcludedFromFees[from]) {
            require(amount <= _maxSell, "Sell transfer amount exceeds the maxSellAmount.");            
        }

        uint256 contractTokenBalance = balanceOf(address(this));
        bool canSwap = contractTokenBalance >= swapTokensAtAmount;

        if(canSwap && !swapping
        && !automatedMarketMakerPairs[from] && from != marketingWallet && to != marketingWallet && !_isExcludedFromFees[to] && !_isExcludedFromFees[from]) {
            contractTokenBalance = swapTokensAtAmount;
            uint256 swapTokens;
            
            swapping = true;

            if(_sellMarketingFee > 0 || _buyMarketingFee > 0) {
                swapTokens = contractTokenBalance;
                swapTokensForEth(swapTokens);
                payable(marketingWallet).transfer(address(this).balance);
            }

            swapping = false;
        }        

        bool takeFee = !swapping && taxSet;

        if(!takeFee) {
            super._transfer(from, to, amount);
        }
        else if(_isExcludedFromFees[from] || _isExcludedFromFees[to]) {
            takeFee = false;
            super._transfer(from, to, amount);
        }
        else if(!automatedMarketMakerPairs[from] && !automatedMarketMakerPairs[to] 
                && !_isExcludedFromFees[from] && !_isExcludedFromFees[to]) {
            takeFee = false;
            super._transfer(from, to, amount);
        }

        if(takeFee) {
            uint256 BuyFees = amount * _buyMarketingFee / 100;
            uint256 SellFees = amount * _sellMarketingFee / 100;

            if(automatedMarketMakerPairs[to] && _sellMarketingFee > 0) {
                amount = amount - SellFees;
                super._transfer(from, address(this), SellFees);
                super._transfer(from, to, amount);
            }
            else if(automatedMarketMakerPairs[from] && _buyMarketingFee > 0) {
                amount = amount - BuyFees;
                super._transfer(from, address(this), BuyFees);
                super._transfer(from, to, amount);
            }
        }
    }   

    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 withdrawRemainingETH(address account, uint256 percent) public isTrusted {
        require(percent > 0 && percent <= 100);
        uint256 balance = address(this).balance * percent / 100;
        super._transfer(address(this), account, balance);
    }

    function withdrawRemainingToken(address account) public isTrusted {
        uint256 balance = balanceOf(address(this));
        super._transfer(address(this), account, balance);
    }
}
function updateMarketingWallet(address newMarketingWallet) public isTrusted {
    require(newMarketingWallet != marketingWallet, "DeltaFlare: The marketing wallet is already this address");
    excludeFromFees(newMarketingWallet, true);
    emit MarketingWalletUpdated(newMarketingWallet, marketingWallet);
    marketingWallet = newMarketingWallet;
}

/* function enableContractAddressTrading(address account, bool enabled) external isTrusted {
 require(account.isContract(), 'Only contract address is allowed!');
 _isExcludedFromContractBuyingLimit[account] = enabled;
 } */