#include "dsd_path.h"

const LPCTSTR dsd_path_t::control_path = _T("Local\\foo_dsd_asio_control_path");
const LPCTSTR dsd_path_t::dsddata_path = _T("Local\\foo_dsd_asio_dsddata_path");
const LPCTSTR dsd_path_t::access_mutex = _T("Local\\foo_dsd_asio_access_mutex");

dsd_path_t::dsd_path_t() {
	memset(this, 0, sizeof(*this));
}

void dsd_path_t::acquire() {
	WaitForSingleObject(hMutex, DSD_WAIT_TIME);
}

void dsd_path_t::release() {
	ReleaseMutex(hMutex);
}

dsd_control_t* dsd_path_t::get_control() const {
	return p_control;
}

dsd_dsddata_t* dsd_path_t::get_dsddata() const {
	return p_dsddata;
}

DWORD dsd_path_t::create_control_channel() {
	DWORD hr;
	if (p_control) {
		return ERROR_SUCCESS;
	}
	hMutex = CreateMutex(NULL, FALSE, access_mutex);
	if (!hMutex) {
		hr = GetLastError();
		return hr;
	}
	hControl = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(dsd_control_t), control_path);
	if (!hControl) {
		hr = GetLastError();
		CloseHandle(hMutex);
		hMutex = NULL;
		return hr;
	}
	p_control = (dsd_control_t*)MapViewOfFile(hControl, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(dsd_control_t));
	if (!p_control) {
		hr = GetLastError();
		CloseHandle(hMutex);
		hMutex = NULL;
		CloseHandle(hControl);
		hControl = NULL;
		return hr;
	}
	return ERROR_SUCCESS;
}

DWORD dsd_path_t::create_dsddata_channel() {
	DWORD hr;
	if (p_dsddata) {
		return ERROR_SUCCESS;
	}
	hDsdData = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(dsd_dsddata_t), dsddata_path);
	if (!hDsdData) {
		hr = GetLastError();
		return hr;
	}
	p_dsddata = (dsd_dsddata_t*)MapViewOfFile(hDsdData, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(dsd_dsddata_t));
	if (!p_dsddata) {
		hr = GetLastError();
		CloseHandle(hDsdData);
		hDsdData = NULL;
		return hr;
	}
	acquire();
	p_dsddata->attr.pipe_pace         = DSD_DATA_PACE;
	p_dsddata->attr.pipe_size         = 0;
	p_dsddata->attr.pipe_end          = DSD_DATA_SIZE;
	p_dsddata->attr.pipe_read_offset  = 0;
	p_dsddata->attr.pipe_write_offset = 0;
	release();
	memset(p_dsddata->pipe_data, DSD_SILENCE_BYTE, DSD_READ_SIZE);
	return ERROR_SUCCESS;
}

DWORD dsd_path_t::attach_control_channel() {
	DWORD hr;
	if (p_control) {
		return ERROR_SUCCESS;
	}
	hMutex = OpenMutex(SYNCHRONIZE, FALSE, access_mutex);
	if (!hMutex) {
		hr = GetLastError();
		return hr;
	}
	hControl = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, control_path);
	if (!hControl) {
		hr = GetLastError();
		return hr;
	}
	p_control = (dsd_control_t*)MapViewOfFile(hControl, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(dsd_control_t));
	if (!p_control) {
		hr = GetLastError();
		CloseHandle(hMutex);
		hMutex = NULL;
		CloseHandle(hControl);
		hControl = NULL;
		return hr;
	}
	return ERROR_SUCCESS;
}

DWORD dsd_path_t::attach_dsddata_channel() {
	DWORD hr;
	if (p_dsddata) {
		return ERROR_SUCCESS;
	}
	hDsdData = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, dsddata_path);
	if (!hDsdData) {
		hr = GetLastError();
		CloseHandle(hMutex);
		hMutex = NULL;
		return hr;
	}
	p_dsddata = (dsd_dsddata_t*)MapViewOfFile(hDsdData, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(dsd_dsdattr_t));
	if (!p_dsddata) {
		hr = GetLastError();
		CloseHandle(hDsdData);
		hDsdData = NULL;
		return hr;
	}
	int pipe_memsize = p_dsddata->attr.pipe_end + DSD_READ_SIZE;
	UnmapViewOfFile(p_dsddata);
	p_dsddata = (dsd_dsddata_t*)MapViewOfFile(hDsdData, FILE_MAP_ALL_ACCESS, 0, 0, pipe_memsize);
	if (!p_dsddata) {
		hr = GetLastError();
		CloseHandle(hDsdData);
		hDsdData = NULL;
		return hr;
	}
	return ERROR_SUCCESS;
}

void dsd_path_t::close_control_channel() {
	DWORD hr;
	if (p_control) {
		UnmapViewOfFile(p_control);
		p_control = NULL;
	}
	if (hControl) {
		hr = CloseHandle(hControl);
		hControl = NULL;
	}
	if (hMutex) {
		hr = CloseHandle(hMutex);
		hMutex = NULL;
	}
}

void dsd_path_t::close_dsddata_channel() {
	DWORD hr;
	if (p_dsddata) {
		UnmapViewOfFile(p_dsddata);
		p_dsddata = NULL;
	}
	if (hDsdData) {
		hr = CloseHandle(hDsdData);
		hDsdData = NULL;
	}
}

void dsd_path_t::flush_dsddata_channel() {
	if (p_dsddata) {
		acquire();
		p_dsddata->attr.pipe_read_offset = p_dsddata->attr.pipe_write_offset;
		p_dsddata->attr.pipe_size = 0;
		release();
	}
}
