#pragma once

// TapeManagerDlg.h : header file
//

#include <afxmt.h>
#include <Mmsystem.h>

#include "Tape.h"

#include <mutex>
#include <condition_variable>
#include <queue>
#include "GFResizeDialogHelper.h"

/////////////////////////////////////////////////////////////////////////////
// CTapeManagerDlg dialog
class CTapeUnit;
#define DIRECTSOUND_VERSION 0x1000

class CTapeManagerDlg : public CDialogEx
{
		enum : int          {CAPTURE_BUFFERS_NUM = 5};
		enum : int          {COLUMN_TYPE = 0, COLUMN_NAME, COLUMN_ADDR, COLUMN_LEN,
		                     COLUMN_TIME, COLUMN_WAVELEN, COLUMN_CRC, COLUMN_PATH
		                    };
		enum : int          {COMBO_NONE = 0, COMBO_SAVE_AS_MSF, COMBO_SAVE_AS_WAV, COMBO_SAVE_AS_BIN};

		int                 m_nSilenceLength;

		GFResizeDialogHelper m_Resizer;

		CCriticalSection    m_csModifyBuffer;
		CList <SAMPLE_INT *, SAMPLE_INT *>m_captureBuffers;
		SAMPLE_INT         *m_CurrentCaptureBuffer; // указатель на текущий буфер из m_captureBuffers

		bool                m_bRun;
		HWAVEIN             m_hWaveIn;
		WAVEHDR             m_WHDR[CAPTURE_BUFFERS_NUM];
		WAVEFORMATEX        m_wfx;

		bool                m_bCaptureMode;
		int                 m_nCaptureOffset;   // в сэмплах
		int                 m_nCaptureLength;   // в сэмплах
		CTape               m_TapeReader;
		CFile               m_captureFile;
		CString             m_strCaptureFileName;
		CList<CString, CString &> m_strCaptureFileNameList; // список временных файлов, которые надо удалить при закрытии диалога

		CImageList          m_imgList;

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

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

		int                 m_nTapePos;
		int                 m_nTapeCount;
		CString             m_strCurrentFolder;

		// 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 DWORD        GetBufferSampleLength() // возвращает длину буфера в сэмплах
		{
			return m_wfx.nSamplesPerSec;
		}

		void                ClearBuffers();

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

		CString             GetTmpFilePath();
		bool                WriteBuffer(SAMPLE_INT *pBuff, int nSizeInSamples);
		bool                IsCaptureEnd(SAMPLE_INT *pBuff, int nSizeInSamples);

		// 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(int type);

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

// Dialog Data
		enum { IDD = IDD_TAPE_MANAGER };
		CListCtrl   m_list;


// 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 OnSize(UINT nType, int cx, int cy);
		afx_msg void OnGetMinMaxInfo(MINMAXINFO *lpMMI);
		afx_msg void OnTmSelectall();
		afx_msg void OnDestroy();
		afx_msg void OnClose();
		DECLARE_MESSAGE_MAP()
};

