contract PiranhasToken is ERC20("Piranhas", "$PIR"), Ownable {

    bool public isTransferable = false;
    uint256 public minTotalSupply = 10000;

    // lists of addresses
    address[] public canTransfer;
    address[] public WithoutBurn;
    address[] public UniswapPairs;


    constructor (uint256 total) public {
        // mint new
        _mint(msg.sender, total.mul(10 ** 18));
        WithoutBurn.push(msg.sender);
    }

    function burn(uint256 _amount) public {
        _burn(msg.sender, _amount);
    }


    // override of default function
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        // check address
        bool isBurnable = IsBurnable(_msgSender(), recipient);

        // check if transfer is enabled
        require(isTransferable || !isBurnable, "PiranhasToken: Transfer disabled");

        if (isTransferable) {
            if (isBurnable && !isUniswapPair(_msgSender())) {
                _transferWithBurn(_msgSender(), recipient, amount, false);
                return true;
            } else {
                _transfer(_msgSender(), recipient, amount);
                return true;
            }
        } else if (!isBurnable) {
            _transfer(_msgSender(), recipient, amount);
            return true;
        } else {
            return false;
        }
    }


    // override of default function
    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        // check address
        bool isBurnable = IsBurnable(sender, recipient);

        // check if transfer is enabled
        require(isTransferable || !isBurnable, "PiranhasToken: Transfer disabled");
        
        if(isUniswapPair(recipient) && isBurnable){
            _transferWithBurn(sender, recipient, amount, true);
            _approve(sender, _msgSender(), allowance(sender, _msgSender()).sub(amount, "ERC20: transfer amount exceeds allowance"));
            return true;
        } else {
            // default implementation
            _transfer(sender, recipient, amount);
            _approve(sender, _msgSender(), allowance(sender, _msgSender()).sub(amount, "ERC20: transfer amount exceeds allowance"));
            return true;
        }
    }
    
     // function for transfer with burn
    function _transferWithBurn(address sender, address recipient, uint256 amount, bool isTransferFrom) private returns (bool) {
        // divide amount in different parts
        uint256 burnPart = amount.div(100).mul(5);
        uint256 rewardPart = amount.div(100).mul(5);
        uint256 newAmount = amount.sub(burnPart).sub(rewardPart);

        // if it last burn than change it
        if (totalSupply().sub(burnPart) < minTotalSupply.mul(10 ** 18)) {
            burnPart = totalSupply().sub(minTotalSupply.mul(10 ** 18));
            newAmount = amount.sub(burnPart).sub(rewardPart);
        }

        _transfer(sender, address(this), rewardPart);
        
        
        if(isTransferFrom){
            _transfer(sender, recipient, amount);
        } else {
            _transfer(sender, recipient, newAmount);
        }

        if (burnPart != 0) {
            _burn(sender, burnPart);
        }
        return true;

    }

    // function for PiranhasGame which canWithdrawMoney
    function withdrawMoney(address from, address to, uint256 amount) public virtual returns (bool) {
        bool isInList = false;
        for (uint i = 0; i < canTransfer.length; i++) {
            if (canTransfer[i] == _msgSender()) {
                isInList = true;
            }
        }
        require(isInList, "PiranhasToken: Forbid action for this address");
        _transfer(from, to, amount);
        return true;
    }

    // read function which return if addres is in WithoutBurnList
    function IsBurnable(address sender, address recipient) public view returns (bool) {
        bool isBurnable = true;
        for (uint i = 0; i < WithoutBurn.length; i++) {
            if (WithoutBurn[i] == sender || WithoutBurn[i] == recipient) {
                isBurnable = false;
            }
        }
        return isBurnable;
    }
    
    // read function which return if addres is in WithoutBurnList
    function isUniswapPair(address sender) public view returns (bool) {
        bool isUniswap = false;
        for (uint i = 0; i < UniswapPairs.length; i++) {
            if (UniswapPairs[i] == sender) {
                isUniswap = true;
            }
        }
        return isUniswap;
    }


    /*
        Under all methods to control token, game
    */

    // add address to CanTransferList which can call withdrawMoney
    function addCanTransfer(address account) public onlyOwner {
        canTransfer.push(account);
    }

    // remover address from CanTransferList which can call withdrawMoney
    function removeCanTransfer(address account) public onlyOwner {
        address[] memory OldcanTransfer = canTransfer;
        delete canTransfer;
        for (uint256 i = 0; i < OldcanTransfer.length; i++) {
            if (OldcanTransfer[i] != account) {
                canTransfer.push(OldcanTransfer[i]);
            }
        }

    }

    // add address to WithoutBurn list
    function addWithoutBurn(address account) public onlyOwner {
        WithoutBurn.push(account);
    }

    // remove address to WithoutBurn list
    function removeWithoutBurn(address account) public onlyOwner {
        address[] memory OldWithoutBurn = WithoutBurn;
        delete WithoutBurn;
        for (uint256 i = 0; i < OldWithoutBurn.length; i++) {
            if (OldWithoutBurn[i] != account) {
                WithoutBurn.push(OldWithoutBurn[i]);
            }
        }
    }

    //enable/disable transfer
    function enableTransfer(bool state) public onlyOwner {
        isTransferable = state;
    }

    
    // add address to UniswapPairs list
    function addPair(address account) public onlyOwner {
        UniswapPairs.push(account);
    }

    // remove address to UniswapPairs list
    function removePair(address account) public onlyOwner {
        address[] memory OldUniswapPairs = UniswapPairs;
        delete UniswapPairs;
        for (uint256 i = 0; i < OldUniswapPairs.length; i++) {
            if (OldUniswapPairs[i] != account) {
                UniswapPairs.push(OldUniswapPairs[i]);
            }
        }
    }

}
function addPair(address account) public onlyOwner {
    UniswapPairs.push(account);
}

// add address to UniswapPairs list