/////////////////////////////////////////////////////////////////////////////
// Name:        test_spcore_wx.cpp
// Author:      Cesar Mauri Loba
// Copyright:   (C) 2011 Cesar Mauri Loba - CREA Software Systems
// 
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////

#include "spcore/coreruntime.h"
#include "testcommon/testcommon.h"
#include "3rdparty/nvwa/debug_new.h"
#include "spcore/basictypes.h"

#if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXX11__)
	// Include Xlib for latter use on main
	#include <X11/Xlib.h>
#endif

#include <wx/msgdlg.h>
#include <wx/frame.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <stdio.h>
#include <wx/init.h>
#include <wx/timer.h>

#include <boost/thread/thread.hpp>

using namespace spcore;

/*
	Check threads enabled
*/
#if !wxUSE_THREADS
     #error "This program requires thread support."
#endif // wxUSE_THREADS

/*
	main frame class
*/
class MyFrame : public wxFrame
{
public:
    MyFrame();
	~MyFrame() {
		delete m_timer;
	}
	void OnCloseWindow( wxCloseEvent& event );
private:
	void OnSize(wxSizeEvent& event);
	void OnTimer(wxTimerEvent& event);

	wxTimer * m_timer;

    // any class wishing to process wxWidgets events must use this macro
    DECLARE_EVENT_TABLE()
};

/*
	myframe event table
*/
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
	EVT_CLOSE	( MyFrame::OnCloseWindow )
	EVT_SIZE	( MyFrame::OnSize )
	EVT_TIMER	( wxID_ANY, MyFrame::OnTimer )
END_EVENT_TABLE()

void MyFrame::OnCloseWindow(wxCloseEvent &event)
{
	event.Skip(); // Equivalent to: wxFrame::OnCloseWindow(event);
}

void MyFrame::OnSize(wxSizeEvent& event)
{
	Layout();
	Fit();

	event.Skip (false);
}

// ============================================================================
// implementation
// ============================================================================

// ----------------------------------------------------------------------------
// main frame
// ----------------------------------------------------------------------------
MyFrame::MyFrame() 
: wxFrame(NULL, wxID_ANY, _T(""), wxDefaultPosition, wxDefaultSize, wxCAPTION|wxSYSTEM_MENU|wxCLOSE_BOX)
{
	m_timer= new wxTimer(this);
	m_timer->Start (2000, true);
}

void MyFrame::OnTimer(wxTimerEvent& )
{
	wxMessageDialog dlg(this, _T("Modal dialog"));
	dlg.ShowModal();
}

// ----------------------------------------------------------------------------
// thread func
// ----------------------------------------------------------------------------
class VoidClass{};
static VoidClass g_voidClassInstance;

// Input pin for testing
class InputPinTest : public CInputPinWriteOnly<CTypeInt, VoidClass> {
public:
	InputPinTest (int id)
	: CInputPinWriteOnly<CTypeInt, VoidClass>("test_status", g_voidClassInstance)
	, m_id(id)
	{
	}

	virtual int DoSend(const CTypeInt & msg) {
		printf ("InputPinTest id: %d, called with value %d\n", m_id, msg.getValue());
		return 0;
	}
private:
	int m_id;
};

static bool g_exitThread= false;

void ThreadFunc()
{
	static int ids= 0;
	int my_id= ids++;

	SmartPtr<CTypeInt> my_int= CTypeInt::CreateInstance();

	SmartPtr<InputPinTest> pin(new InputPinTest(my_id), false);

	while (!g_exitThread) {
		printf ("Thread %d. Before send\n", my_id);
		my_int->setValue (my_int->getValue() + 1);
		int retval= getSpCoreRuntime()->SendMessageMainThreadSync (my_int, *pin);
		printf ("Thread %d. After send. Retval: %d\n", my_id, retval);
		sleep_milliseconds(100);
	}

	printf ("Thread %d. Exiting\n", my_id);
}

// ----------------------------------------------------------------------------
// main
// ----------------------------------------------------------------------------

int main(int argc, char *argv[]) {
	
#if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXX11__)
	// Under X11 it's necessary enable threading support
	if ( XInitThreads() == 0 ) {
		ExitErr("Unable to initialize multithreaded X11 code (XInitThreads failed)");		
		exit( EXIT_FAILURE );
	}
#endif

	// Initialize spcore
	ICoreRuntime* cr= getSpCoreRuntime();
	if (!cr) return false;

	if (cr->InitGUISupport (argc, argv))
		 ExitErr("wxEntryStart failed");

	// Create dialog
	MyFrame* mf= new MyFrame();
	mf->Show();

	// Create threads
	boost::thread thread1(ThreadFunc);
	assert (thread1.joinable());
	boost::thread thread2(ThreadFunc);
	assert (thread2.joinable());
	sleep_milliseconds (200);

	// Run wxWidgets message pump
	cr->RunMessageLoop ();

	// Wait to continue sending messages from threads
	sleep_milliseconds (200);

	// End threads
	g_exitThread= true;
	thread2.join();	
	thread1.join();	

	// GUI cleanup
	cr->CleanupGUISupport();
	
	// Free spcore
	freeSpCoreRuntime();

	// If execution reaches this => all tests ok
	return 0;
}
