#include <iomanip>
#include <sstream>
#include <cstdlib>
#include "windows.h"
#include "commctrl.h"
#include "ifschooserwindow.hpp"

#include "debug.hpp"

using namespace std;

void TIFSChooserWindow::ConstructIFSEntryWindow()
{
	//Set up additional class globals
	AffineTransformationTab = 0;
 GeneralTab = 1;
	
 //Create the entry window.
 IFSEntryWindow = CreateIFSEntryWindow();

 //Get the dimensions of the entry window.
 GetClientRect(IFSEntryWindow, &IFSEntryWindowRect);
 IFSEntryWindowWidth = IFSEntryWindowRect.right;
 IFSEntryWindowHeight = IFSEntryWindowRect.bottom;

 //Create the tabs for the entry window.
 InputMethodTabs = CreateInputMethodTabs();
 AffineTransformationTab = CreateInputMethodTab("Affine Transformation", AffineTransformationTab);
 GeneralTab = CreateInputMethodTab("General", GeneralTab);
 
 //Create the trackbar
 ProbabilityTrackbar = CreateProbabilityTrackbar();
 
 //Create buttons
 OKButton = CreateIFSEntryWindowButton("OK", ENTRYCHILD_OKBUTTON, 5, IFSEntryWindowHeight - 35, 30);
 CancelButton = CreateIFSEntryWindowButton("Cancel", ENTRYCHILD_CANCELBUTTON, 45, IFSEntryWindowHeight - 35, 55);

 //Create edit boxes
 FunctionTitleEditBox = CreateIFSEntryWindowEditBox(ENTRYCHILD_FUNCTIONTITLEEDITBOX, 5, 5, 150, false);
 ProbabilityEditBox = CreateIFSEntryWindowEditBox(ENTRYCHILD_PROBABILITYEDITBOX, 5, IFSEntryWindowHeight - 110, 50, false);
 XComponentEditBox = CreateIFSEntryWindowEditBox(ENTRYCHILD_XCOMPONENTEDITBOX, 10, 100, 250, true);
 YComponentEditBox = CreateIFSEntryWindowEditBox(ENTRYCHILD_YCOMPONENTEDITBOX, 10, 130, 250, true);
 
 //Limit the Edit Boxes
 SendMessage(FunctionTitleEditBox, EM_SETLIMITTEXT, (WPARAM) 20, (LPARAM) 0);
 SendMessage(XComponentEditBox, EM_SETLIMITTEXT, (WPARAM) 255, (LPARAM) 0);
 SendMessage(YComponentEditBox, EM_SETLIMITTEXT, (WPARAM) 255, (LPARAM) 0);
 SendMessage(ProbabilityEditBox, EM_SETLIMITTEXT, (WPARAM) 4, (LPARAM) 0);
 
 //Initialise the window
 ClearIFSEntryWindow();

 return;
}

void TIFSChooserWindow::DestroyIFSEntryWindow()
{
 DestroyWindow(InputMethodTabs);
 DestroyWindow(IFSEntryWindow);
 UnregisterClass("TIFSChooserWindow-Entry", AppInst);
}

HWND TIFSChooserWindow::CreateIFSEntryWindow()
{
 WNDCLASSEX IFSEntryClass;

 //Create the window class
 if (!GetClassInfoEx(AppInst, "TIFSChooserWindow-Entry", &IFSEntryClass))
 {
  IFSEntryClass.cbSize = sizeof(WNDCLASSEX); //Always set to this
  IFSEntryClass.style = CS_OWNDC;
  IFSEntryClass.lpfnWndProc = &TIFSChooserWindow::GlobalEntryWndProc; //!Window Procedure.
  IFSEntryClass.cbClsExtra = 0; //Bytes to allocate for extra class information.
  IFSEntryClass.cbWndExtra = 0; //Bytes to allocate for extra window information.
  IFSEntryClass.hInstance = AppInst; //Instance of application which created the class.
  IFSEntryClass.hIcon = NULL; //Window Icon.
  IFSEntryClass.hCursor = LoadCursor(NULL, IDC_ARROW); //Window Cursor.
  IFSEntryClass.hbrBackground = (HBRUSH) COLOR_BACKGROUND; //Window Background.
  IFSEntryClass.lpszMenuName = NULL; //Name of main menu (if we have one)
  IFSEntryClass.lpszClassName = "TIFSChooserWindow-Entry"; //Name of class.
  IFSEntryClass.hIconSm = NULL; //Window Small Icon.

  RegisterClassEx(&IFSEntryClass);
 }

 //Create the window
 return CreateWindowEx(
 WS_EX_CONTEXTHELP,
 "TIFSChooserWindow-Entry", //Class name.
 "", //Title of window.
 (WS_CAPTION | WS_SYSMENU | WS_OVERLAPPED),
 CW_USEDEFAULT, //X Position.
 CW_USEDEFAULT, //Y Position.
 350, //Width
 400, //Height
 Handle, //Parent Window
 (HMENU) NULL, //Child's ID.
 AppInst, //Instance of application which created the class.
 this //Extra user data to pass to WM_CREATE.
 );
}

HWND TIFSChooserWindow::CreateInputMethodTabs()
{
 return CreateWindowEx(
 (DWORD) NULL,
 WC_TABCONTROL,
 "",
 (WS_CHILD | WS_VISIBLE),
 5,
 30,
 IFSEntryWindowWidth - 10,
 IFSEntryWindowHeight - 150,
 IFSEntryWindow,
 (HMENU) ENTRYCHILD_INPUTMETHODTABS,
 AppInst,
 NULL
 );
}

HWND TIFSChooserWindow::CreateProbabilityTrackbar()
{
 return CreateWindowEx(
 (DWORD) NULL,
 TRACKBAR_CLASS,
 "Probability",
 (WS_CHILD | WS_VISIBLE | TBS_HORZ),
 5,
 IFSEntryWindowHeight - 85,
 IFSEntryWindowWidth - 10,
 30,
 IFSEntryWindow,
 (HMENU) ENTRYCHILD_PROBABILITYTRACKBAR,
 AppInst,
 NULL
 );	
}

HWND TIFSChooserWindow::CreateIFSEntryWindowButton(char *s, int ID, int x, int y, int Width)
{
 return CreateWindowEx(
 (DWORD) NULL,
 "BUTTON",
 s,
 (WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | BS_TEXT),
 x,
 y,
 Width,
 30,
 IFSEntryWindow,
 (HMENU) ID,
 AppInst,
 (LPVOID) NULL
 );
}

HWND TIFSChooserWindow::CreateIFSEntryWindowEditBox(int ID, int x, int y, int Width, bool PartOfTabs)
{
	if (PartOfTabs)
	{
  return CreateWindowEx(
  (DWORD) NULL,
  "EDIT",
  NULL,
  (WS_CHILD | WS_BORDER),
  x,
  y,
  Width,
  20,
  IFSEntryWindow,
  (HMENU) ID,
  AppInst,
  (LPVOID) NULL
  );
	}
 else
 {
  return CreateWindowEx(
  (DWORD) NULL,
  "EDIT",
  NULL,
  (WS_CHILD | WS_VISIBLE | WS_BORDER),
  x,
  y,
  Width,
  20,
  IFSEntryWindow,
  (HMENU) ID,
  AppInst,
  (LPVOID) NULL
  );
 }
}

LRESULT CALLBACK TIFSChooserWindow::EntryWndProc(HWND hwnd, UINT MsgIdent, WPARAM wParam, LPARAM lParam)
{
 switch(MsgIdent)
 {
  case WM_SHOWWINDOW:
  if (((BOOL) wParam) == TRUE)
  {
   switch(IFSEntryWindowMode)
   {
    case MODE_ADD:
    SetWindowText(IFSEntryWindow, "Add a new IFS");
    ClearIFSEntryWindow();
    break;
    case MODE_EDIT:
    SetWindowText(IFSEntryWindow, "Edit an IFS");
    break;
   }
  }
  break;
  case WM_COMMAND:
  if (HIWORD(wParam) == BN_CLICKED)
  {
  	if (LOWORD(wParam) == ENTRYCHILD_OKBUTTON)
  	{
  		switch(IFSEntryWindowMode)
  		{
  			case MODE_ADD:
  			CallAddFunction();
  			break;
  			case MODE_EDIT:
  			CallEditFunction();
  			break;
  		}
  		HideIFSEntryWindow();
  	}
  	else if (LOWORD(wParam) == ENTRYCHILD_CANCELBUTTON)
  	{
  		HideIFSEntryWindow();
  	}
  }
  else if (HIWORD(wParam) == EN_CHANGE)
  {
  	if (LOWORD(wParam) == ENTRYCHILD_PROBABILITYEDITBOX)
  	{
  		UpdateProbabilityTrackbar();
  	}
  }
  break;
  case WM_NOTIFY:
  if (((NMHDR *) lParam)->code == TCN_SELCHANGE)
  {
   if (((NMHDR *) lParam)->idFrom == ENTRYCHILD_INPUTMETHODTABS)
   {
    ProcessTabChange();
   }
  }
  break;
  case WM_HSCROLL:
  UpdateProbabilityEditBox();
  break;
  case WM_CLOSE:
  HideIFSEntryWindow();
  break;
  default:
  return DefWindowProc(hwnd, MsgIdent, wParam, lParam);
  break;
 }

 return 0;
}

LRESULT CALLBACK TIFSChooserWindow::GlobalEntryWndProc(HWND hwnd, UINT MsgIdent, WPARAM wParam, LPARAM lParam)
{
 TIFSChooserWindow *self;

 switch(MsgIdent)
 {
  case WM_CREATE:
  self = (TIFSChooserWindow *) ((CREATESTRUCT *) lParam)->lpCreateParams;
  SetWindowLongPtr(hwnd, GWLP_USERDATA, ((LONG_PTR) self));
  return self->EntryWndProc(hwnd, MsgIdent, wParam, lParam);
  break;
  default:
  self = (TIFSChooserWindow *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  return self->EntryWndProc(hwnd, MsgIdent, wParam, lParam);
  break;
 }

 return 0;
}

void TIFSChooserWindow::ClearIFSEntryWindow()
{
	SendMessage(FunctionTitleEditBox, WM_SETTEXT, (WPARAM) 0, (LPARAM) "");
	SendMessage(XComponentEditBox, WM_SETTEXT, (WPARAM) 0, (LPARAM) "");
	SendMessage(YComponentEditBox, WM_SETTEXT, (WPARAM) 0, (LPARAM) "");
	SendMessage(ProbabilityEditBox, WM_SETTEXT, (WPARAM) 0, (LPARAM) "0");
	SendMessage(ProbabilityTrackbar, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) 0);
	SendMessage(InputMethodTabs, TCM_SETCURSEL, (WPARAM) AffineTransformationTab, (LPARAM) 0);
	ProcessTabChange();
	return;
}

void TIFSChooserWindow::HideIFSEntryWindow()
{
 ShowWindow(IFSEntryWindow, SW_HIDE);
 EnableWindow(Handle, TRUE);
 BringToTop();
}

int TIFSChooserWindow::CreateInputMethodTab(char *s, int i)
{
	TCITEM TabToAdd;
	
	TabToAdd.mask = (TCIF_IMAGE | TCIF_TEXT);
	TabToAdd.iImage = -1;
	TabToAdd.pszText = s;
	
	return SendMessage(InputMethodTabs, TCM_INSERTITEM, i, (LPARAM) &TabToAdd);
}

void TIFSChooserWindow::ProcessTabChange()
{
	int SelectedTab;
	
	SelectedTab = SendMessage(InputMethodTabs, TCM_GETCURSEL, 0, 0);
	
	if (SelectedTab == AffineTransformationTab)
	{
		switch(IFSEntryWindowMode)
		{
			case MODE_ADD:
			IFSEntryWindowMethod = METHOD_AFFINE;
			break;
			case MODE_EDIT:
			break;
		}
		ShowWindow(XComponentEditBox, SW_HIDE);
		ShowWindow(YComponentEditBox, SW_HIDE);
	}
	else if (SelectedTab == GeneralTab)
	{
		switch(IFSEntryWindowMode)
		{
			case MODE_ADD:
			IFSEntryWindowMethod = METHOD_GENERAL;
			break;
			case MODE_EDIT:
			break;
		}
		ShowWindow(XComponentEditBox, SW_SHOW);
		ShowWindow(YComponentEditBox, SW_SHOW);
	}
		
	return;
}

void TIFSChooserWindow::UpdateProbabilityTrackbar()
{
	float CurrentProb;
	TCHAR *s = new TCHAR[5];
	
	s[0] = (TCHAR) 5; //Required by the EM_GETLINE message.
	
	SendMessage(ProbabilityEditBox, EM_GETLINE, (WPARAM) 0, (LPARAM) s);
	CurrentProb = strtod(s, NULL); //Returns 0.0 if invalid.
	SendMessage(ProbabilityTrackbar, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) (int) (CurrentProb * 100));
	
	delete s;
	
	return;
}

void TIFSChooserWindow::UpdateProbabilityEditBox()
{
	float CurrentProb;
	stringstream ss;
	
	CurrentProb = ((float) SendMessage(ProbabilityTrackbar, TBM_GETPOS, 0, 0)) / 100;
	
	ss << setprecision(3) << CurrentProb;
	SendMessage(ProbabilityEditBox, WM_SETTEXT, 0, (LPARAM) ss.str().c_str());
	
	return;
}

void TIFSChooserWindow::CallAddFunction()
{
	int i;
	TCHAR *FunctionTitle = new TCHAR[21];
	TCHAR *sx = new TCHAR[256];
	TCHAR *sy = new TCHAR[256];
	//TAffineTransformation t;
	float prob;
	
	i = SendMessage(FunctionTitleEditBox, EM_GETLINE, (WPARAM) 0, (LPARAM) FunctionTitle);
	prob = ((float) SendMessage(ProbabilityTrackbar, TBM_GETPOS, 0, 0)) / 100;
	
	switch(IFSEntryWindowMethod)
	{
		case METHOD_AFFINE:
		break;
		case METHOD_GENERAL:
		SendMessage(XComponentEditBox, EM_GETLINE, (WPARAM) 0, (LPARAM) sx);
		SendMessage(YComponentEditBox, EM_GETLINE, (WPARAM) 0, (LPARAM) sy);
		AddFunction(FunctionTitle, sx, sy, prob);
		break;
	}
	
	return;
}

void TIFSChooserWindow::CallEditFunction()
{
	return;
}

