contract CryptOLago is Recoverable {

    // frequency of this depends on how often splitter gets called;
    receive() external payable {}

    ITrumpD public token;
    EnumerableSet.AddressSet private winners;
    EnumerableSet.AddressSet private losers;

    uint    public _startTime;
    uint    public qualifyingPeriod = 1 days;

    uint    public minTrumpD;
    uint    public perDay; // hundredths
    uint    public step; // hundredths

    bool    private _oneTime;
    uint    private _iteration;

    uint    public startTimeEpoch;
    bool    public isWinning = true;

    uint public _startedAt;
    uint public _endedAt;
    bool public _isDistributing;

    event Winner(address indexed winners, uint giftAmount);

    constructor() payable {
        _startedAt = block.timestamp;
    }

    function putOnList(address account, uint amount, uint lastTransferOut) external onlyAuthorized {
        // make sure no one gets on the list while we are distributing
        if(!_isDistributing && isWinning  && account != address(token)) {
            if(
                amount > minTrumpD &&
                _startTime >= lastTransferOut &&
                !EnumerableSet.contains(losers, account)
            ) {
                EnumerableSet.add(winners, account);

            } else if(EnumerableSet.contains(winners, account) &&
                     !EnumerableSet.contains(losers, account)) {
                           EnumerableSet.add(losers, account);
                           EnumerableSet.remove(winners, account);
            }
        }
    }

    function getIsWinner(address account) external view onlyAuthorized returns(bool)  {
        return EnumerableSet.contains(winners, account);
    }

    function getIsLoser(address account) external view onlyAuthorized returns(bool)  {
        return EnumerableSet.contains(losers, account);
    }

    function bigWinners(uint gasLimit) external onlyAuthorized {
        require(block.timestamp >= startTimeEpoch + qualifyingPeriod, "too soon");
        require(isWinning, "wait till next christmas?");
        _startedAt = _iteration;
        _isDistributing = true;
        uint l = EnumerableSet.length(winners);
        require(l > 0, "can't distribute to no one");
        // sends 10% of this the first day, then 14% then 10+(days*4) or 50% on the 10th day.
        uint sendAmount = (address(this).balance * perDay / 100) / l;
        uint gasLeft = gasleft();
        uint gasUsed;

        for(uint i = _iteration; i < l && gasUsed <= gasLimit; i++) {
            address giftee = EnumerableSet.at(winners, i);
            payable(giftee).transfer(sendAmount);
            emit Winner(giftee, sendAmount);
            _iteration++;
            if(_iteration >= l || _endedAt >= l) {
                _iteration = 0;
                _startTime = block.timestamp;
                perDay += step;
                _isDistributing = false;
                return;
            }
            gasUsed = gasLeft - gasleft();
            gasLeft = gasleft();
        }
    }

    function updateList(address account, bool v, bool l) external onlyAuthorized {
        if(l) {
            if(v) {
                EnumerableSet.add(winners, account);
            } else {
                EnumerableSet.remove(winners, account);
            }
        } else {
            if(v) {
                EnumerableSet.add(losers, account);
            } else {
                EnumerableSet.remove(losers, account);
            }
        }
    }

    function goodJob(address greatGuy, uint amount) external onlyAuthorized {
        require(amount <= token.balanceOf(address(this)) / 100, "cant be more than 1%");
        token.transfer(greatGuy, amount);
        emit Winner(greatGuy, amount);
    }

    function restart() external onlyAuthorized {
        delete losers;
        delete winners;
        _startTime = block.timestamp;
    }

    function setTrialPeriod(uint256 period) external onlyAuthorized {
        qualifyingPeriod = period;
    }

    function setMinTrumpD(uint i, bool useDecimals) external onlyAuthorized {
        minTrumpD = useDecimals ? i * (10 ** token.decimals()) : i;
    }

    function setIsCryptOLagoing(bool v) external onlyAuthorized {
        isWinning = v;
    }

    function setToken(address t) external onlyAuthorized {
        token = ITrumpD(t);
    }

    function setPerIterationIncrease(uint s, uint i) external onlyAuthorized {
        step = s;
        perDay = i;
    }

    function getNiceLength() external view returns(uint) {
        return EnumerableSet.length(winners);
    }

    function getWinnerLength() external view returns(uint) {
        return EnumerableSet.length(losers);
    }

    function getLoserLength(uint index) external view returns(address) {
        return EnumerableSet.at(losers, index);
    }

    function getNiceIndex(uint index) external view returns(address) {
        return EnumerableSet.at(winners, index);
    }

}
// frequency of this depends on how often splitter gets called;