/////////////////////////////////////////////////////////////////////////////
// Name:        midiconfiggui.cpp
// Purpose:
// Author:      César Mauri Loba
// Modified by:
// Created:     01/04/2011 18:13:36
// RCS-ID:
// 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/>. 
/////////////////////////////////////////////////////////////////////////////

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

////@begin includes
////@end includes

#include "midiconfiggui.h"
#include "mod_midi/midi_types.h"

#include "spcore/coreruntime.h"
#include "spcore/pinimpl.h"
#include "spcore/iterator.h"
#include "spcore/basictypes.h"

////@begin XPM images
////@end XPM images

using namespace spcore;

namespace mod_midi {

// Pin to receive the list of output devices
class InputPinDevices : public CInputPinWriteOnly<CTypeAny, MIDIConfigGui> {
public:
	InputPinDevices (MIDIConfigGui & component)
	:  CInputPinWriteOnly<CTypeAny, MIDIConfigGui>("device_list", component) {}

	virtual int DoSend(const CTypeAny & msg) {
		// Clean entries
		m_component->m_choMidiOut->Clear();

		// Populate output midi devices
		SmartPtr<IIterator<CTypeAny*> > it=	msg.QueryChildren();

		for (it->First(); !it->IsDone(); it->Next()) {
			CTypeString* name= sptype_dynamic_cast<CTypeString>(it->CurrentItem());
			if (name) {
				m_component->m_choMidiOut->Append (wxString(name->get(), wxConvUTF8));
			}
		}

		return 0;
	}
};

/*
 * MIDIConfigGui type definition
 */

IMPLEMENT_DYNAMIC_CLASS( MIDIConfigGui, wxPanel )


/*
 * MIDIConfigGui event table definition
 */

BEGIN_EVENT_TABLE( MIDIConfigGui, wxPanel )

////@begin MIDIConfigGui event table entries
    EVT_CLOSE( MIDIConfigGui::OnCloseWindow )

    EVT_BUTTON( ID_BUTTON_MIDI_TEST, MIDIConfigGui::OnButtonMidiTestClick )

    EVT_BUTTON( wxID_OK, MIDIConfigGui::OnOkClick )

    EVT_BUTTON( wxID_CANCEL, MIDIConfigGui::OnCancelClick )

////@end MIDIConfigGui event table entries

END_EVENT_TABLE()


/*
 * MIDIConfigGui constructors
 */

MIDIConfigGui::MIDIConfigGui()
{
    Init();
}

MIDIConfigGui::MIDIConfigGui( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name )
{
    Init();
    Create(parent, id, pos, size, style, name);
}


/*
 * MIDIConfigGui creator
 */

bool MIDIConfigGui::Create( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name )
{
////@begin MIDIConfigGui creation
    SetExtraStyle(wxWS_EX_BLOCK_EVENTS);
    wxPanel::Create( parent, id, pos, size, style, name );

    CreateControls();
    if (GetSizer())
    {
        GetSizer()->SetSizeHints(this);
    }
    Centre();
////@end MIDIConfigGui creation
    return true;
}


/*
 * MIDIConfigGui destructor
 */

MIDIConfigGui::~MIDIConfigGui()
{
////@begin MIDIConfigGui destruction
////@end MIDIConfigGui destruction
}


/*
 * Member initialisation
 */

void MIDIConfigGui::Init()
{
////@begin MIDIConfigGui member initialisation
    m_choMidiOut = NULL;
////@end MIDIConfigGui member initialisation
}


/*
 * Control creation for MIDIConfigGui
 */

void MIDIConfigGui::CreateControls()
{
////@begin MIDIConfigGui content construction
    MIDIConfigGui* itemPanel1 = this;

    wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL);
    itemPanel1->SetSizer(itemBoxSizer2);

    wxStaticBox* itemStaticBoxSizer3Static = new wxStaticBox(itemPanel1, wxID_ANY, _("Select MIDI output device"));
    wxStaticBoxSizer* itemStaticBoxSizer3 = new wxStaticBoxSizer(itemStaticBoxSizer3Static, wxVERTICAL);
    itemBoxSizer2->Add(itemStaticBoxSizer3, 0, wxALIGN_LEFT|wxALL, 5);

    wxBoxSizer* itemBoxSizer4 = new wxBoxSizer(wxHORIZONTAL);
    itemStaticBoxSizer3->Add(itemBoxSizer4, 0, wxALIGN_LEFT|wxALL, 5);

    wxArrayString m_choMidiOutStrings;
    m_choMidiOut = new wxChoice( itemPanel1, ID_CHOICE_MIDI_OUT, wxDefaultPosition, wxDefaultSize, m_choMidiOutStrings, 0 );
    itemBoxSizer4->Add(m_choMidiOut, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    wxButton* itemButton6 = new wxButton( itemPanel1, ID_BUTTON_MIDI_TEST, _("Test"), wxDefaultPosition, wxDefaultSize, 0 );
    itemBoxSizer4->Add(itemButton6, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    wxStdDialogButtonSizer* itemStdDialogButtonSizer7 = new wxStdDialogButtonSizer;

    itemBoxSizer2->Add(itemStdDialogButtonSizer7, 0, wxALIGN_RIGHT|wxALL, 5);
    wxButton* itemButton8 = new wxButton( itemPanel1, wxID_OK, _("&OK"), wxDefaultPosition, wxDefaultSize, 0 );
    itemStdDialogButtonSizer7->AddButton(itemButton8);

    wxButton* itemButton9 = new wxButton( itemPanel1, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, 0 );
    itemStdDialogButtonSizer7->AddButton(itemButton9);

    itemStdDialogButtonSizer7->Realize();

////@end MIDIConfigGui content construction

	// Create midi_config component
	m_midiConfigComponent= getSpCoreRuntime()->CreateComponent("midi_config", "mc", 0, NULL);
	if (m_midiConfigComponent.get()== NULL) {
		getSpCoreRuntime()->LogMessage (ICoreRuntime::LOG_FATAL, "cannot create midi_config component", "midi_module");
		return;
	}

	// Find output pin
	IOutputPin* opin= IComponent::FindOutputPin(*m_midiConfigComponent, "device_list");
	assert (opin);

	// Create a temporary input pin and connect
	InputPinDevices devicesPin(*this);
	int retval= opin->Connect(devicesPin);
	assert (!retval);

	// Send message to fill available midi devices
	SmartPtr<CTypeBool> foo= CTypeBool::CreateInstance();
	IInputPin* ipinReqStatus= IComponent::FindInputPin(*m_midiConfigComponent, "req_status");
	assert (opin);
	ipinReqStatus->Send(foo);
	opin->Disconnect(devicesPin);

	// Read current configured device
	IInputPin* devicePin= IComponent::FindInputPin(*m_midiConfigComponent, "out_device");
	assert (devicePin);
	SmartPtr<const CTypeInt> outDev= sptype_dynamic_cast<const CTypeInt>(devicePin->Read());
	m_choMidiOut->SetSelection(outDev->getValue());
}


/*
 * Should we show tooltips?
 */

bool MIDIConfigGui::ShowToolTips()
{
    return true;
}

/*
 * Get bitmap resources
 */

wxBitmap MIDIConfigGui::GetBitmapResource( const wxString& name )
{
    // Bitmap retrieval
////@begin MIDIConfigGui bitmap retrieval
    wxUnusedVar(name);
    return wxNullBitmap;
////@end MIDIConfigGui bitmap retrieval
}

/*
 * Get icon resources
 */

wxIcon MIDIConfigGui::GetIconResource( const wxString& name )
{
    // Icon retrieval
////@begin MIDIConfigGui icon retrieval
    wxUnusedVar(name);
    return wxNullIcon;
////@end MIDIConfigGui icon retrieval
}




/*
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for wxID_OK
 */

void MIDIConfigGui::OnOkClick( wxCommandEvent& event )
{
	// Store new selection and finish
	SmartPtr<CTypeInt> outDev= CTypeInt::CreateInstance();
	outDev->setValue (m_choMidiOut->GetSelection());

	IInputPin* devicePin= IComponent::FindInputPin(*m_midiConfigComponent, "out_device");
	assert (devicePin);
	devicePin->Send(outDev);

	GetParent()->Close();
	event.Skip(false);
}


/*
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for wxID_CANCEL
 */

void MIDIConfigGui::OnCancelClick( wxCommandEvent& event )
{
	GetParent()->Close();
    event.Skip(false);
}

/*
 * wxEVT_CLOSE_WINDOW event handler for ID_MIDICONFIGGUI
 */

void MIDIConfigGui::OnCloseWindow( wxCloseEvent& event )
{
////@begin wxEVT_CLOSE_WINDOW event handler for ID_MIDICONFIGGUI in MIDIConfigGui.
    // Before editing this code, remove the block markers.
    event.Skip();
////@end wxEVT_CLOSE_WINDOW event handler for ID_MIDICONFIGGUI in MIDIConfigGui.
}

/*
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_BUTTON_MIDI_TEST
 */

void MIDIConfigGui::OnButtonMidiTestClick( wxCommandEvent& event )
{
	event.Skip(false);

	SmartPtr<IComponent> midiOut= getSpCoreRuntime()->CreateComponent ("midi_out", "mo", 0, NULL);
	assert (midiOut.get());
	if (midiOut.get()== NULL) return;

	SmartPtr<CTypeMIDIMessage> msg= CTypeMIDIMessage::CreateInstance();
	assert (msg.get());
	if (msg.get()== NULL) return;

	if (midiOut->Initialize()!= 0) {
		assert (false);
		return;
	}

	// Play scale
	for (unsigned char note= 40; note< 60; ++note) {
		msg->SetNoteOn (0, note, 127);
		IComponent::FindInputPin(*midiOut, "message")->Send(msg);
		wxMilliSleep(100);
		msg->SetNoteOff (0, note, 127);
		IComponent::FindInputPin(*midiOut, "message")->Send(msg);
	}

	// Change instrument
	msg->SetProgramChange (0, 16);
	IComponent::FindInputPin(*midiOut, "message")->Send(msg);

	// Play scale
	for (unsigned char note= 40; note< 60; ++note) {
		msg->SetNoteOn (0, note, 127);
		IComponent::FindInputPin(*midiOut, "message")->Send(msg);
		wxMilliSleep(100);
		msg->SetNoteOff (0, note, 127);
		IComponent::FindInputPin(*midiOut, "message")->Send(msg);
	}

	midiOut->Finish();
}


};
