/*
* SACD Decoder plugin
* Copyright (c) 2011-2022 Maxim V.Anisiutkin <maxim.anisiutkin@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifndef _OUTPUT_BACKTRACE_H_INCLUDED
#define _OUTPUT_BACKTRACE_H_INCLUDED

class output_backtrace_t {
	const size_t   MAX_SEGMENTS        = 100;
	const uint64_t MAX_SPEC_TRANSITION = 50;
	struct segment_t {
		audio_chunk::spec_t m_spec;
		double              m_duration;
	};
	std::list<segment_t> m_segments;
	uint64_t             m_time;
	audio_chunk::spec_t  m_spec;
public:
	void flush() {
		m_segments.clear();
		m_spec.clear();
	}
	bool add_chunk(const audio_chunk::spec_t& p_spec, double p_duration) {
		bool segment_added{ false };
		if (m_segments.empty() || m_segments.begin()->m_spec != p_spec) {
			m_segments.push_front({ p_spec, p_duration });
			if (m_segments.size() > MAX_SEGMENTS) {
				m_segments.pop_back();
			}
			segment_added = true;
		}
		else {
			m_segments.begin()->m_duration += p_duration;
		}
		return segment_added;
	}
	bool get_spec(audio_chunk::spec_t& p_spec, double p_backtime) {
		double duration{ 0.0 };
		audio_chunk::spec_t spec;
		for (auto& segment : m_segments) {
			duration += segment.m_duration;
			if (p_backtime < duration) {
				spec = segment.m_spec;
				break;
			}
		}
		if (!spec.is_valid() || spec == m_spec || GetTickCount64() < m_time) {
			p_spec = m_spec;
			return false;
		}
		else {
			m_spec = spec;
			m_time = GetTickCount64() + MAX_SPEC_TRANSITION;
		}
		p_spec = m_spec;
		return true;
	}
};

#endif
