/////////////////////////////////////////////////////////////////////////////
// Name:        filepicker.cpp
// Purpose:     
// Author:      César Mauri Loba
// Modified by: 
// Created:     18/05/2011 09:45:13
// 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/>.    
/////////////////////////////////////////////////////////////////////////////

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

#include "filepicker.h"
#include <wx/filedlg.h>
#include <wx/dirdlg.h>
#include <wx/sizer.h>
#include <wx/bitmap.h>
#include <wx/statbox.h>
#include <wx/textctrl.h>
#include <wx/button.h>

#include <sys/types.h>
#include <sys/stat.h>

#ifdef WIN32
#include <io.h>
#define access(path,mode) _access(path,mode)
#define stat(path,buf) _stat(path,buf)
#define R_OK    4               /* Test for read permission.  */
typedef struct _stat t_stat;
#define S_ISDIR(x) (x & _S_IFDIR)
#define S_ISREG(x) (x & _S_IFREG)
#else
#include <unistd.h>
typedef struct stat t_stat;
#endif

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

using namespace spcore;
using namespace std;

namespace mod_widgets {

FilePickerComponent::FilePickerComponent(const char * name, int argc, const char * argv[])
: CComponentAdapter(name, argc, argv)
, m_pickDirectory(false)
, m_panel(NULL)
{
	// Create pins and storage
	m_iPin= SmartPtr<IInputPin>(new InputPinValue(*this), false);
	m_oPin= CTypeString::CreateOutputPin("value");		
	m_value= CTypeString::CreateInstance();
	RegisterInputPin (*m_iPin);
	RegisterOutputPin (*m_oPin);		
	
	// Process arguments
	if (argc) {
		for (int i= 0; i< argc; ++i) {
			if (strcmp ("-v", argv[i])== 0) {
				// Value
			
				++i;
				if (i< argc) m_value->set(argv[i]);				
				else throw std::runtime_error("widget_filepicker. Wrong value for option --v");
			}
			else if (strcmp ("-l", argv[i])== 0) {
				// Label
				++i;

				if (i== argc) throw std::runtime_error("widget_filepicker. Missing value for -l argument");
				m_label= argv[i];
			}
			else if (strcmp ("-w", argv[i])== 0) {
				// Wildcard
				++i;

				if (i== argc) throw std::runtime_error("widget_filepicker. Missing value for -w argument");
				m_wildcard= argv[i];
			}
			else if (strcmp ("-t", argv[i])== 0) {
				// Type
				++i;

				char opt= 0;

				if (i< argc && (opt= argv[i][0]) && argv[i][1]== 0 && (opt== 'd' || opt== 'a' )) {
					if (opt== 'd') m_pickDirectory= true;
					else m_pickDirectory= false;
				}
				else throw std::runtime_error("widget_filepicker. Wrong value for option -t. Use either d or a.");				
			}
			else if (strlen(argv[i])) {
				string error_msg("widget_slider. Unknown option:");
				error_msg+= argv[i];
				throw std::runtime_error(error_msg);
			}
		}
	}
}

bool FilePickerComponent::IsValid(const char* path) const
{
	if (access(path, R_OK)!= 0) return false;

	// Is file or directory?
	t_stat statbuf;
	if (stat(path,&statbuf)== 0) {
		if (m_pickDirectory)
			return (S_ISDIR(statbuf.st_mode)? true : false);
		else
			return (S_ISREG(statbuf.st_mode)? true : false);
	}
	else 
		return false;
}

int FilePickerComponent::DoInitialize()
{
	if (IsValid(m_value->get())) {
		if (m_panel) m_panel->ValueChanged();
		m_oPin->Send(m_value);
	}
	else
		m_value->set("");

	return 0;
}

wxWindow* FilePickerComponent::GetGUI(wxWindow * parent) {
	assert (wxIsMainThread());
	if (m_panel) {
		// Already created
		assert (false);
		getSpCoreRuntime()->LogMessage(ICoreRuntime::LOG_ERROR, "panel alredy open", "filepicker");
		return NULL;
	}
	else {
		m_panel= new FilePickerPanel();
		m_panel->SetComponent(this);
		m_panel->Create(parent);
	}

	return m_panel;
}

// 
// Called from GUI
//	

bool FilePickerComponent::SetFilePickerValue (const char* v)
{
	if (strcmp(m_value->get(), v)!= 0 && IsValid(v)) {
		m_value->set(v);
		m_oPin->Send(m_value);
		return true;
	}
	return false;
}

const char* FilePickerComponent::GetFilePickerValue() const
{
	return m_value->get();
}

void FilePickerComponent::OnPanelDestroyed ()
{
	assert (wxIsMainThread());
	m_panel= NULL;
}

// 
// Private methods
//	

void FilePickerComponent::OnPinValue (const CTypeString & msg)
{
	if (SetFilePickerValue (msg.get()) && m_panel) m_panel->ValueChanged();
}

FilePickerComponent::~FilePickerComponent()
{
	assert (wxIsMainThread());
	if (m_panel) {
		m_panel->SetComponent(NULL);
		m_panel->Close();
		m_panel= NULL;
	}
}

//////////////////////////////////////////////////////////////////////////////


/*!
 * FilePickerPanel type definition
 */

IMPLEMENT_DYNAMIC_CLASS( FilePickerPanel, wxPanel )

// New event to comunicate updates to GUI
DECLARE_LOCAL_EVENT_TYPE(wxEVT_SPFILEPICKER_VALUE_CHANGE, -1)
DEFINE_LOCAL_EVENT_TYPE(wxEVT_SPFILEPICKER_VALUE_CHANGE)

/*!
 * FilePickerPanel event table definition
 */

BEGIN_EVENT_TABLE( FilePickerPanel, wxPanel )

////@begin FilePickerPanel event table entries
    EVT_BUTTON( ID_BUTTON_CHOOSE, FilePickerPanel::OnButtonChooseClick )

////@end FilePickerPanel event table entries

	EVT_COMMAND  (wxID_ANY,wxEVT_SPFILEPICKER_VALUE_CHANGE, FilePickerPanel::OnValueChanged)

END_EVENT_TABLE()


/*!
 * FilePickerPanel constructors
 */

FilePickerPanel::FilePickerPanel()
{
    Init();
}

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


/*!
 * FilePickerPanel creator
 */

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

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


/*!
 * FilePickerPanel destructor
 */

FilePickerPanel::~FilePickerPanel()
{
	if (m_component!= NULL) {
		m_component->OnPanelDestroyed();
		m_component= NULL;
	}
////@begin FilePickerPanel destruction
////@end FilePickerPanel destruction
}


/*!
 * Member initialisation
 */

void FilePickerPanel::Init()
{
	m_component= NULL;
////@begin FilePickerPanel member initialisation
    m_staSizer = NULL;
    m_txtFilePath = NULL;
////@end FilePickerPanel member initialisation
}


/*!
 * Control creation for FilePickerPanel
 */

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

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

    m_staSizer = new wxStaticBox(itemPanel1, wxID_ANY, wxEmptyString);
    wxStaticBoxSizer* itemStaticBoxSizer3 = new wxStaticBoxSizer(m_staSizer, wxHORIZONTAL);
    itemBoxSizer2->Add(itemStaticBoxSizer3, 0, wxGROW|wxLEFT|wxRIGHT, 5);

    m_txtFilePath = new wxTextCtrl;
    m_txtFilePath->Create( itemPanel1, ID_TEXTCTRL_FILE_PATH, wxEmptyString, wxDefaultPosition, wxSize(200, -1), wxTE_READONLY );
    itemStaticBoxSizer3->Add(m_txtFilePath, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    wxButton* itemButton5 = new wxButton;
    itemButton5->Create( itemPanel1, ID_BUTTON_CHOOSE, _("Choose..."), wxDefaultPosition, wxDefaultSize, 0 );
    itemStaticBoxSizer3->Add(itemButton5, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

////@end FilePickerPanel content construction

	assert (m_component);

	// Label
	if (m_component->GetLabel().size()) {
		wxString label(m_component->GetLabel().c_str(), wxConvUTF8);
		m_staSizer->SetLabel(label);
	}
}


/*!
 * Should we show tooltips?
 */

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

/*!
 * Get bitmap resources
 */

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

/*!
 * Get icon resources
 */

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


/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_BUTTON_CHOOSE
 */

void FilePickerPanel::OnButtonChooseClick( wxCommandEvent& event )
{
	wxString wildcard(m_component->GetWildcard().c_str(), wxConvUTF8);
	
	if (m_component) {
		if (m_component->GetPickDirectory()) {
			// Pick a directory
			wxDirDialog dlg(this, _("Choose a directory"), _T(""), wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
			if (dlg.ShowModal()== wxID_OK && m_component->SetFilePickerValue(dlg.GetPath().mb_str()))
				OnValueChanged( event );
		}
		else {
			// Pick a regular file
			wxFileDialog dlg(this, _("Choose a file to open"), _T(""), _T(""), wildcard, wxFD_OPEN);
			if (dlg.ShowModal()== wxID_OK && m_component->SetFilePickerValue(dlg.GetPath().mb_str()))
				OnValueChanged( event );
		}
	}
	
    event.Skip(false);
}

void FilePickerPanel::ValueChanged()
{
	wxCommandEvent event(wxEVT_SPFILEPICKER_VALUE_CHANGE);
		
	if (!wxIsMainThread()) wxPostEvent(this, event);
	else OnValueChanged( event );
}

void FilePickerPanel::OnValueChanged( wxCommandEvent& )
{
	if (m_component) {
		wxString path(m_component->GetFilePickerValue(), wxConvUTF8);
		m_txtFilePath->SetValue(path);		
	}
}

}; // namespace

