/////////////////////////////////////////////////////////////////////////////
// Name:        test_mod_collage_graphics.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 "spcore/basictypes.h"
#include "testcommon/testcommon.h"
#include "3rdparty/nvwa/debug_new.h"

#if defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXX11__)
	// Include Xlib for latter use on main
	#include <X11/Xlib.h>
#endif
#include <wx/app.h>
#include <wx/image.h>
#include <wx/msgdlg.h>
#include <wx/frame.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/timer.h>

enum { TIMER_ID= 1234 };
enum { PANEL_WIDTH= 500, PANEL_HEIGHT= 500 };

using namespace spcore;

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

/*
	main app class
*/
class TestWXApp: public wxApp
{
	DECLARE_CLASS( TestWXApp )
public:
	TestWXApp();	// Constructor

private:
	virtual bool OnInit();	// Initialises the application
	virtual int OnExit();	// Called on exit

	SmartPtr<spcore::IComponent> m_comp;
};

/*
	main frame class
*/
class MyFrame : public wxFrame
{
public:
    MyFrame();
	virtual ~MyFrame();
	void OnCloseWindow( wxCloseEvent& event );
	static MyFrame* Create( );
private:
	wxTimer m_timer;
	float m_motion;
	SmartPtr<IComponent> m_composer;
	wxPoint m_prevPosition;
	IInputPin* m_ipin;

	// Event handlers
	void OnMotion(wxMouseEvent& event);
	void OnTimer(wxTimerEvent& event);

    // 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_TIMER(TIMER_ID, MyFrame::OnTimer)
END_EVENT_TABLE()

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

/*!
 * Application instance declaration
 */
DECLARE_APP(TestWXApp)

/*!
 * TestWXApp type definition
 */
IMPLEMENT_CLASS( TestWXApp, wxApp )

/*
	Application instance implementation

	we use IMPLEMENT_APP_NO_MAIN instead of IMPLEMENT_APP
	because we define our own main
 */
IMPLEMENT_APP_NO_MAIN(TestWXApp)

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

// ----------------------------------------------------------------------------
// main frame
// ----------------------------------------------------------------------------
MyFrame::MyFrame()
: wxFrame(NULL, wxID_ANY, _T(""), wxDefaultPosition, wxDefaultSize, wxCAPTION|wxSYSTEM_MENU|wxCLOSE_BOX)
, m_timer(this, TIMER_ID)
, m_motion(0.0f)
, m_ipin(NULL)
{

}

MyFrame::~MyFrame()
{
	m_timer.Stop();

	m_composer->Finish();
}

void MyFrame::OnMotion( wxMouseEvent& event )
{
	wxPoint current= event.GetPosition();

	int dx= current.x - m_prevPosition.x;
	int dy= current.y - m_prevPosition.y;
	m_prevPosition= current;
	float abs_motion= sqrtf(static_cast<float>(dx*dx + dy*dy)) /
		sqrtf(static_cast<float>(PANEL_WIDTH * PANEL_WIDTH + PANEL_HEIGHT * PANEL_HEIGHT));

	m_motion+= abs_motion;

	if (m_motion> 1.0f) m_motion= 1.0f;

	event.Skip(false);
}

void MyFrame::OnTimer(wxTimerEvent& event)
{
	SmartPtr<CTypeFloat> value= spcore::CTypeFloat::CreateInstance();
	value->setValue(m_motion);
	m_ipin->Send (value);
	m_motion= 0.0f;

	event.Skip(false);
}

MyFrame* MyFrame::Create ( )
{
	MyFrame* mf= new MyFrame;
	wxBoxSizer* sizer= new wxBoxSizer(wxVERTICAL);
	mf->SetSizer(sizer);

	long idPanel= wxNewId();
	wxPanel* itemPanel3 = new wxPanel( mf, idPanel, wxDefaultPosition, wxSize(PANEL_WIDTH, PANEL_HEIGHT), wxSUNKEN_BORDER|wxTAB_TRAVERSAL );
    sizer->Add(itemPanel3, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 0);

    // Connect events and objects
    itemPanel3->Connect(idPanel, wxEVT_MOTION, wxMouseEventHandler(MyFrame::OnMotion), NULL, mf);

	mf->GetSizer()->SetSizeHints(mf);	// Fit to content

	//
	// Build graph
	//

	mf->m_composer= getSpCoreRuntime()->CreateComponent("component_composer", "composer", 0, NULL);
	if (!mf->m_composer.get()) ExitErr("cannot create composer");

	SmartPtr<IComponent> sdl_drawer= getSpCoreRuntime()->CreateComponent("sdl_drawer", "drawer", 0, NULL);
	if (!sdl_drawer.get()) ExitErr("cannot create sdl_drawer");

	// First add drawer
	int retval= mf->m_composer->AddChild(sdl_drawer);
	if (retval!= 0) ExitErr("error adding child");

	// Create and add collage_graphics
	SmartPtr<IComponent> collage_graphics= getSpCoreRuntime()->CreateComponent("collage_graphics", "collage", 0, NULL);
	if (!collage_graphics.get()) ExitErr("cannot create collage_graphics");

	retval= mf->m_composer->AddChild(collage_graphics);
	if (retval!= 0) ExitErr("error adding child: collage_graphics");

	// Connect components
	DumpComponent (*collage_graphics);
	retval= spcore::Connect (collage_graphics.get(), "result", sdl_drawer.get(), "draw");
	if (retval!= 0) ExitErr("cannot connect pins");

	retval= mf->m_composer->Initialize();
	if (retval!= 0) ExitErr("initialization failed");

	// Get input pin to send motion
	mf->m_ipin= IComponent::FindInputPin (*collage_graphics, "motion");
	if (!mf->m_ipin) ExitErr("pin not found");

	mf->m_timer.Start(50);	// Refresh 25Hz

	/** Test without wxpickerctrl **/
	IInputPin* pin_file=IComponent::FindInputPin(*collage_graphics, "file");
	SmartPtr<CTypeString> file= spcore::CTypeString::CreateInstance();

	file->set("../sitplus/samples/mod_collage/XML/instruments/piano2.xml");
	pin_file->Send(file);
	/** end test without wxpickerctrl **/

	return mf;
}

// ----------------------------------------------------------------------------
// the application class
// ----------------------------------------------------------------------------

TestWXApp::TestWXApp() {
}

/*
  Initialisation for TestWXApp

  Return true to signal correct initialization or false when error
 */
bool TestWXApp::OnInit()
{
#if wxUSE_XPM
	wxImage::AddHandler(new wxXPMHandler);
#endif
#if wxUSE_LIBPNG
	wxImage::AddHandler(new wxPNGHandler);
#endif
#if wxUSE_LIBJPEG
	wxImage::AddHandler(new wxJPEGHandler);
#endif
#if wxUSE_GIF
	wxImage::AddHandler(new wxGIFHandler);
#endif

#if defined(WIN32)
	// Uncomment this to enable a console in Windows for debug purposes
	//AllocConsole(); freopen("CONOUT$", "wb", stdout);
#endif

	ICoreRuntime* cr= getSpCoreRuntime();

	int retval= cr->LoadModule("mod_sdl");
	if (retval!= 0) ExitErr("error loading mod_sdl");
	retval= cr->LoadModule("mod_collage");
	if (retval!= 0) ExitErr("error loading mod_collage");

	DumpCoreRuntime(cr);

	// Create dialog
	MyFrame* mf= MyFrame::Create ( );
	if (!mf) ExitErr("error error creating pannel");

	mf->Show();

	return true;
}


/*!
  Cleanup for TestWXApp
 */

int TestWXApp::OnExit()
{
	return wxApp::OnExit();
}

// ----------------------------------------------------------------------------
// 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;

	// Run wxWidgets message pump
	wxEntry(argc, argv);

	// Free spcore
	freeSpCoreRuntime();

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