#include <windows.h>
#include <stdlib.h>
#include <atlbase.h>
#include "reco.h"

//Konstruktor.
SpeechCommanding::SpeechCommanding(int editBox)
{
	 this->editBox = editBox;
}

//Metoda inicjalizujaca rozpoznawanie.
bool SpeechCommanding::initializeDialog(HWND dialogHandle)
{
	this->dialogHandle = dialogHandle;

    HRESULT result = S_OK;
	//Stworzenie recognition engine i ustawienie go na in-process.
    CComPtr<ISpRecognizer> cpRecoEngine;
    result = cpRecoEngine.CoCreateInstance(CLSID_SpInprocRecognizer);

    if(SUCCEEDED(result))
    {
		//Stworzenie kontekstu.
		result = cpRecoEngine->CreateRecoContext(&recognitionContext);
    }

    if (SUCCEEDED(result))
    {
		//Przypisanie zdarzenia rozpoznania do okna.
		result = recognitionContext->SetNotifyWindowMessage( dialogHandle, WM_RECOEVENT, 0, 0 );
    } 
    
    if (SUCCEEDED(result))
    {
        //Ustawienie typu zdarzenia.
		const ULONGLONG ullInterest = SPFEI(SPEI_RECOGNITION);
		recognitionContext->SetInterest(ullInterest, ullInterest);
    }

	//Stworzenie obiektu audio.
    CComPtr<ISpAudio> audio;
    SpCreateDefaultObjectFromCategoryId(SPCAT_AUDIOIN, &audio);

	//Okreslenie input stream do rozpoznania.
    cpRecoEngine->SetInput(audio, TRUE);
	//Ustawienie stanu rozpoznawania na aktywny.
    result = cpRecoEngine->SetRecoState( SPRST_ACTIVE );
    
    if (SUCCEEDED(result))
    {
		//Stworzenie gramatyki.
		result = recognitionContext->CreateGrammar(GID_COMMAND_CONTROL, &recognitionGrammar);
    }
    if  (SUCCEEDED(result))
    {
		//Wczytanie pliku z gramatyka.
		result = recognitionGrammar->LoadCmdFromFile(L"..\\SpeechLibrary\\grammar.cfg", SPLO_STATIC);
    }
    if (SUCCEEDED(result))
    {
		//Okreslenie, ktora z zasad zapisanych w pliku ma byc uzywana.
		result = recognitionGrammar->SetRuleState(L"Controls", NULL, SPRS_ACTIVE);
    }
    if (FAILED(result))
    {
        //Zwolnienie gramatyki.
		recognitionGrammar.Release();
    }

    return (result == S_OK);
}

//Metoda obslugajaca rozpoznanie.
int SpeechCommanding::processRecognitionEvent()
{
    CSpEvent event;

    while (event.GetFrom(recognitionContext) == S_OK)
    {
		if (event.eEventId == SPEI_RECOGNITION)
        {
            CSpDynamicString dstrText;

            //Pobieramy rozpoznany tekst.
			if (FAILED(event.RecoResult()->GetText(SP_GETWHOLEPHRASE, SP_GETWHOLEPHRASE, TRUE, &dstrText, NULL)))
            {
                return 0;
            }

            dstrText.Append(L" ");
					
			//Wysylamy rozpoznany tekst do pola tekstowego.
			SendDlgItemMessage(dialogHandle, editBox, EM_REPLACESEL, TRUE, (LPARAM)(LPTSTR)CW2T(dstrText));

			char *c = dstrText.CopyToChar();

			//W zaleznosci od rozpoznanej komendy zwracamy odpowiednia wartosc. Nie robie tego w switchu, bo do kazdej komendy mozna dodac jeszcze "please", wiec trzeba uzywac strncmp.
			if (strncmp(c,"Pan left", 8) == 0)
			{
				return 1;
			}

			if (strncmp(c,"Pan right", 9) == 0)
			{
				return 2;
			}

			if (strncmp(c,"Pan up", 6) == 0)
			{
				return 3;
			}

			if (strncmp(c,"Pan down", 8) == 0)
			{
				return 4;
			}

			if (strncmp(c, "Exit", 4) == 0)
			{
				return 5;
			}

			if (strncmp(c,"Rotate left", 11) == 0)
			{
				return 6;
			}

			if (strncmp(c,"Rotate right", 12) == 0)
			{
				return 7;
			}

			if (strncmp(c,"Rotate up", 9) == 0)
			{
				return 8;
			}

			if (strncmp(c,"Rotate down", 11) == 0)
			{
				return 9;
			}

			if (strncmp(c,"Zoom in", 7) == 0)
			{
				return 10;
			}

			if (strncmp(c,"Zoom out", 8) == 0)
			{
				return 11;
			}

			if (strncmp(c,"Help", 4) == 0)
			{
				return 12;
			}

			if (strncmp(c,"Load file", 9) == 0)
			{
				return 13;
			}
		}
    }

	return 0;
}