class BandwidthBuilderImpl implements BandwidthBuilderCapacityStage, BandwidthBuilderRefillStage, BandwidthBuilderBuildStage {

        private long capacity;
        private long refillPeriodNanos;
        private long refillTokens;
        private long initialTokens;
        private boolean refillIntervally;
        private long timeOfFirstRefillMillis = UNSPECIFIED_TIME_OF_FIRST_REFILL;
        private boolean useAdaptiveInitialTokens;
        private String id = UNDEFINED_ID;

        @Override
        public BandwidthBuilderRefillStage capacity(long tokens) {<FILL_FUNCTION_BODY>}

        @Override
        public BandwidthBuilderBuildStage refillGreedy(long tokens, Duration period) {
            setRefill(tokens, period, false);
            return this;
        }

        @Override
        public BandwidthBuilderBuildStage refillIntervally(long tokens, Duration period) {
            setRefill(tokens, period, true);
            return this;
        }

        @Override
        public BandwidthBuilderBuildStage refillIntervallyAligned(long tokens, Duration period, Instant timeOfFirstRefill) {
            long timeOfFirstRefillMillis = timeOfFirstRefill.toEpochMilli();
            if (timeOfFirstRefillMillis < 0) {
                throw BucketExceptions.nonPositiveTimeOfFirstRefill(timeOfFirstRefill);
            }
            setRefill(tokens, period, true);
            this.timeOfFirstRefillMillis = timeOfFirstRefillMillis;
            return this;
        }

        @Override
        public BandwidthBuilderBuildStage refillIntervallyAlignedWithAdaptiveInitialTokens(long tokens, Duration period, Instant timeOfFirstRefill) {
            long timeOfFirstRefillMillis = timeOfFirstRefill.toEpochMilli();
            if (timeOfFirstRefillMillis < 0) {
                throw BucketExceptions.nonPositiveTimeOfFirstRefill(timeOfFirstRefill);
            }
            setRefill(tokens, period, true);
            this.timeOfFirstRefillMillis = timeOfFirstRefillMillis;
            this.useAdaptiveInitialTokens = true;
            return this;
        }

        @Override
        public BandwidthBuilderBuildStage id(String id) {
            this.id = id;
            return this;
        }

        @Override
        public BandwidthBuilderBuildStage initialTokens(long initialTokens) {
            if (initialTokens < 0) {
                throw BucketExceptions.nonPositiveInitialTokens(initialTokens);
            }
            if (timeOfFirstRefillMillis != UNSPECIFIED_TIME_OF_FIRST_REFILL && useAdaptiveInitialTokens) {
                throw BucketExceptions.intervallyAlignedRefillWithAdaptiveInitialTokensIncompatipleWithManualSpecifiedInitialTokens();
            }
            this.initialTokens = initialTokens;
            return this;
        }

        @Override
        public Bandwidth build() {
            return new Bandwidth(capacity, refillPeriodNanos, refillTokens, initialTokens, refillIntervally, timeOfFirstRefillMillis, useAdaptiveInitialTokens, id);
        }

        private void setRefill(long tokens, Duration period, boolean refillIntervally) {
            if (period == null) {
                throw BucketExceptions.nullRefillPeriod();
            }
            if (tokens <= 0) {
                throw BucketExceptions.nonPositivePeriodTokens(tokens);
            }
            long refillPeriodNanos = period.toNanos();
            if (refillPeriodNanos <= 0) {
                throw BucketExceptions.nonPositivePeriod(refillPeriodNanos);
            }
            if (tokens > refillPeriodNanos) {
                throw BucketExceptions.tooHighRefillRate(refillPeriodNanos, tokens);
            }

            this.refillPeriodNanos = refillPeriodNanos;
            this.refillIntervally = refillIntervally;
            this.refillTokens = tokens;
        }

    }

            if (tokens <= 0) {
                throw BucketExceptions.nonPositiveCapacity(tokens);
            }
            this.capacity = tokens;
            this.initialTokens = tokens;
            return this;
        
<no_super_class>