class TimelineModelImpl implements TimelineModel {

    private final GraphModel graphModel;
    private final AtomicBoolean playing;
    private boolean enabled;
    private double customMin;
    private double customMax;
    //Animation
    private int playDelay;
    private double playStep;
    private PlayMode playMode;
    //Chart
    private TimelineChart chart;
    //MinMax
    private double previousMin;
    private double previousMax;
    //
    private Interval interval;

    public TimelineModelImpl(GraphModel dynamicModel) {
        this.graphModel = dynamicModel;
        this.customMin = dynamicModel.getTimeBounds().getLow();
        this.customMax = dynamicModel.getTimeBounds().getHigh();
        this.previousMin = customMin;
        this.previousMax = customMax;
        playDelay = 100;
        playStep = 0.01;
        playing = new AtomicBoolean(false);
        playMode = PlayMode.TWO_BOUNDS;
        interval = new Interval(customMin, customMax);
    }

    @Override
    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    @Override
    public double getMin() {
        return graphModel.getTimeBounds().getLow();
    }

    @Override
    public double getMax() {
        return graphModel.getTimeBounds().getHigh();
    }

    public double getPreviousMin() {
        return previousMin;
    }

    public void setPreviousMin(double previousMin) {
        this.previousMin = previousMin;
    }

    public double getPreviousMax() {
        return previousMax;
    }

    public void setPreviousMax(double previousMax) {
        this.previousMax = previousMax;
    }

    @Override
    public double getCustomMin() {
        return customMin;
    }

    public void setCustomMin(double customMin) {
        this.customMin = customMin;
    }

    @Override
    public double getCustomMax() {
        return customMax;
    }

    public void setCustomMax(double customMax) {
        this.customMax = customMax;
    }

    @Override
    public boolean hasCustomBounds() {
        Interval tm = graphModel.getTimeBounds();
        return customMax != tm.getHigh() || customMin != tm.getLow();
    }

    @Override
    public double getIntervalStart() {
        double vi = interval.getLow();
        if (Double.isInfinite(vi)) {
            return getCustomMin();
        }
        return vi;
    }

    @Override
    public double getIntervalEnd() {<FILL_FUNCTION_BODY>}

    @Override
    public TimeFormat getTimeFormat() {
        return graphModel.getTimeFormat();
    }

    public void setInterval(double start, double end) {
        this.interval = new Interval(start, end);
    }

    @Override
    public boolean hasValidBounds() {
        Interval i = graphModel.getTimeBounds();
        return !Double.isInfinite(i.getLow()) && !Double.isInfinite(i.getHigh());
    }

    public GraphModel getGraphModel() {
        return graphModel;
    }

    @Override
    public boolean isPlaying() {
        return playing.get();
    }

    public void setPlaying(boolean playing) {
        this.playing.set(playing);
    }

    @Override
    public int getPlayDelay() {
        return playDelay;
    }

    public void setPlayDelay(int playDelay) {
        this.playDelay = playDelay;
    }

    @Override
    public double getPlayStep() {
        return playStep;
    }

    public void setPlayStep(double playStep) {
        this.playStep = playStep;
    }

    @Override
    public PlayMode getPlayMode() {
        return playMode;
    }

    public void setPlayMode(PlayMode playMode) {
        this.playMode = playMode;
    }

    @Override
    public TimelineChart getChart() {
        return chart;
    }

    public void setChart(TimelineChart chart) {
        this.chart = chart;
    }
}

        double vi = interval.getHigh();
        if (Double.isInfinite(vi)) {
            return getCustomMax();
        }
        return vi;
    
<no_super_class>