#include "stdafx.h"
#include "kohonen.h"
#include <math.h>

CKohonen::CKohonen()
{
	m_dwVectorLength = -1;
	m_dwVectorCount = 0;
	InitializeCriticalSection(&m_cs);
}

CKohonen::~CKohonen()
{
	Clear();
	DeleteCriticalSection(&m_cs);
}

void CKohonen::Add(WCHAR neuron, double *pdData)
{
	EnterCriticalSection(&m_cs);
	double *pdDataCopy = new double[m_dwVectorLength];
	memcpy(pdDataCopy, pdData, m_dwVectorLength * sizeof(double));
	m_mmapNeurons.insert(std::pair<WCHAR, double*>(neuron, pdDataCopy));
	m_dwVectorCount++;
	LeaveCriticalSection(&m_cs);
}

void CKohonen::Clear()
{
	EnterCriticalSection(&m_cs);
	std::multimap<WCHAR, double*>::iterator it;
	for ( it = m_mmapNeurons.begin(); it != m_mmapNeurons.end(); it++ )
	{
		delete[](it->second);
	}
	m_mmapNeurons.clear();
	m_dwVectorCount = 0;
	LeaveCriticalSection(&m_cs);
}

void CKohonen::SetVectorLength(DWORD dwVectorLength)
{
	EnterCriticalSection(&m_cs);
	Clear();
	m_dwVectorLength = dwVectorLength;
	LeaveCriticalSection(&m_cs);
}

DWORD CKohonen::GetVectorLength()
{
	DWORD dwRet;
	EnterCriticalSection(&m_cs);
	dwRet = m_dwVectorLength;
	LeaveCriticalSection(&m_cs);
	return dwRet;
}

BOOL CKohonen::GetOutput(double *pdData, WCHAR *pwcOut)
{
	BOOL bRet = FALSE;
	EnterCriticalSection(&m_cs);
	std::multimap<WCHAR, double*>::iterator it, result;
	result = m_mmapNeurons.end();
	double dMin = -1;
	for ( it = m_mmapNeurons.begin(); it != m_mmapNeurons.end(); it++ )
	{
		double dVal = 0;
		for ( DWORD i = 0; i < m_dwVectorLength; i++ )
		{
			double dVectVal = it->second[i] - pdData[i];
			dVal += dVectVal * dVectVal;
		}
		dVal = sqrt(dVal);
		if ( -1 == dMin || dVal < dMin)
		{
			dMin = dVal;
			result = it;
		}
	}

	if ( result != m_mmapNeurons.end() )
	{
		*pwcOut = result->first;
		bRet = TRUE;
	}

	LeaveCriticalSection(&m_cs);

	return bRet;
}

void CKohonen::Serialize(CArchive &ar)
{
	EnterCriticalSection(&m_cs);
	if ( ar.IsStoring() )
	{	// ukladani dat
		ar << m_dwVectorLength;
		ar << m_dwVectorCount;
		std::multimap<WCHAR, double*>::iterator it;
		for ( it = m_mmapNeurons.begin(); it != m_mmapNeurons.end(); it++ )
		{
			double* pVectorData = it->second;
			ar << it->first;
			for ( DWORD j = 0; j < m_dwVectorLength; j++ )
			{
				ar << pVectorData[j];
			}
		}
	}
	else
	{	// nacitani dat
		DWORD dwCount;
		DWORD dwVectorLength;
		ar >> dwVectorLength;
		SetVectorLength(dwVectorLength);
		ar >> dwCount;
		for ( DWORD i = 0; i < dwCount; i++ )
		{
			double *data = new double[m_dwVectorLength];
			WCHAR wcNeuron;
			ar >> wcNeuron;
			for ( DWORD j = 0; j < m_dwVectorLength; j++ )
			{
				ar >> data[j];
			}
			m_mmapNeurons.insert(std::pair<WCHAR, double*>(wcNeuron, data));
			m_dwVectorCount++;
		}
	}
	LeaveCriticalSection(&m_cs);
}

DWORD CKohonen::GetNeuronCount()
{
	return m_mmapNeurons.size();
}