contract StabinolToken is ERC20("Stabinol Token", "STOL"), Ownable {
    using SafeMath for uint256;

    // Variables
    uint256 constant DIVISION_FACTOR = 100000;
    uint256 constant TAX_EFFECTIVE = 500000e18; // The threshold at which the tax kicks in
    uint256 private effectiveMaxSupply = 1000000e18; // The default max supply of tokens
    uint256 public taxRate = 0; // Governance can update the tax rate as it gets closer to the max supply
    
    mapping (address => bool) public taxExemptAccounts; // Addresses that will not have a sender tax
    
    constructor() public {
        // We will mint 350,000 tokens to the deployer to use for the merkle airdrop, team and liquidity
        _mint(_msgSender(), 350000e18);
    }

    modifier onlyClaimer() {
        require(claimerAddress == _msgSender(), "Ownable: caller is not the claimer");
        _;
    }

    function getMaxSupply() external view returns (uint256) {
        return effectiveMaxSupply;
    }
    
    /// @notice Creates `_amount` token to `_to`. Must only be called by the claimer.
    function mint(address _to, uint256 _amount) external onlyClaimer returns (bool) {
        _mint(_to, _amount);
        require(totalSupply() <= effectiveMaxSupply, "Cannot mint any more tokens"); // After max supply is reached, claimer cannot claim anymore
        return true;
    }

    // This function will tax each non-exempt address the transfer fee
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override returns (uint256) {
        super._beforeTokenTransfer(from, to, amount); // Call parent hook
        if(taxExemptAccounts[from] == true){ return amount; } // No fee for certain accounts
        if(taxRate > 0 && totalSupply() > TAX_EFFECTIVE){
            // Tax is taken from sender balance. If sender balance not enough to cover transfer, tax taken from transferred amount
            // For contracts to calculate ideal fee when sending this token, use this equation: taxRate / (1 + taxRate) = withdrawFeeRate
            uint256 taxAmount = amount.mul(taxRate).div(DIVISION_FACTOR);
            if(taxAmount.add(amount) > balanceOf(from)){
                uint256 overage = taxAmount.add(amount).sub(balanceOf(from)); // The overage for the fee
                amount = amount.sub(overage);
            }
            _tax(from,taxAmount);
        }
        return amount;
    }
    
    // Now add some governance functions behind 24 hour timelock
    
    // Timelock variables
    // Timelock doesn't activate until claimer is set to a non-zero account
    
    uint256 private _timelockStart; // The start of the timelock to change governance variables
    uint256 private _timelockType; // The function that needs to be changed
    uint256 constant TIMELOCK_DURATION = 86400; // Timelock is 24 hours
    
    // Reusable timelock variables
    uint256 private _timelock_data;
    address private _timelock_address;
    
    modifier timelockConditionsMet(uint256 _type) {
        require(_timelockType == _type, "Timelock not acquired for this function");
        _timelockType = 0; // Reset the type once the timelock is used
        if(claimerAddress != address(0)){
            require(now >= _timelockStart + TIMELOCK_DURATION, "Timelock time not met");
        }
        _;
    }
    
    // Change the governance
    // --------------------
    function startChangeGovernance(address _address) external onlyGovernance {
        _timelockStart = now;
        _timelockType = 1;
        _timelock_address = _address;       
    }
    
    function finishChangeGovernance() external onlyGovernance timelockConditionsMet(1) {
        _transferGovernance(_timelock_address);
    }
    // --------------------
    
    // Used to change tax rate
    // --------------------
    function startChangeTaxRate(uint256 _percent) external onlyGovernance {
        _timelockStart = now;
        _timelockType = 2;
        _timelock_data = _percent;
    }
    
    function finishChangeTaxRate() external onlyGovernance timelockConditionsMet(2) {
        taxRate = _timelock_data;
    }
    // --------------------
    
    // Change the claimer address
    // --------------------
    function startChangeClaimer(address _address) external onlyGovernance {
        _timelockStart = now;
        _timelockType = 3;
        _timelock_address = _address;       
    }
    
    function finishChangeClaimer() external onlyGovernance timelockConditionsMet(3) {
        taxExemptAccounts[_timelock_address] = true;
        _setClaimer(_timelock_address);
    }
    // --------------------
    
    // Toggle whether an account is tax exempt or not
    // --------------------
    function startToggleTaxExempt(address _address) external onlyGovernance {
        _timelockStart = now;
        _timelockType = 4;
        _timelock_address = _address;       
    }
    
    function finishToggleTaxExempt() external onlyGovernance timelockConditionsMet(4) {
        if(taxExemptAccounts[_timelock_address] == true){
            taxExemptAccounts[_timelock_address] = false;
        }else{
            taxExemptAccounts[_timelock_address] = true;
        }
    }
    // --------------------
    
    // Used to change the effective max supply
    // --------------------
    function startChangeEffectiveSupply(uint256 _supply) external onlyGovernance {
        _timelockStart = now;
        _timelockType = 5;
        _timelock_data = _supply;
    }
    
    function finishChangeEffectiveSupply() external onlyGovernance timelockConditionsMet(5) {
        effectiveMaxSupply = _timelock_data;
    }
    // --------------------
}
// Stabilize Token with Governance.
function startChangeEffectiveSupply(uint256 _supply) external onlyGovernance {
    _timelockStart = now;
    _timelockType = 5;
    _timelock_data = _supply;
}

// --------------------
// Used to change the effective max supply
// --------------------