#include "stdafx.h"
#include "WaveParserAmp.h"

CWaveParserAmp::CWaveParserAmp()
    = default;


CWaveParserAmp::~CWaveParserAmp()
    = default;



//////////////////////////////////////////////////////////////////////
// Вход: pos - текущая позиция в сэмплах
// Выход: длина импульса в сэмплах
int CWaveParserAmp::CalcImpLength(WaveData &pWave, int &pos)
{
	auto nWaveLength = int(pWave.size());

	if (pos >= nWaveLength)
	{
		return CWaveParserProto::BAD_LENGTH;
	}

	int len_0 = 0;
	int len_1 = 0;

	if (m_bInverse)
	{
		// Пропускаем инверсные импульсы
		while (GetCurrentSample(pWave, pos))
		{
			if (++pos >= nWaveLength)
			{
				return CWaveParserProto::BAD_LENGTH;
			}
		}

		// Считаем количество единиц
		while (!GetCurrentSample(pWave, pos))
		{
			len_1++;

			if (++pos >= nWaveLength)
			{
				return CWaveParserProto::BAD_LENGTH;
			}
		}

		// Считаем количество нулей
		while (GetCurrentSample(pWave, pos))
		{
			len_0++;

			if (++pos >= nWaveLength)
			{
				return CWaveParserProto::BAD_LENGTH;
			}
		}
	}
	else
	{
		// Пропускаем инверсные импульсы
		while (!GetCurrentSample(pWave, pos))
		{
			if (++pos >= nWaveLength)
			{
				return CWaveParserProto::BAD_LENGTH;
			}
		}

		// Считаем количество единиц
		while (GetCurrentSample(pWave, pos))
		{
			len_1++;

			if (++pos >= nWaveLength)
			{
				return CWaveParserProto::BAD_LENGTH;
			}
		}

		// Считаем количество нулей
		while (!GetCurrentSample(pWave, pos))
		{
			len_0++;

			if (++pos >= nWaveLength)
			{
				return CWaveParserProto::BAD_LENGTH;
			}
		}
	}

	return len_1 + len_0;
}

bool CWaveParserAmp::GetCurrentSample(WaveData &pWave, int pos)
{
	return pWave.at(pos) >= m_dAverage;
}


// поиск первого маркера
bool CWaveParserAmp::FindMarker1(WaveData &pWave)
{
	auto nWaveLength = int(pWave.size());
	int size = 0;
	int pos = m_nPos;

	for (;;)
	{
		int len_1 = 0;

		if (pos >= nWaveLength)
		{
			return false;
		}

		// Считаем количество единиц
		while (GetCurrentSample(pWave, pos))
		{
			if (++pos >= nWaveLength)
			{
				return false;
			}

			len_1++;
		}

		double l = double(len_1) / GetAvgImpLen();

		if (MinusDelta(4.0) / 2.0 <= l && l <= PlusDelta(4.0) / 2.0)
		{
			break;
		}

		int len_0 = 0;

		if (pos >= nWaveLength)
		{
			return false;
		}

		// Считаем количество нулей
		while (!GetCurrentSample(pWave, pos))
		{
			if (++pos >= nWaveLength)
			{
				return false;
			}

			len_0++;
		}

		l = double(len_0) / GetAvgImpLen();

		if (MinusDelta(4.0) / 2.0 <= l && l <= PlusDelta(4.0) / 2.0)
		{
			m_bInverse = true;
			break;
		}
	}

	m_nPos = pos;
	bool bBit{};

	if (ReadBit(pWave, bBit))
	{
		return bBit;    // в правильном маркере бит - "1"
	}

	return false;
}


int CWaveParserAmp::GetImpulseLen(WaveData &pWave)
{
	CalcAverage(pWave);
	DWORD nStartTunung = 0;
	int nLength = 0;
	m_nPos = 0;
	InitAvgImp();

	// ищем настроечную последовательность в начале файла
	if (FindTuning(true, false, pWave, TUNESEQ_LENGTH, nStartTunung, nLength))
	{
		m_nPos = 0;
		return int(GetAvgImpLen() + 0.5);
	}

	m_nPos = 0;
	return CWaveParserProto::BAD_LENGTH;
}

// вход: pWave - ваве данные
//      startPos - откуда начинать поиск в сэмплах
// выход: 0 - успешно, <0 - код ошибки
//      nTuneStart - начало стартовой последовательности
//      nTuneLength - длина стартовой последовательности
//      nMarkerPos - позиция маркера
int CWaveParserAmp::FindNextTuning(WaveData &pWave, int startPos, int &nTuneStart, int &nTuneLength, int &nMarkerPos)
{
	m_nPos = startPos;  // зададим начальную позицию
	CalcAverage(pWave); // посчитаем среднее значение
	m_bInverse = false;
	// ищем настроечную последовательность в начале файла
	DWORD dwStart = -1; nTuneLength = -1;
	int nRet = 0;

	do
	{
		// функция ищет настроечную последовательность, и может получить ложное срабатывание, на участке из кучи нулей
		if (FindTuning(true, false, pWave, TUNESEQ_LENGTH, dwStart, nTuneLength))
		{
			nTuneStart = int(dwStart);
			const int nMarkerStart = m_nPos; // при успешном выходе из функции эта переменная указывает на начало маркера за синхропоследовательностью

			if (FindMarker1(pWave)) // функция ищет маркер, и может убежать далеко вперёд, пока не найдёт что-то подходящее
			{
				// m_nPos  на выходе - указывает на конец маркера и начало данных за ним.
				// если позиция маркера не сильно далеко от конца настроечной последовательности, то мы нашли верную последовательность
				// длина маркера примерно 8 длин синхроимпульсов, + ещё запас, длстаточно 10, но пусть будет 12
				if (m_nPos - nMarkerStart < int(GetAvgImpLen() * 12.0))
				{
					nMarkerPos = nMarkerStart;
					return 0;
				}

				// откат, чтобы заново искать настроечную последовательность
				m_nPos = nMarkerStart;
			}

			nRet = CWaveParserProto::BAD_MARKER;
		}
		else
		{
			nRet = CWaveParserProto::BAD_TUNING;
		}
	}
	while (m_nPos < int(pWave.size()));

	return nRet;
}

