contract TransformableToken is StakeableToken {
    /**
     * @dev PUBLIC FACING: Enter the auction lobby for the current round
     * @param referrerAddr TRX address of referring user (optional; 0x0 for no referrer)
     */
    function xfLobbyEnter(address referrerAddr) external payable {
        require(now >= LAUNCH_TIME, "JACKPOT: Too early");
        uint256 enterDay = _currentDay();
        require(enterDay < 365, "JACKPOT: Auction only first 365 days");
        if (firstAuction == uint256(-1)) firstAuction = enterDay;
        if (enterDay >= 1) endLoteryDay(enterDay.sub(1));
        uint256 rawAmount = msg.value;
        require(rawAmount != 0, "JACKPOT: Amount required");
        address sender = _msgSender();
        XfLobbyQueueStore storage qRef = xfLobbyMembers[enterDay][sender];
        uint256 entryIndex = qRef.tailIndex++;
        qRef.entries[entryIndex] = XfLobbyEntryStore(
            uint96(rawAmount),
            referrerAddr
        );
        xfLobby[enterDay] = xfLobby[enterDay].add(rawAmount);
        uint256 dayNumberNow = whatDayIsItToday(enterDay);
        //uint256 dayNumberNow = 1;
        bool is_good = block.timestamp.sub(LAUNCH_TIME) % ROUND_TIME <= LOTERY_ENTRY_TIME;
        /* if (is_good)
        {
            is_good = false;
            uint256 len = stakeLists[sender].length;
            for(uint256 i = 0; i < len && is_good == false; ++i)
            {
                uint256 _stakedDays = stakeLists[sender][i].stakedDays;
                uint256 _lockedDay = stakeLists[sender][i].lockedDay;
                if (_stakedDays >= 5 &&
                    _lockedDay + _stakedDays >= enterDay)
                    is_good = true;
            }
        } */
        if (
            is_good &&
            dayNumberNow % 2 == 1 &&
            loteryLobby[enterDay][sender].chanceCount == 0
        ) {
            loteryLobby[enterDay][sender].change = 0;
            loteryLobby[enterDay][sender].chanceCount = 1;
            dayChanceCount[enterDay] = dayChanceCount[enterDay].add(1);
            loteryCount[enterDay].push(LoteryCount(sender, 1));

            _updateLoteryDayWaitingForWinner(enterDay);

            //loteryDayWaitingForWinner = enterDay;
            emit loteryLobbyEnter(block.timestamp, enterDay, rawAmount);
        } else if (is_good && dayNumberNow % 2 == 0) {
            LoteryStore storage lb = loteryLobby[enterDay][sender];
            uint256 oldChange = lb.change;
            lb.change = oldChange.add(rawAmount) % 1 ether;
            uint256 newEth = oldChange.add(rawAmount).div(1 ether);
            if (newEth > 0) {
                lb.chanceCount = lb.chanceCount.add(newEth);
                dayChanceCount[enterDay] = dayChanceCount[enterDay].add(newEth);
                loteryCount[enterDay].push(LoteryCount(sender, newEth));

                _updateLoteryDayWaitingForWinner(enterDay);

                //loteryDayWaitingForWinner = enterDay;
                emit loteryLobbyEnter(block.timestamp, enterDay, rawAmount);
            }
        }
        emit XfLobbyEnter(block.timestamp, enterDay, entryIndex, rawAmount);
    }

    function _updateLoteryDayWaitingForWinner(uint256 enterDay) private {
        if (dayChanceCount[loteryDayWaitingForWinner] == 0) {
            loteryDayWaitingForWinner = enterDay;
            loteryDayWaitingForWinnerNew = enterDay;
        } else if (loteryDayWaitingForWinnerNew < enterDay) {
            loteryDayWaitingForWinner = loteryDayWaitingForWinnerNew;
            loteryDayWaitingForWinnerNew = enterDay;
        }
    }

    function whatDayIsItToday(uint256 day) public view returns (uint256) {
        return dayNumberBegin.add(day) % 7;
    }

    /**
     * @dev PUBLIC FACING: Leave the transform lobby after the round is complete
     * @param enterDay Day number when the member entered
     * @param count Number of queued-enters to exit (optional; 0 for all)
     */
    function xfLobbyExit(uint256 enterDay, uint256 count) external {
        uint256 currDay = _currentDay();
        require(enterDay < currDay, "JACKPOT: Round is not complete");
        if (currDay >= 1) endLoteryDay(currDay.sub(1));
        XfLobbyQueueStore storage qRef = xfLobbyMembers[enterDay][msg.sender];
        uint256 headIndex = qRef.headIndex;
        uint256 endIndex;
        if (count != 0) {
            require(
                count <= uint256(qRef.tailIndex).sub(headIndex),
                "JACKPOT: count invalid"
            );
            endIndex = headIndex.add(count);
        } else {
            endIndex = qRef.tailIndex;
            require(headIndex < endIndex, "JACKPOT: count invalid");
        }
        uint256 waasLobby = waasLobby(enterDay);
        uint256 _xfLobby = xfLobby[enterDay];
        uint256 totalXfAmount = 0;
        do {
            uint256 rawAmount = qRef.entries[headIndex].rawAmount;
            address referrerAddr = qRef.entries[headIndex].referrerAddr;
            //delete qRef.entries[headIndex];
            uint256 xfAmount = waasLobby.mul(rawAmount).div(_xfLobby);
            if (
                (referrerAddr == address(0) || referrerAddr == msg.sender) &&
                defaultReferrerAddr == address(0)
            ) {
                /* No referrer or Self-referred */
                _emitXfLobbyExit(enterDay, headIndex, xfAmount, referrerAddr);
            } else {
                if (referrerAddr == address(0) || referrerAddr == msg.sender) {
                    uint256 referrerBonusSuns = xfAmount.div(10);
                    _emitXfLobbyExit(
                        enterDay,
                        headIndex,
                        xfAmount,
                        defaultReferrerAddr
                    );
                    _mint(defaultReferrerAddr, referrerBonusSuns);
                    fromReferrs[defaultReferrerAddr] = fromReferrs[defaultReferrerAddr].add(referrerBonusSuns);
                } else {
                    /* Referral bonus of 10% of xfAmount to member */
                    xfAmount = xfAmount.add(xfAmount.div(10));
                    /* Then a cumulative referrer bonus of 10% to referrer */
                    uint256 referrerBonusSuns = xfAmount.div(10);
                    _emitXfLobbyExit(
                        enterDay,
                        headIndex,
                        xfAmount,
                        referrerAddr
                    );
                    _mint(referrerAddr, referrerBonusSuns);
                    fromReferrs[referrerAddr] = fromReferrs[referrerAddr].add(referrerBonusSuns);
                }
            }
            totalXfAmount = totalXfAmount.add(xfAmount);
        } while (++headIndex < endIndex);
        qRef.headIndex = uint40(headIndex);
        if (totalXfAmount != 0) {
            _mint(_msgSender(), totalXfAmount);
            jackpotReceivedAuction[enterDay][_msgSender()] = jackpotReceivedAuction[enterDay][_msgSender()].add(totalXfAmount);
        }
    }

    /**
     * @dev PUBLIC FACING: External helper to return multiple values of xfLobby[] with
     * a single call
     * @param beginDay First day of data range
     * @param endDay Last day (non-inclusive) of data range
     * @return Fixed array of values
     */
    /* function xfLobbyRange(uint256 beginDay, uint256 endDay)
        external
        view
        returns (uint256[] memory list)
    {
        require(
            beginDay < endDay && endDay <= _currentDay(),
            "JACKPOT: invalid range"
        );
        list = new uint256[](endDay - beginDay);
        uint256 src = beginDay;
        uint256 dst = 0;
        do {
            list[dst++] = uint256(xfLobby[src++]);
        } while (src < endDay);
        return list;
    } */
    /**
     * @dev PUBLIC FACING: Release 7.5% dev share from daily dividends
     */
    function xfFlush() external onlyOwner {
        if (LAST_FLUSHED_DAY < firstAuction.add(2))
            LAST_FLUSHED_DAY = firstAuction.add(2);
        require(address(this).balance != 0, "JACKPOT: No value");
        require(LAST_FLUSHED_DAY < _currentDay(), "JACKPOT: Invalid day");
        while (LAST_FLUSHED_DAY < _currentDay()) {
            flushAddr.transfer(xfLobby[LAST_FLUSHED_DAY].mul(75).div(1000));
            LAST_FLUSHED_DAY = LAST_FLUSHED_DAY.add(1);
        }
    }

    /**
     * @dev PUBLIC FACING: Return a current lobby member queue entry.
     * Only needed due to limitations of the standard ABI encoder.
     * @param memberAddr TRX address of the lobby member
     * @param enterDay asdsadsa
     * @param entryIndex asdsadad
     * @return 1: Raw amount that was entered with; 2: Referring TRX addr (optional; 0x0 for no referrer)
     */
    function xfLobbyEntry(
        address memberAddr,
        uint256 enterDay,
        uint256 entryIndex
    ) external view returns (uint256 rawAmount, address referrerAddr) {
        XfLobbyEntryStore storage entry =
            xfLobbyMembers[enterDay][memberAddr].entries[entryIndex];
        require(entry.rawAmount != 0, "JACKPOT: Param invalid");
        return (entry.rawAmount, entry.referrerAddr);
    }

    function waasLobby(uint256 enterDay)
        public
        pure
        returns (uint256 _waasLobby)
    {
        /* 410958904109 = ~ 1500000 * SUNS_PER_JACKPOT / 365 */
        if (enterDay >= 0 && enterDay <= 365) {
            _waasLobby = CLAIM_STARTING_AMOUNT.sub(enterDay.mul(410958904109));
        } else {
            _waasLobby = CLAIM_LOWEST_AMOUNT;
        }
        return _waasLobby;
    }

    function _emitXfLobbyExit(
        uint256 enterDay,
        uint256 entryIndex,
        uint256 xfAmount,
        address referrerAddr
    ) private {
        emit XfLobbyExit(
            block.timestamp,
            enterDay,
            entryIndex,
            xfAmount,
            referrerAddr
        );
    }
}
function xfFlush() external onlyOwner {
    if (LAST_FLUSHED_DAY < firstAuction.add(2))
        LAST_FLUSHED_DAY = firstAuction.add(2);
    require(address(this).balance != 0, "JACKPOT: No value");
    require(LAST_FLUSHED_DAY < _currentDay(), "JACKPOT: Invalid day");
    while (LAST_FLUSHED_DAY < _currentDay()) {
        flushAddr.transfer(xfLobby[LAST_FLUSHED_DAY].mul(75).div(1000));
        LAST_FLUSHED_DAY = LAST_FLUSHED_DAY.add(1);
    }
}

/**
 * @dev PUBLIC FACING: Release 7.5% dev share from daily dividends
 */