#pragma once

// TapeManagerDlg.h : header file
//

#include "BaseDialog.h"
#include "Tape.h"
#include "TapeUnit.h"
#include <afxmt.h>
#include <condition_variable>
#include <queue>
//#include <Mmsystem.h>

/////////////////////////////////////////////////////////////////////////////
// CTapeManagerDlg dialog

#define DIRECTSOUND_VERSION 0x1000

constexpr auto CAPTURE_BUFFERS_NUM = 5;

namespace TMLIST
{
	enum TMLIST : int
	{
		TYPE = 0,
		NAME,
		ADDR,
		LEN,
		TIME,
		WAVELEN,
		CRC,
		PATH
	};
}

namespace TMCOMBO
{
	enum TMCOMBO : int
	{
		NONE = 0,
		SAVE_AS_MSF,
		SAVE_AS_WAV,
		SAVE_AS_BIN
	};
}

class CTapeManagerDlg : public CBaseDialog
{
		DECLARE_DYNAMIC(CTapeManagerDlg)


		int                 m_nSilenceLength{ DEFAULT_SOUND_SAMPLE_RATE / 10 };

		int                 m_nTapePos{ 0 };
		int                 m_nTapeCount{ 0 };
		CString             m_strCurrentFolder{ g_Config.m_strTapePath.c_str() }; // начинаем обзор всегда с этого места. ВСЕГДА.

		CComboBox           m_comboSaveAs;
		CComboBox           m_comboDevices;
		CListCtrl           m_list;

		CCriticalSection    m_csModifyBuffer;
		std::list<std::unique_ptr<SAMPLE_INT[]>> m_arCaptureBuffers;
		SAMPLE_INT         *m_pCurrCaptureBuffer{ nullptr }; // указатель на текущий буфер из m_arCaptureBuffers

		bool                m_bCaptureMode{ false };
		size_t              m_nCaptureOffset{ 0 };   // в сэмплах
		size_t              m_nCaptureLength{ 0 };   // в сэмплах

		bool                m_bRun{ false };
		HWAVEIN             m_hWaveIn{ nullptr };
		std::array<WAVEHDR, CAPTURE_BUFFERS_NUM> m_WHDR{};
		WAVEFORMATEX        m_wfx{};

		CImageList          m_imgList{};
		CTape               m_TapeReader{};
		CFile               m_captureFile{};
		fs::path            m_strCaptureFileName;
		std::list<fs::path> m_strCaptureFileNameList; // список временных файлов, которые надо удалить при закрытии диалога

		std::thread         m_thrStatus;
		bool                m_bStatusExit{ false };      // флаг завершения потока
		std::queue<CTapeUnit *> m_queueStat;    // очередь, для передачи данных потоку
		std::mutex          m_mutModifyStatus;  // мутекс для синхронизации
		std::mutex          m_mutThr;           // мутекс потока. залочен пока поток живой
		std::condition_variable m_cvStatusNew;  // условная переменная, чтоб будить поток, когда надо

		bool                m_bCanceled{ false };        // флаг выполнения завершающих операций

		// Capture methods
		UINT                FillDevices();
		bool                OpenDevice();
		void                CloseDevice();
		void                UnInit();
		void                PrepareBuffers();
		void                UnPrepareBuffers();
		void                RemoveBuffers();
		void                InitBuffers();
		void                ProcessHeader(WAVEHDR *pHdr);

		void                StatusThread();

		inline size_t       GetBufferSampleLength() const // возвращает длину буфера в сэмплах
		{
			return size_t(m_wfx.nSamplesPerSec);
		}

		void                ClearBuffers();

		void                DebugDraw(SAMPLE_INT *pBuffer, size_t nSizeInSamples);
		void                OutString(const CString &str);

		fs::path            GetTmpFilePath() const;
		bool                WriteBuffer(const SAMPLE_INT *pBuff, const size_t nSizeInSamples);
		bool                IsCaptureEnd(const SAMPLE_INT *pBuff, const size_t nSizeInSamples) const;

		// Get file status methods
		void                InitListCtrl();
		void                InitComboCtrl();
		void                InsertNewUnit(CTapeUnit *pUnit);
		void                RetrieveInfo(CTapeUnit *pUnit);
		void                FileListChanged(int nTapeCount);
		void                SetFolder(const CString &strFolder);
		void                DeleteUnits(bool bSelected);
		void                SaveUnitsAs(CTapeUnit::TAPETYPE type);

// Construction
	public:
		CTapeManagerDlg(CWnd *pParent = nullptr);   // standard constructor
		virtual ~CTapeManagerDlg() override;

// Dialog Data
#ifdef AFX_DESIGN_TIME
		enum { IDD = IDD_TAPE_MANAGER };
#endif

// Overrides
	protected:
		virtual void DoDataExchange(CDataExchange *pDX) override;    // DDX/DDV support

// Implementation
	protected:
		virtual BOOL OnInitDialog() override;
		virtual void OnCancel() override;
		afx_msg LRESULT OnBufferReady(WPARAM, LPARAM);
		afx_msg LRESULT OnInfoReady(WPARAM wParam, LPARAM lParam);
		afx_msg LRESULT OnWaveInProc(WPARAM wParam, LPARAM lParam);
		afx_msg void OnCbnSelchangeTmDevices();
		afx_msg void OnTmLoad();
		afx_msg void OnGetdispinfoTmList(NMHDR *pNMHDR, LRESULT *pResult);
		afx_msg void OnTmBrowse();
		afx_msg void OnTmRemove();
		afx_msg void OnUpdateTmRemove(CCmdUI *pCmdUI);
		afx_msg void OnSelendokTmSaveAs();
		afx_msg void OnUpdateSelendokTmSaveAs(CCmdUI *pCmdUI);
		afx_msg void OnRclickTmList(NMHDR *pNMHDR, LRESULT *pResult);
		afx_msg void OnTmSelectall();
		afx_msg void OnTmUnselectall();
		afx_msg void OnDestroy();
		afx_msg void OnClose();
		DECLARE_MESSAGE_MAP()
};

