
#define _CRT_SECURE_NO_WARNINGS	  /* disable compiler warnings for standard C functions like strcpy() */

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winuser.h>

#include "globals.h"
#include "resource.h"

int APIENTRY WinMain(HINSTANCE hInstance,
					 HINSTANCE hPrevInstance,
					 LPSTR lpCmdLine,
					 int nCmdShow)

{
MSG			msg;
WNDCLASS	wc;
LRESULT		CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
FILE		*fpt;
int			i;

wc.style=CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc=(WNDPROC)WndProc;
wc.cbClsExtra=0;
wc.cbWndExtra=0;
wc.hInstance=hInstance;
hInst=hInstance;
wc.hIcon=LoadIcon(hInstance,MAKEINTRESOURCE(ID_ICON));
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName=MAKEINTRESOURCE(ID_MAIN_MENU);
wc.lpszClassName="CAFEVIEW";

if (!RegisterClass(&wc))
  return(FALSE);

MainWnd=CreateWindow("CAFEVIEW","Cafeteria Data Review",
			WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL | WS_MAXIMIZE,
			0,0,600+650,800,NULL,NULL,hInstance,NULL);
if (!MainWnd)
  return(FALSE);

ShowScrollBar(MainWnd,SB_BOTH,FALSE);
ShowWindow(MainWnd,SW_MAXIMIZE);
InvalidateRect(MainWnd,NULL,TRUE);
UpdateWindow(MainWnd);

DataStretch[0]=DataStretch[1]=DataStretch[2]=30.0;
DataStretch[3]=DataStretch[4]=DataStretch[5]=1.0;
DataStretch[6]=0.1;
FFspeed=15;

		/* check for master list; allows scrolling through multiple files using keystrokes */
TotalFilenames=0;
fpt=fopen("WINDOWS_FILENAMES.txt","r");
if (fpt == NULL)
  fpt=fopen("..\\WINDOWS_FILENAMES.txt","r");
if (fpt != NULL)
  {
  while (1)
	{
	i=fscanf(fpt,"%s",NameList[TotalFilenames]);
	if (i != 1)
	  break;
	TotalFilenames++;
	}
  fclose(fpt);
  }

InitializeDataVariables();
RollThresh=10.0;	  /* deg/sec */
Time1Thresh=30;		  /* samples at 15 Hz */
Time2Thresh=15;		  /* samples at 15 Hz */

SCALE_WINDOW=30;
SCALE_ROWS=8;
SCALE_COLS=12;
scale_image=(unsigned char *)calloc(SCALE_ROWS*SCALE_COLS,1);
scale_video=NULL;

while (GetMessage(&msg,NULL,0,0))
  {
  TranslateMessage(&msg);
  DispatchMessage(&msg);
  }
return(msg.wParam);
}



LRESULT CALLBACK WndProc (HWND hWnd,
						  UINT uMsg,
						  WPARAM wParam,
						  LPARAM lParam)

{
int				i,j,closest;
OPENFILENAME	ofn;
HMENU			hAppMenu;
char			text[320];

switch (uMsg)
  {
  case WM_COMMAND:
	switch (LOWORD(wParam))
	  {
	  case ID_FILE_LOAD:
		memset(&(ofn),0,sizeof(ofn));
		ofn.lStructSize=sizeof(ofn);
		ofn.lpstrFile=DataFilename;
		DataFilename[0]=0;
		ofn.nMaxFile=320;
		ofn.Flags=OFN_EXPLORER | OFN_HIDEREADONLY;
		ofn.lpstrFilter="Data files\0?????????????????.txt\0All files\0*.*\0\0";
//		ofn.lpstrFilter="All files\0*.*\0\0";
		if (!( GetOpenFileName(&ofn))  ||  DataFilename[0] == '\0')
		  break;
						/* set currentpath to where file loaded from */
		strcpy(CurrentPath,DataFilename);
		i=strlen(CurrentPath)-1;
		while (i > 0  &&  CurrentPath[i] != '\\')
		  i--;
		CurrentPath[i]='\0';
		SetCurrentDirectory((LPCTSTR)CurrentPath);
		if (VideoLoaded)
		  {
		  if (disp_image != NULL)
			{
			free(disp_image);
			disp_image=NULL;
			}
		  CloseVideoFile();
		  }
		InitializeDataVariables();
		ReadFiles();
		sprintf(text,"Cafeteria Data Review   %s   %s",DataFilename,GTFilename);
		SetWindowText(hWnd,text);
		PaintImage();
		break;

	  case ID_FILE_LOADGT:
		memset(&(ofn),0,sizeof(ofn));
		ofn.lStructSize=sizeof(ofn);
		ofn.lpstrFile=GTFilename;
		GTFilename[0]=0;
		ofn.nMaxFile=320;
		ofn.Flags=OFN_EXPLORER | OFN_HIDEREADONLY;
		ofn.lpstrFilter="GT files\0gt_*.txt\0All files\0*.*\0\0";
		if (!( GetOpenFileName(&ofn))  ||  GTFilename[0] == '\0')
		  break;
		LoadGT();
		sprintf(text,"Cafeteria Data Review   %s   %s",DataFilename,GTFilename);
		SetWindowText(hWnd,text);
		PaintImage();
		break;
	  case ID_SAVE_GT:
		if (Playing != 0  ||  DataLoaded == 0  ||  TotalGTBites == 0)
		  break;
		memset(&(ofn),0,sizeof(ofn));
		ofn.lStructSize=sizeof(ofn);
		ofn.lpstrFile=GTFilename;
		ofn.nMaxFile=320;
		ofn.Flags=OFN_EXPLORER | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
		ofn.lpstrFilter="GT files\0gt_*.txt\0All files\0*.*\0\0";
		if (!( GetSaveFileName(&ofn))  ||  GTFilename[0] == '\0')
		  break;
		SaveGT(GTFilename);
		sprintf(text,"Cafeteria Data Review   %s   %s",DataFilename,GTFilename);
		SetWindowText(hWnd,text);
		PaintImage();
		break;
	  case ID_LOAD_MD_BITES:
		memset(&(ofn),0,sizeof(ofn));
		ofn.lStructSize=sizeof(ofn);
		ofn.lpstrFile=text;
		text[0]=0;
		ofn.nMaxFile=320;
		ofn.Flags=OFN_EXPLORER | OFN_HIDEREADONLY;
		ofn.lpstrFilter="MD files\0md_*.txt\0All files\0*.*\0\0";
		if (!( GetOpenFileName(&ofn))  ||  text[0] == '\0')
		  break;
		LoadMDBites(text);
		PaintImage();
		break;

	  case ID_LOAD_GESTURES:
		memset(&(ofn),0,sizeof(ofn));
		ofn.lStructSize=sizeof(ofn);
		ofn.lpstrFile=text;
		text[0]=0;
		ofn.nMaxFile=320;
		ofn.Flags=OFN_EXPLORER | OFN_HIDEREADONLY;
		ofn.lpstrFilter="gesture files\0gesture*.txt\0All files\0*.*\0\0";
		if (!( GetOpenFileName(&ofn))  ||  text[0] == '\0')
		  break;
		LoadGestures(text,&TotalGTGestures,GTGestureStart,GTGestureEnd,GTGestureType);
		PaintImage();
		break;
	  case ID_LOAD_MD_GESTURES:
		memset(&(ofn),0,sizeof(ofn));
		ofn.lStructSize=sizeof(ofn);
		ofn.lpstrFile=text;
		text[0]=0;
		ofn.nMaxFile=320;
		ofn.Flags=OFN_EXPLORER | OFN_HIDEREADONLY;
		ofn.lpstrFilter="gesture files\0gesture*.txt\0All files\0*.*\0\0";
		if (!( GetOpenFileName(&ofn))  ||  text[0] == '\0')
		  break;
		LoadGestures(text,&TotalMDGestures,MDGestureStart,MDGestureEnd,MDGestureType);
		PaintImage();
		break;

	  case ID_DATA_SMOOTH:
		ViewSmoothed=(ViewSmoothed+1)%2;
		hAppMenu=GetMenu(hWnd);
		if (ViewSmoothed == 1)
		  CheckMenuItem(hAppMenu,ID_DATA_SMOOTH,MF_CHECKED);
		else
		  CheckMenuItem(hAppMenu,ID_DATA_SMOOTH,MF_UNCHECKED);
		PaintImage();
		break;
	  case ID_DISPLAY_ACCELEROMETERS:
		DisplayAccs=(DisplayAccs+1)%2;
		hAppMenu=GetMenu(hWnd);
		if (DisplayAccs == 1)
		  CheckMenuItem(hAppMenu,ID_DISPLAY_ACCELEROMETERS,MF_CHECKED);
		else
		  CheckMenuItem(hAppMenu,ID_DISPLAY_ACCELEROMETERS,MF_UNCHECKED);
		PaintImage();
		break;
	  case ID_DISPLAY_GYROSCOPES:
		DisplayGyros=(DisplayGyros+1)%2;
		hAppMenu=GetMenu(hWnd);
		if (DisplayGyros == 1)
		  CheckMenuItem(hAppMenu,ID_DISPLAY_GYROSCOPES,MF_CHECKED);
		else
		  CheckMenuItem(hAppMenu,ID_DISPLAY_GYROSCOPES,MF_UNCHECKED);
		PaintImage();
		break;
	  case ID_DISPLAY_ROLL_ONLY:
		DisplayRollOnly=(DisplayRollOnly+1)%2;
		hAppMenu=GetMenu(hWnd);
		if (DisplayRollOnly == 1)
		  CheckMenuItem(hAppMenu,ID_DISPLAY_ROLL_ONLY,MF_CHECKED);
		else
		  CheckMenuItem(hAppMenu,ID_DISPLAY_ROLL_ONLY,MF_UNCHECKED);
		PaintImage();
		break;
	  case ID_DISPLAY_SCALE:
		DisplayScale=(DisplayScale+1)%2;
		hAppMenu=GetMenu(hWnd);
		if (DisplayScale == 1)
		  CheckMenuItem(hAppMenu,ID_DISPLAY_SCALE,MF_CHECKED);
		else
		  CheckMenuItem(hAppMenu,ID_DISPLAY_SCALE,MF_UNCHECKED);
		PaintImage();
		break;
	  case ID_DISPLAY_GROUNDTRUTH:
		DisplayGT=(DisplayGT+1)%2;
		hAppMenu=GetMenu(hWnd);
		if (DisplayGT == 1)
		  CheckMenuItem(hAppMenu,ID_DISPLAY_GROUNDTRUTH,MF_CHECKED);
		else
		  CheckMenuItem(hAppMenu,ID_DISPLAY_GROUNDTRUTH,MF_UNCHECKED);
		PaintImage();
		break;
	  case ID_DISPLAY_MACHINEDETECTIONS:
		DisplayMDBites=(DisplayMDBites+1)%2;
		hAppMenu=GetMenu(hWnd);
		if (DisplayMDBites == 1)
		  CheckMenuItem(hAppMenu,ID_DISPLAY_MACHINEDETECTIONS,MF_CHECKED);
		else
		  CheckMenuItem(hAppMenu,ID_DISPLAY_MACHINEDETECTIONS,MF_UNCHECKED);
		PaintImage();
		break;
	  case ID_DISPLAY_EVALUATIONLINKS:
		DisplayEvaluationLinks=(DisplayEvaluationLinks+1)%2;
		hAppMenu=GetMenu(hWnd);
		if (DisplayEvaluationLinks == 1)
		  CheckMenuItem(hAppMenu,ID_DISPLAY_EVALUATIONLINKS,MF_CHECKED);
		else
		  CheckMenuItem(hAppMenu,ID_DISPLAY_EVALUATIONLINKS,MF_UNCHECKED);
		PaintImage();
		break;

	  case ID_ANALYSIS_PATTERNPARAMETERS:
		DialogBox(hInst,MAKEINTRESOURCE(IDD_ANALYSIS_PARAMS),hWnd,(DLGPROC)ChangeAnalysisParams);
		if (DataLoaded == 1)
		  {		/* rerun bite detection with new parameters */
		  MachineDetectBites();
		  EvaluateBiteDetections();
		  }
		PaintImage();
		break;

	  case ID_EDIT_FF_SPEED:
		DialogBox(hInst,MAKEINTRESOURCE(IDD_FF_DIALOG),hWnd,(DLGPROC)ChangeFFSpeed);
		PaintImage();
		break;

	  case ID_EDIT_BITE:
		if (DataLoaded == 0  ||  Playing != 0)
		  break;
		DialogBox(hInst,MAKEINTRESOURCE(IDD_DIALOG_BITE),hWnd,(DLGPROC)RecordBiteInfo);
		PaintImage();
		break;

	  case ID_DELETE_BITE:
		if (DataLoaded == 0  ||  Playing != 0  ||  TotalGTBites == 0)
		  break;
		for (i=0; i<TotalGTBites; i++)
		  if (GTBiteIndex[i] == TimeIndex)
			break;
		if (i < TotalGTBites)
		  {
		  if (MessageBox(hWnd,"Confirm bite deletion?","Confirm bite deletion",MB_YESNO) != IDYES)
			break;
		  for (j=i; j<TotalGTBites-1; j++)
			{
			GTBiteIndex[j]=GTBiteIndex[j+1];
			strcpy(GTBiteHand[j],GTBiteHand[j+1]);
			strcpy(GTBiteUtensil[j],GTBiteUtensil[j+1]);
			strcpy(GTBiteContainer[j],GTBiteContainer[j+1]);
			strcpy(GTBiteFood[j],GTBiteFood[j+1]);
			}
		  TotalGTBites--;
		  SaveGT("gt_temp.txt");
		  PaintImage();
		  }
		break;

	  case ID_SNAP_BITE:
		if (DataLoaded == 0  ||  Playing != 0  ||  TotalGTBites == 0)
		  break;
		closest=0;
		for (i=1; i<TotalGTBites; i++)
		  if (abs(GTBiteIndex[i]-TimeIndex) < abs(GTBiteIndex[closest]-TimeIndex))
			closest=i;
		if (abs(GTBiteIndex[closest]-TimeIndex) > 15)
		  if (MessageBox(hWnd,"Confirm snap?","Snap distance >1 second",MB_YESNO) != IDYES)
			break;
		GTBiteIndex[closest]=TimeIndex;
		SaveGT("gt_temp.txt");
		PaintImage();
		break;

	  case ID_HELP_KEYS:
		sprintf(text,"Key(s)\tAction(s)\n-------------------------------------------------\n");
		strcat(text,"asdfg\tplayback controls   << < [] > >>\n");
		strcat(text,"[]\tprevious/next bite\n");
		strcat(text,"b\tadd/edit bite\n");
		strcat(text,"p\tplayback bite (-1 sec ... +1 sec)\n");
		strcat(text,"-+\tload prev/next file\n");
		MessageBox(hWnd,text,"Keyboard controls",MB_OK | MB_APPLMODAL);
		break;

	  case ID_QUIT:
		if (VideoLoaded)
		  {
		  if (disp_image != NULL)
			{
			free(disp_image);
			disp_image=NULL;
			}
		  CloseVideoFile();
		  VideoLoaded=0;
		  }
		Sleep(100);
		DestroyWindow(hWnd);
		break;
		
	  }
	break;

  case WM_HSCROLL:
	if (Playing == 1)
	  break;
	if (LOWORD(wParam) == SB_LINELEFT)  
	  {
	  if (TimeIndex-1 < 0)
		TimeIndex=0; 
	  else
		TimeIndex--;
	  }
	if (LOWORD(wParam) == SB_LINERIGHT) 
	  {
	  if (TimeIndex+1 > TotalData-1)
		TimeIndex=TotalData-1;
	  else
		TimeIndex++;
	  }
	if (LOWORD(wParam) == SB_PAGELEFT) 
	  {
	  if (TimeIndex-DataDisplayWidth < 0)
		TimeIndex=0; 
	  else
		TimeIndex-=DataDisplayWidth;		
	  }
	if (LOWORD(wParam) == SB_PAGERIGHT)
	  {	
	  if (TimeIndex+DataDisplayWidth > TotalData-1)
		TimeIndex=TotalData-1; 
	  else
		TimeIndex+=DataDisplayWidth;
	  }
	if (LOWORD(wParam) == SB_THUMBPOSITION)
	  {
	  TimeIndex=HIWORD(wParam);
	  }
	PaintImage();
	break;

  case WM_CHAR:
									/* all these controls set the current PlayJump */
	if (((TCHAR)wParam == 'a') || ((TCHAR)wParam == 'A'))
 	  {
	  PlayJump=((TCHAR)wParam == 'a' ? -FFspeed : -FFspeed*5);
	  UpdateDisplay();
	  }
	if (((TCHAR)wParam == 's') || ((TCHAR)wParam == 'S'))
 	  {
	  PlayJump=-1;
	  UpdateDisplay();
	  }
	if (((TCHAR)wParam == 'f') || ((TCHAR)wParam == 'F'))
 	  {
	  PlayJump=+1;
	  UpdateDisplay();
	  }
	if (((TCHAR)wParam == 'g') || ((TCHAR)wParam == 'G'))
 	  {
	  PlayJump=((TCHAR)wParam == 'g' ? FFspeed : FFspeed*5);
	  UpdateDisplay();
	  }
	if (((TCHAR)wParam == 'd') || ((TCHAR)wParam == 'D'))
	  {	
	  Playing=(Playing+1)%2;
	  if (Playing == 1)
		SetTimer(hWnd,TIMER_SECOND,10,NULL);
	  else
		KillTimer(hWnd,TIMER_SECOND);
	  UpdateDisplay();
	  }
	if (((TCHAR)wParam == '[') || ((TCHAR)wParam == '{'))
	  {
	  for (i=TotalGTBites-1; i>=0; i--)
		if (GTBiteIndex[i] < TimeIndex)
		  break;
	  if (i >= 0)
		{
		TimeIndex=GTBiteIndex[i];
		PaintImage();
		}
	  }
	if (((TCHAR)wParam == ']') || ((TCHAR)wParam == '}'))
	  {
	  for (i=0; i<TotalGTBites; i++)
		if (GTBiteIndex[i] > TimeIndex)
		  break;
	  if (i < TotalGTBites)
		{
		TimeIndex=GTBiteIndex[i];
		PaintImage();
		}
	  }
	if (((TCHAR)wParam == 'b') || ((TCHAR)wParam == 'B'))
	  {
	  SendMessage(hWnd,WM_COMMAND,ID_EDIT_BITE,0);
	  }
	if (((TCHAR)wParam == 'p') || ((TCHAR)wParam == 'P'))	  /* play a bite -- from 3 seconds before, to 3 seconds after current time */
	  {
	  if (PlayCountdown == 0)
		{		/* start playback of bite 1 second prior and end 1 second after */
		TimeIndex-=15;
		if (TimeIndex < 0)
		  TimeIndex=0;
		PlayJump=+1;
		PlayCountdown=30;
		SendMessage(hWnd,WM_CHAR,(TCHAR)'d',0);
		}
	  else
		{		/* end playback currently in operation */
		PlayCountdown=0;
		SendMessage(hWnd,WM_CHAR,(TCHAR)'d',0);
		}
	  }
	if ((TCHAR)wParam == '-'  ||  (TCHAR)wParam == '+')
	  {
	  for (i=0; i<TotalFilenames; i++)
		if (strcmp(NameList[i],DataFilename) == 0)
		  break;
	  if ((TCHAR)wParam == '-'  &&  i > 0)
		strcpy(DataFilename,NameList[i-1]);
	  else if ((TCHAR)wParam == '+'  &&  i < TotalFilenames-1)
		strcpy(DataFilename,NameList[i+1]);
	  else if (DataLoaded == 0  &&  TotalFilenames > 0)
		strcpy(DataFilename,NameList[0]);
	  else
		break;	  /* no change; do not reload */
	  strcpy(CurrentPath,DataFilename);
	  i=strlen(CurrentPath)-1;
	  while (i > 0  &&  CurrentPath[i] != '\\')
		i--;
	  CurrentPath[i]='\0';
	  SetCurrentDirectory((LPCTSTR)CurrentPath);
	  if (VideoLoaded)
		{
		if (disp_image != NULL)
		  {
		  free(disp_image);
		  disp_image=NULL;
		  }
		CloseVideoFile();
		}
	  InitializeDataVariables();
	  ReadFiles();
	  sprintf(GTFilename,"%s\\gt_union.txt",CurrentPath);
	  LoadGT();
	  sprintf(text,"Cafeteria Data Review   %s   %s",DataFilename,GTFilename);
	  SetWindowText(hWnd,text);
	  MachineDetectBites();
	  EvaluateBiteDetections();
	  PaintImage();
	  }
	break;


  case WM_SIZE:
	if (hWnd != hWnd  ||  GetUpdateRect(hWnd,NULL,FALSE) == 0)
	  return(DefWindowProc(hWnd,uMsg,wParam,lParam));
	break;

  case WM_PAINT:
	PaintImage();
	return(DefWindowProc(hWnd,uMsg,wParam,lParam));
	break;

  case WM_TIMER:
	if (wParam == TIMER_SECOND)
	  {
	  UpdateDisplay();
	  if (PlayCountdown > 0)	  /* playing a brief sequence; stop when counter reaches zero */
		{
		PlayCountdown--;
		if (PlayCountdown == 0)
		  SendMessage(hWnd,WM_CHAR,(TCHAR)'d',0);
		}
	  }
	break;
	
  case WM_DESTROY:
	Sleep(100);
	DestroyWindow(hWnd);
	PostQuitMessage(0);
	break;
	
  default:
	return(DefWindowProc(hWnd,uMsg,wParam,lParam));
	break;
  }

return(0L);
}




		/* moves the TimeIndex according to PlayJump, then calls PaintImage() */

void UpdateDisplay()

{
if (TimeIndex+PlayJump < 0  ||  TimeIndex+PlayJump >= TotalData)
  {
  if (TimeIndex+PlayJump < 0)
	TimeIndex=0;
  else
	TimeIndex=TotalData-1;
  if (Playing == 1)		  /* halt play if reached either start or end */
	{
	KillTimer(MainWnd,TIMER_SECOND);
	Playing=0;
	}
  }
else
  {
  TimeIndex+=PlayJump;
  }
PaintImage();
}



void InitializeDataVariables()

{
TimeIndex=0;
VideoLoaded=0;
DataLoaded=0;
FoodsLoaded=0;
Playing=0;
PlayJump=1;
PlayCountdown=0;
TotalData=0;
disp_image=NULL;
ViewSmoothed=1;
DisplayAccs=1;
DisplayGyros=1;
DisplayRollOnly=0;
DisplayScale=1;
TotalFoodsInMeal=0;
TotalGTBites=0;
TotalMDBites=0;
TotalGTGestures=0;
TotalMDGestures=0;
GTFilename[0]='\0';
CurrentHand=1;	/* right */
CurrentUtensil=6; /* unknown */
CurrentContainer=7; /* unknown */
CurrentFood=11;	  /* unknown */
GestureColors[0][0]=255; GestureColors[0][1]=0; GestureColors[0][2]=0; strcpy(GestureNames[0],"bite");
GestureColors[1][0]=0; GestureColors[1][1]=255; GestureColors[1][2]=255; strcpy(GestureNames[1],"drink");
GestureColors[2][0]=120; GestureColors[2][1]=120; GestureColors[2][2]=120; strcpy(GestureNames[2],"other");
GestureColors[3][0]=0; GestureColors[3][1]=0; GestureColors[3][2]=0; strcpy(GestureNames[3],"rest");
GestureColors[4][0]=255; GestureColors[4][1]=140; GestureColors[4][2]=0; strcpy(GestureNames[4],"utensiling");
DisplayGT=1;
DisplayMDBites=1;
DisplayEvaluationLinks=0;
TotalPeaks=0;
}