contract HUDLToken is Ownable, ERC20{
    /* Scalar for safe math */
    uint256 scalar = 1000000;
    /* Max supply of HUDL tokens */
    uint256 maxSupply = 40000000 * 10**18;
    /* Initial supply for distributor */
    uint256 initialSupply = 2000000 * 10**18;
    /* Initial founder supply*/
    uint256 initialFounderSupply = 500000 * 10**18;
    /* Max pool supply scaled 10000 = 1% */
    uint256 poolMaxSize = 10000;
    /* Min pool supply scaled 100 = 0.01% */
    uint256 poolMinSize = 100;
    /* Timestamp for tracking */
    uint256 lastPoolTimeStamp = block.timestamp;
    /* Distributor contract address */
    address distributorAddress = address(0);
    /* HUDL pool contract address */
    address hudlPoolAddress = address(0);
    /* How much tokens are in reserve for the pool */ 
    uint256 amountInReserve = maxSupply;
    /* How much tokens are in reserve for the pool */ 
    uint256 mintTimeLock = 0;
    /* have the initial tokens been minted? */ 
    bool initialMinted = false;

    constructor (string memory name, string memory symbol, uint256 timeLock) public ERC20(name, symbol) Ownable(){
        mintTimeLock = timeLock + 60 days; 
    }


    /*** GETTER FUNCTIONS ***/
    function getHudlPoolAddress() external view returns(address){
        return hudlPoolAddress;
    }

    function getDistributorAddress() external view returns(address){
        return distributorAddress;
    }

   function getAmountInReserve() external view returns(uint256){
        return amountInReserve;
    }

    function getMaxPoolSize() external view returns(uint256, uint256, uint256, uint256){
        uint256 tempPool;
        if(block.timestamp - lastPoolTimeStamp > 24 hours){
            tempPool = 10000;
        }
        else{
            tempPool = poolMaxSize + (((block.timestamp - lastPoolTimeStamp) * 24 hours * (10000 - poolMaxSize)) / 24 hours) / 24 hours;
        }
        uint256 responseTokensMinSize = amountInReserve/10000;
        uint256 responseTokensMaxSize = (tempPool * amountInReserve) / scalar;

        return (poolMaxSize, tempPool, responseTokensMinSize, responseTokensMaxSize);
    }
    

    /*** MUTATOR FUNCTIONS ***/
    /* Allows the distributor contract to mint tokens into its address */
    function mintInitial() external onlyOwner{
        require(distributorAddress != address(0), "Distributor address required");
        require(!initialMinted, "Can only initially mint once");
        _mint(distributorAddress, initialSupply);
        _mint(owner(), initialFounderSupply);
        amountInReserve = amountInReserve - initialSupply - initialFounderSupply;
        initialMinted = true;
    }

    /* Allows the hudl pool contract to mint tokens into its address */
    function hudlCreatePool(uint256 size) external onlyOwner{
        uint256 tempPool;
        require(block.timestamp >= mintTimeLock, "Require distribution to be over");
        
        if(block.timestamp - lastPoolTimeStamp > 24 hours){
            tempPool = 10000;
        }
        else{
            tempPool = poolMaxSize + (((block.timestamp - lastPoolTimeStamp) * 24 hours * (10000 - poolMaxSize)) / 24 hours) / 24 hours;
        }

        if(((size * scalar) / amountInReserve) > tempPool){
            revert("Pool too big");
        }
        if(((size * scalar) / amountInReserve) < poolMinSize){
            revert("Pool too small");
        }
        else{
            /* Check if pool goes under 3000 with an subtraction overflow protection*/
            if(((poolMaxSize - ((size * 700000) / amountInReserve)) > 3000) && ((poolMaxSize - ((size * 700000) / amountInReserve)) < 10000000000000000)){
                poolMaxSize = poolMaxSize - ((size * 700000) / (amountInReserve));
            }  
            else{  
                poolMaxSize = 3000;
            }
        }
        
        lastPoolTimeStamp = block.timestamp;
        
        amountInReserve -= size;

        _mint(hudlPoolAddress, size);
    }

    /* Allows the distributor to send tokens to the uniswapv2 contract */
    function approvePair(address pair) external{
        approve(distributorAddress, initialSupply);
        _approve(distributorAddress, pair, initialSupply);
    }

    /*** SETTER FUNCTIONS ***/

    /* Sets the hudl pool contract address */
    function setHudlPoolAddress(address newAddress) external onlyOwner{
        hudlPoolAddress = newAddress;
        transferOwnership(hudlPoolAddress);
    }

    /* Sets the distributor contract address */
    function setDistributorAddress(address newAddress) external onlyOwner{
        require(distributorAddress == address(0), "Can only set once");
        distributorAddress = newAddress;
    }
}
function mintInitial() external onlyOwner{
    require(distributorAddress != address(0), "Distributor address required");
    require(!initialMinted, "Can only initially mint once");
    _mint(distributorAddress, initialSupply);
    _mint(owner(), initialFounderSupply);
    amountInReserve = amountInReserve - initialSupply - initialFounderSupply;
    initialMinted = true;
}

/* Allows the distributor contract to mint tokens into its address */