/////////////////////////////////////////////////////////////////////////////
// Name:        MenuObjectPropDlg.cpp
// Purpose:     DVD menu button properties dialog
// Author:      Alex Thuering
// Created:	20.11.2003
// RCS-ID:      $Id: MenuObjectPropDlg.cpp,v 1.58 2012/07/01 19:27:08 ntalex Exp $
// Copyright:   (c) Alex Thuering
// Licence:     GPL
/////////////////////////////////////////////////////////////////////////////

#include "MenuObjectPropDlg.h"
#include "VideoFrameDlg.h"
#include "Config.h"
#include <wxSVG/svg.h>
#include <wx/statline.h>
#include <stdint.h>

enum {
	JUMP_ACTION_RADIO_ID = 7900,
	CUSTOM_ACTION_RADIO_ID,
	TARGET_CHOICE_ID,
	CHAPTER_CHOICE_ID,
	AUTO_SIZE_RADIO_ID,
	KEEP_ASPECT_CB_ID,
	IMAGE_RADIO_ID,
	VIDEOFRAME_RADIO_ID,
	VIDEOFRAME_BT_ID
};

BEGIN_EVENT_TABLE(MenuObjectPropDlg, wxPropDlg)
	EVT_RADIOBUTTON(JUMP_ACTION_RADIO_ID, MenuObjectPropDlg::OnJumpActionSelected)
	EVT_RADIOBUTTON(CUSTOM_ACTION_RADIO_ID, MenuObjectPropDlg::OnCustomActionSelected)
	EVT_CHOICE(TARGET_CHOICE_ID, MenuObjectPropDlg::OnChangeTarget)
	EVT_CHOICE(CHAPTER_CHOICE_ID, MenuObjectPropDlg::OnChangeChapter)
	EVT_RADIOBUTTON(KEEP_ASPECT_CB_ID, MenuObjectPropDlg::OnKeepAspectRatio)
	EVT_RADIOBUTTON(IMAGE_RADIO_ID, MenuObjectPropDlg::OnImageRadio)
	EVT_RADIOBUTTON(VIDEOFRAME_RADIO_ID, MenuObjectPropDlg::OnImageRadio)
	EVT_BUTTON(VIDEOFRAME_BT_ID, MenuObjectPropDlg::OnVideoFrame)
END_EVENT_TABLE()

MenuObjectPropDlg::MenuObjectPropDlg(wxWindow* parent, wxString id, bool multObjects, Menu* menu, DVD* dvd, int tsi,
		int pgci): wxPropDlg(parent, wxString(_("Properties"))
				+ (!multObjects ? wxT(" - ") + menu->GetObject(id)->GetId(true) : wxT(""))) {
	m_id = id;
	m_multObjects = multObjects;
	m_menu = menu;
	m_dvd = dvd;
	m_tsi = tsi;
	m_pgci = pgci;
	m_imageEdit = NULL;
	m_imageRadio = NULL;
	m_videoFrameRadio = NULL;
	m_videoFrameBt = NULL;
	m_customActionEdit = NULL;
	m_widthEdit = NULL;
	m_heightEdit = NULL;
	m_object = menu->GetObject(id);
	m_displayVideoFrame = m_object->IsDisplayVideoFrame();
	m_defaultPos = 0;
	m_videoPos = 0;
	m_videoDuration = 0;
	Create();
}

void MenuObjectPropDlg::CreatePropPanel(wxSizer* sizer) {
	wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
	wxFlexGridSizer* grid = NULL;

	// action
	if (m_object->IsButton() && !m_multObjects) {
		DVDAction& action = m_object->GetAction();
		AddStaticLine(mainSizer, _("Action"));
		grid = new wxFlexGridSizer(2, 4, 16);
		grid->AddGrowableCol(1);
		// check menu entry if it is set
		wxString customAction = action.GetCustom();
		if (action.GetEntry().length() > 0 && customAction.length() == 0) {
			// find menu with given entry
			Menus& menus = (Menus&) m_dvd->GetPgcArray(action.GetTsi(), true);
			int pgci = menus.GetPgciByEntry(action.GetEntry());
			if (pgci >= 0) {
				action.SetPgci(pgci);
			} else {
				// entry is not valid => set custom action
				customAction = action.AsString(m_dvd);
			}
		}
		// jump to
		AddRadioProp(grid, _("Jump to") + wxString(wxT(":")), customAction.length() == 0, wxRB_GROUP, false,
				JUMP_ACTION_RADIO_ID);
		wxSizer* jumpSizer = new wxFlexGridSizer(4, 4, 4);
		AddChoiceProp(jumpSizer, wxT(""), wxT(""), wxArrayString(), -1, false, TARGET_CHOICE_ID);
		m_targetChoice = (wxChoice*) m_controls[m_controls.Count()-1];
		FillTargets(m_targetChoice);
		AddChoiceProp(jumpSizer, wxT(""), wxT(""), wxArrayString(), -1, true, CHAPTER_CHOICE_ID);
		m_chapterChoice = (wxChoice*) m_controls[m_controls.Count()-1];
		UpdateChapters();
		AddCheckProp(jumpSizer, _("Play all titles"), action.IsPlayAll());
		grid->Add(jumpSizer);
		// customAction
		if (!customAction.length()) {
			// check if selection was ok, otherwise set this action as custom action
			int tsi = action.GetTsi() > -2 ? action.GetTsi() : m_tsi;
			int pgci = action.GetPgci() > -1 ? action.GetPgci() : m_pgci;
			bool menu = action.GetPgci() > -1 ? action.IsMenu() : true;
			if (GetSelectedTsi() != tsi || GetSelectedPgci() != pgci || IsSelectedMenu() != menu
					|| GetSelectedChapter() != action.GetChapter())
				customAction = action.AsString(m_dvd);
		}
		AddRadioProp(grid, _("Custom") + wxString(wxT(":")), customAction.length() > 0, 0, false,
				CUSTOM_ACTION_RADIO_ID);
		AddTextProp(grid, wxT(""), customAction);
		m_customActionEdit = (wxTextCtrl*) m_controls[m_controls.Count()-1];
		mainSizer->Add(grid, 0, wxEXPAND|wxBOTTOM, 8);
		wxCommandEvent evt;
		if (customAction.length())
			OnCustomActionSelected(evt);
		else
			OnJumpActionSelected(evt);

		// audio & subtitle
		wxArrayString labels;
		labels.Add(_("last selected"));
		for (int i = 0; i < (int) m_dvd->GetAudioStreamCount(); i++)
			labels.Add(_("track") + wxString::Format(wxT(" %d"), i + 1));
		AddText(grid, _("Audio") + wxString(wxT(":")), wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT);
		wxSizer* s = AddChoiceProp(grid, wxT(""), labels[action.GetAudio()+1], labels, 0, false);
		if (m_dvd->GetAudioStreamCount() == 1)
			GetLastControl()->Enable(false);
		s->Add(16, 16);
		labels.Clear();
		labels.Add(_("last selected"));
		labels.Add(_("off"));
		for (int i = 0; i < (int) m_dvd->GetSubtitleStreamsCount(); i++)
			labels.Add(_("track") + wxString::Format(wxT(" %d"), i + 1));
		AddText(s, _("subtitle") + wxString(wxT(":")));
		s->Add(16, 16);
		int subtitleIdx = action.GetSubtitle() + 1 < (int) labels.size() ? action.GetSubtitle() + 1 : 0;
		AddChoiceProp(s, wxT(""), labels[subtitleIdx], labels, 0, true);
		if (m_dvd->GetSubtitleStreamsCount() == 0)
			GetLastControl()->Enable(false);

		grid = new wxFlexGridSizer(3, 4, 4, 16);
		grid->AddGrowableCol(0);
		grid->Add(10,10);
		AddText(grid, _("Focus"));
		AddFocusDestProp(grid, nbUP);
		grid->Add(10,10);
		grid->Add(10,10);
		AddFocusDestProp(grid, nbLEFT);
		grid->Add(10,10);
		AddFocusDestProp(grid, nbRIGHT);
		grid->Add(10,10);
		grid->Add(10,10);
		AddFocusDestProp(grid, nbDOWN);
		grid->Add(10,10);
		mainSizer->Add(grid, 0, wxEXPAND|wxALL, 4);
		AddStaticLine(mainSizer, _("Look"));
	}
    CreateLook(mainSizer, grid);
    if (!m_multObjects)
		CreateLocAndSize(mainSizer);

	sizer->Add(mainSizer, 1, wxEXPAND|wxALL, 4);
}

void MenuObjectPropDlg::CreateLook(wxBoxSizer* mainSizer, wxFlexGridSizer* grid) {
    // object look parameters
    bool lastChangeable = false;
    for (int i=0; i<m_object->GetObjectParamsCount(); i++) {
		MenuObjectParam* param = m_object->GetObjectParam(i);

		if (i == 0 || param->changeable != lastChangeable) {
			if (param->changeable) {
				grid = new wxFlexGridSizer(3, 4, 4, 16);
				AddText(grid, wxT(""));
				AddText(grid, _("Normal"));
				AddText(grid, _("Highlighted"));
				AddText(grid, _("Selected"));
			} else {
				grid = new wxFlexGridSizer(2, 4, 16);
				grid->AddGrowableCol(1);
			}
			if (i==0)
				mainSizer->Add(grid, 0, wxEXPAND|wxTOP|wxBOTTOM, 4);
			else
				mainSizer->Add(grid, 0, wxEXPAND|wxBOTTOM, 4);
			lastChangeable = param->changeable;
		}

		wxString title = wxGetTranslation((const wxChar*)param->title.GetData()) + wxString(wxT(":"));

		if (param->changeable && param->type == _T("colour")) {
			AddColourProp(grid, title, m_object->GetParamColour(param->name));
			AddColourProp(grid, wxT(""), m_object->GetParamColour(param->name, mbsHIGHLIGHTED));
			AddColourProp(grid, wxT(""), m_object->GetParamColour(param->name, mbsSELECTED));
		} else {
			if (param->type == _T("text")) {
				AddText(grid, title);
				wxBoxSizer* sizer2 = new wxBoxSizer(wxHORIZONTAL);
				AddTextProp(sizer2, wxT(""), m_object->GetParam(param->name), m_multObjects, -1, true, wxTE_MULTILINE);
				if (m_multObjects)
					GetLastControl()->Enable(false);
				AddFontProp(sizer2, wxT(""), m_object->GetParamFont(param->name), _("Font..."));
				grid->Add(sizer2, 0, wxEXPAND);
			} else if (param->type == _T("string")) {
				AddTextProp(grid, title, m_object->GetParam(param->name));
			} else if (param->type == _T("decimal")) {
				AddTextProp(grid, title, m_object->GetParam(param->name), false, 54);
				if (m_multObjects && param->attribute.Find(wxT('#')) != wxNOT_FOUND)
					GetLastControl()->Enable(false);
			} else if (param->type.Mid(0,7) == _T("integer")) {
				long min = 0, max = 999;
				if (param->type.Find(wxT('(')) != -1 && param->type.Find(wxT(')')) != -1) {
					param->type.AfterFirst(wxT('(')).BeforeFirst(wxT(',')).Strip(wxString::both).ToLong(&min);
					param->type.BeforeFirst(wxT(')')).AfterFirst(wxT(',')).Strip(wxString::both).ToLong(&max);
				}
				AddSpinProp(grid, title, m_object->GetParamInt(param->name), min, max, max < 1000 ? 54 : 80);
				if (m_multObjects && param->attribute.Find(wxT('#')) != wxNOT_FOUND)
					GetLastControl()->Enable(false);
			} else if (param->type == _T("image") && !m_multObjects) {
				wxString imageFile = m_object->GetParam(param->name);
				if (m_object->IsButton()) {
					bool hasVideo = GetVideoFilename(false).length();
					wxString fname = imageFile.Find(wxT('#')) != -1 ? imageFile.BeforeLast(wxT('#')) : imageFile;
					bool image = !m_displayVideoFrame || !hasVideo || fname != GetVideoFilename(false);
					AddRadioProp(grid, wxString(_("Image")) + wxT(":"), image, wxRB_GROUP, false, IMAGE_RADIO_ID);
					m_imageRadio = (wxRadioButton*) GetLastControl();
					AddFileProp(grid, wxT(""), image ? imageFile : wxT(""), wxFD_OPEN, wxT("..."),
							_("Image Files ") + wxImage::GetImageExtWildcard()
							+ wxT("|") + wxString(_("All Files")) + wxT(" (*.*)|*.*"));
					m_imageEdit = (wxTextCtrl*) GetLastControl();
					m_imageEditIdx = GetLastControlIndex();
					AddRadioProp(grid, wxString(_("Video")) + wxT(":"), !image, 0, false, VIDEOFRAME_RADIO_ID);
					m_videoFrameRadio = (wxRadioButton*) GetLastControl();
					m_videoFrameRadio->Enable(hasVideo);
					m_videoFrameBt = new wxButton(this, VIDEOFRAME_BT_ID, wxT("..."));
					int h = m_videoFrameBt->GetSize().GetHeight() > 24 ? m_videoFrameBt->GetSize().GetHeight() : 24;
					m_videoFrameBt->SetSizeHints(h, h, h, h);
					grid->Add(m_videoFrameBt);
					wxCommandEvent evt;
					OnImageRadio(evt);
					// default video position
					wxString url = GetVideoFilename(true);
					if (url.length())
						url.AfterLast(wxT('#')).ToLong(&m_defaultPos);
					// video position
					if (!image) {
						m_videoPos = lround(m_object->GetParamVideoClipBegin(param->name) * 1000);
						if (!image && imageFile.Find(wxT('#')) != -1) {
							wxString vf = imageFile.AfterLast(wxT('#'));
							if (vf.length() > 0)
								vf.ToLong(&m_videoPos);
						}
					} else
						m_videoPos = m_defaultPos;
					// video duration
					m_videoDuration = m_object->GetParamVideoDuration(param->name);
				} else {
					AddFileProp(grid, title, imageFile, wxFD_OPEN,
						wxT("..."), _("Image Files ") + wxImage::GetImageExtWildcard()
						+ wxT("|") + wxString(_("All Files")) + wxT(" (*.*)|*.*"));
					if (m_multObjects)
						GetLastControl()->Enable(false);
				}
			} else if (param->type == _T("colour")) {
				int opacity = 100;
				wxString opacityStr = m_object->GetParam(param->name, wxT("-opacity"));
				if (opacityStr.length() > 0) {
					double dval;
					opacityStr.ToDouble(&dval);
					opacity = (int) (dval*100);
				}
				AddColourProp(grid, title, m_object->GetParamColour(param->name), opacity);
			} else if (param->type == wxT("shadow")) {
				bool shadow = m_object->GetParam(param->name, wxT("visibility")) != wxT("hidden");
				BeginCheckGroup(grid, title, shadow, false);
				wxSizer* shadowSizer = new wxBoxSizer(wxHORIZONTAL);
				grid->Add(shadowSizer);
				int opacity = 100;
				wxString opacityStr = m_object->GetParam(param->name, wxT("-opacity"));
				if (opacityStr.length() > 0) {
					double dval;
					opacityStr.ToDouble(&dval);
					opacity = (int) (dval*100);
				}
				AddColourProp(shadowSizer, wxT(""), m_object->GetParamColour(param->name), opacity);
				shadowSizer->AddSpacer(8);
				AddText(shadowSizer, _("Offset:"));
				shadowSizer->AddSpacer(4);
				AddSpinProp(shadowSizer, wxT(""), m_object->GetParamInt(param->name, wxT("x")), -999, 999, 54, wxT(""), false);
				AddSpinProp(shadowSizer, wxT(""), m_object->GetParamInt(param->name, wxT("y")), -999, 999, 54, wxT(""), false);
				shadowSizer->AddSpacer(4);
				wxSVGElement* filter = m_object->GetElementById(param->element + wxT("Filter"));
				if (filter && ((wxSVGElement*)filter->GetFirstChild())->GetDtd() == wxSVG_FEGAUSSIANBLUR_ELEMENT) {
					wxSVGFEGaussianBlurElement* blur = (wxSVGFEGaussianBlurElement*) filter->GetFirstChild();
					AddText(shadowSizer, _("Deviation:"));
					shadowSizer->AddSpacer(4);
					AddTextProp(shadowSizer, wxT(""), blur->GetAttribute(wxT("stdDeviation")), false, 54);
				}
				EndGroup();
			}
		}
	}
}

void MenuObjectPropDlg::CreateLocAndSize(wxBoxSizer* mainSizer) {
	wxSizer* hSizer = new wxBoxSizer(wxHORIZONTAL);
	mainSizer->Add(hSizer, 0, wxTOP, 8);

	// object location
	wxSizer* grpSizer = BeginGroup(hSizer, _("Location"));
	wxFlexGridSizer* grid = new wxFlexGridSizer(2, 4, 16);
	AddSpinProp(grid, _("X:"), m_object->GetX(), 0, m_menu->GetResolution().GetWidth()-8);
	AddSpinProp(grid, _("Y:"), m_object->GetY(), 0, m_menu->GetResolution().GetHeight()-8);
	grpSizer->Add(grid, 0, wxALL, 4);
	EndGroup();
	hSizer->AddSpacer(8);

	// object size
	grpSizer = BeginGroup(hSizer, _("Size"), _("Custom"), !m_object->IsDefaultSize());
	grid = new wxFlexGridSizer(2, 4, 16);
	AddSpinProp(grid, _("Width:"), m_object->GetWidth(), 0, m_menu->GetResolution().GetWidth());
	m_widthEdit = (wxTextCtrl*) m_controls[m_controls.Count()-1];
	AddSpinProp(grid, _("Height:"), m_object->GetHeight(), 0, m_menu->GetResolution().GetHeight());
	m_heightEdit = (wxTextCtrl*) m_controls[m_controls.Count()-1];
	grid->AddSpacer(4);
	AddCheckProp(grid, _("Keep Aspect Ratio"), m_object->IsKeepAspectRatio(), false, KEEP_ASPECT_CB_ID);
	grpSizer->Add(grid, 0, wxALL, 4);
	EndGroup();
}

int MenuObjectPropDlg::GetSelectedTsi() {
	int tsi = 0;
	if (m_targetChoice->GetSelection() >= 0)
		tsi = ((intptr_t) m_targetChoice->GetClientData(m_targetChoice->GetSelection()))/1000 - 1;
	return tsi;
}

int MenuObjectPropDlg::GetSelectedPgci() {
	if (m_targetChoice->GetSelection() >= 0)
		return (((intptr_t) m_targetChoice->GetClientData(m_targetChoice->GetSelection())) % 1000) / 2;
	return 0;
}

bool MenuObjectPropDlg::IsSelectedMenu() {
	if (m_targetChoice->GetSelection() >= 0)
		return (((intptr_t) m_targetChoice->GetClientData(m_targetChoice->GetSelection())) % 1000) % 2 == 0;
	return true;
}

int MenuObjectPropDlg::GetSelectedChapter() {
	if (m_chapterChoice->GetSelection() >= 0)
		return m_chapterChoice->GetSelection();
	return 0;
}

void* MenuObjectPropDlg::TargetToPtr(int tsi, int pgci, bool menu) {
	return (void*) (((long) tsi+1)*1000 + pgci*2 + (menu ? 0 : 1));
}

/**
 * Fills choice "targets" with possible action targets
 */
void MenuObjectPropDlg::FillTargets(wxChoice* ctrl) {
	int sel = 0;
	DVDAction& action = m_object->GetAction(); // current action
	int actionTsi = action.GetTsi() > -2 ? action.GetTsi() : m_tsi; // tsi of current action target
	int actionPgci = action.GetPgci() > -1 ? action.GetPgci() : m_pgci; // pgci of current action target
	int actionMenu = action.GetPgci() > -1 ? action.IsMenu() : true; // menu/title is target of current action

	ctrl->Append(_("start of current menu"), TargetToPtr(m_tsi, m_pgci, true));

	// add a jump target for every title and menu in every titleset if possible
	for (int tsi = -1; tsi < (int)m_dvd->GetTitlesets().Count(); tsi++) {
		if (tsi == -1) { // Video-Manager-Domain
			// jumpt to vmMenu
			for (int pgci = 0; pgci < (int) m_dvd->GetVmgm().Count(); pgci++) {
				if (tsi == m_tsi && pgci == m_pgci)
					continue; // current menu
				ctrl->Append(wxString::Format(_("vmMenu %d"), pgci + 1), TargetToPtr(tsi, pgci, true));
				if (tsi == actionTsi && pgci == actionPgci && actionMenu)
					sel = ctrl->GetCount() - 1; // current action target
			}
		} else { // Titleset
			Titleset* ts = m_dvd->GetTitlesets()[tsi];
			// jumpt to menu
			for (int pgci = 0; pgci < (int) ts->GetMenus().Count(); pgci++) {
				if (tsi == m_tsi && pgci == m_pgci)
					continue; // current menu
				Pgc* pgc = ts->GetMenus()[pgci];
				wxString label = _("menu") + wxString::Format(wxT(" %d"), pgci + 1);
				if (!m_dvd->IsJumppadsEnabled() && m_tsi != tsi) {
					int rootMenu = ts->GetMenus().GetPgciByEntry(wxT("root"));
					if (pgci != rootMenu && pgc->GetEntries().size() == 0)
						continue; // cannot jump to specific menu from other titleset, only to an entry
					const wxString entries[6] = {
							_("title vmMenu"), _("root menu"), _("subtitle menu"),
							_("audio menu"), _("angle menu"), _("chapter menu")};
					int entryIdx = pgc->GetEntries().size() > 0 ? s_entries.Index(*pgc->GetEntries().begin()) : 1;
					if (entryIdx >= 0)
						label = label + wxT(" (") + entries[entryIdx] + wxT(")");
				}
				if (m_dvd->GetTitlesets().Count() > 1)
					label = _("titleset") + wxString::Format(wxT(" %d "), tsi + 1) + label;
				ctrl->Append(label, TargetToPtr(tsi, pgci, true));
				if (tsi == actionTsi && pgci == actionPgci && actionMenu)
					sel = ctrl->GetCount() - 1;
			}
			// jump to not existing menu
			if (tsi == actionTsi && actionPgci >= (int) ts->GetMenus().Count() && actionMenu) {
				wxString label = _("menu") + wxString::Format(wxT(" %d*"), actionPgci + 1);
				if (m_dvd->GetTitlesets().Count() > 1)
					label = _("titleset") + wxString::Format(wxT(" %d "), tsi + 1) + label;
				ctrl->Append(label, TargetToPtr(tsi, actionPgci, true));
				sel = ctrl->GetCount() - 1;
			}
			// jumping from titleset menu is allowed only to titles from the same titleset
			if (m_dvd->IsJumppadsEnabled() || m_tsi == -1 || m_tsi == tsi) {
				// jump to title
				for (int pgci = 0; pgci < (int) ts->GetTitles().Count(); pgci++) {
					wxString label = _("title") + wxString::Format(wxT(" %d"), pgci + 1);
					if (m_dvd->GetTitlesets().Count() > 1)
						label = _("titleset") + wxString::Format(wxT(" %d "), tsi + 1) + label;
					ctrl->Append(label, TargetToPtr(tsi, pgci, false));
					if (tsi == actionTsi && pgci == actionPgci && !actionMenu)
						sel = ctrl->GetCount() - 1;
				}
				// jump to not existing title
				if (tsi == actionTsi && actionPgci >= (int) ts->GetTitles().Count() && !actionMenu) {
					wxString label = _("title") + wxString::Format(wxT(" %d*"), actionPgci + 1);
					if (m_dvd->GetTitlesets().Count() > 1)
						label = _("titleset") + wxString::Format(wxT(" %d "), tsi + 1) + label;
					ctrl->Append(label, TargetToPtr(tsi, actionPgci, false));
					sel = ctrl->GetCount() - 1;
				}
			}
		}
	}
	ctrl->SetSelection(sel);
}

void MenuObjectPropDlg::UpdateChapters() {
	wxChoice* ctrl = m_chapterChoice;
	int tsi = GetSelectedTsi();
	int pgci = GetSelectedPgci();
	bool menu = IsSelectedMenu();
	int chapter = ctrl->GetCount() ? GetSelectedChapter() : m_object->GetAction().GetChapter();
	ctrl->Clear();
	ctrl->Append(wxString::Format(_("chapter %d"), 1));
	PgcArray& pgcs = m_dvd->GetPgcArray(tsi, false);
	if (tsi >= 0 && !menu && pgci < (int) pgcs.Count())
		for (int i = 1; i < (int) pgcs[pgci]->GetChapterCount(); i++)
			ctrl->Append(wxString::Format(_("chapter %d"), i + 1));
	ctrl->SetSelection(chapter);
	ctrl->Enable(ctrl->GetCount() > 1 && (m_dvd->IsJumppadsEnabled() || m_tsi != -1));
}

void MenuObjectPropDlg::OnChangeTarget(wxCommandEvent& evt) {
	UpdateChapters();
	if (m_videoFrameRadio) {
		m_videoFrameRadio->Enable(GetVideoFilename(false).length());
		if (!m_videoFrameRadio->IsEnabled() && !m_imageRadio->GetValue()) {
			m_imageRadio->SetValue(true);
			wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, m_imageRadio->GetId());
			GetEventHandler()->ProcessEvent(event);
		} else if (m_displayVideoFrame && !m_videoFrameRadio->GetValue()) {
			m_videoFrameRadio->SetValue(true);
			wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, m_imageRadio->GetId());
			GetEventHandler()->ProcessEvent(event);
		}
		// reset video position
		wxString url = GetVideoFilename(true);
		if (url.length()) {
			url.AfterLast(wxT('#')).ToLong(&m_defaultPos);
			m_videoPos = m_defaultPos;
		}
	}
}

void MenuObjectPropDlg::OnChangeChapter(wxCommandEvent& evt) {
	// reset video position
	wxString url = GetVideoFilename(true);
	if (url.length()) {
		bool isDefaultPos = m_videoPos == m_defaultPos;
		url.AfterLast(wxT('#')).ToLong(&m_defaultPos);
		if (isDefaultPos)
			m_videoPos = m_defaultPos;
	}
}

void MenuObjectPropDlg::OnJumpActionSelected(wxCommandEvent& evt) {
	m_targetChoice->Enable(true);
	m_chapterChoice->Enable(m_chapterChoice->GetCount() > 1 && (m_dvd->IsJumppadsEnabled() || m_tsi != -1));
	m_customActionEdit->Enable(false);
	if (m_videoFrameRadio) {
		m_videoFrameRadio->Enable(GetVideoFilename(false).length());
		if (GetVideoFilename(false).length() == 0) {
			m_imageRadio->SetValue(true);
			wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, m_imageRadio->GetId());
			GetEventHandler()->ProcessEvent(event);
		}
		else if (GetVideoFilename(false).length() && m_imageEdit->GetValue().length() == 0)
			m_videoFrameRadio->SetValue(true);
		wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, m_videoFrameRadio->GetId());
		GetEventHandler()->ProcessEvent(event);
	}
}

void MenuObjectPropDlg::OnCustomActionSelected(wxCommandEvent& evt) {
	m_targetChoice->Enable(false);
	m_chapterChoice->Enable(false);
	m_customActionEdit->Enable(true);
	if (m_customActionEdit->GetValue().length() == 0) {
		int tsi = m_object->GetAction().GetTsi();
		m_object->GetAction().SetTsi(GetSelectedTsi() != m_tsi ? GetSelectedTsi() : -2);
		m_customActionEdit->SetValue(m_object->GetAction().AsString(m_dvd));
		m_object->GetAction().SetTsi(tsi);
	}
}

wxString MenuObjectPropDlg::GetVideoFilename(bool withTimestamp, long position) {
	int tsi = -1;
	int pgci = 0;
	int chapter = 0;
	if (!GetBool(0)) { // custom action
		DVDAction action(m_object->GetAction());
		action.SetCustom(m_customActionEdit->GetValue());
		int id = action.FindFirstJump(m_tsi);
		if (id >= 0) {
			tsi = DVD::GetTsi(id);
			pgci = DVD::GetPgci(id);
			chapter = DVD::GetVobi(id);
		}
	} else if (!IsSelectedMenu()) {
		tsi = GetSelectedTsi();
		pgci = GetSelectedPgci();
		chapter = GetSelectedChapter();
	}

	if (tsi < 0 || tsi >= (int) m_dvd->GetTitlesets().size())
		return wxT("");
	Pgc* pgc = m_dvd->GetPgc(tsi, false, pgci);
	if (!pgc)
		return wxT("");
	return withTimestamp ? pgc->GetVideoFrameUri(chapter, position) : pgc->GetVideoFrameUri(chapter, -1, true);
}

void MenuObjectPropDlg::OnImageRadio(wxCommandEvent& evt){
	m_imageEdit->Enable(m_imageRadio->GetValue());
	wxWindow* button = FindWindowByName(wxString::Format(wxT("SelectFileButton_%d"), m_imageEditIdx));
	if (button != NULL)
		button->Enable(m_imageRadio->GetValue());
	if (m_videoFrameRadio->IsEnabled())
		m_displayVideoFrame = m_videoFrameRadio->GetValue();
	m_videoFrameBt->Enable(m_videoFrameRadio->GetValue());
}

void MenuObjectPropDlg::OnVideoFrame(wxCommandEvent& evt) {
	VideoFrameDlg dlg(this, GetVideoFilename(false), false, m_defaultPos, m_videoPos, m_videoDuration);
	if (dlg.ShowModal() == wxID_OK) {
		m_videoPos = dlg.GetPos();
		m_videoDuration = dlg.GetDuration();
	}
}

void MenuObjectPropDlg::OnKeepAspectRatio(wxCommandEvent& evt) {
	m_heightEdit->SetValue(m_widthEdit->GetValue());
}

void MenuObjectPropDlg::AddFocusDestProp(wxSizer* sizer, NavigationButton navButton) {
	wxFlexGridSizer* grid = new wxFlexGridSizer(2, 1, 4, 16);
	AddChoiceProp(grid, wxT(""), wxT(""), wxArrayString());
	wxChoice* ctrl = (wxChoice*) m_controls[m_controls.Count()-1];
	
	// default navigation
	wxString defBtId = m_object->GetDefaultFocusDest(navButton);
	wxString text = _("none");
	if (defBtId.length()) {
		long l = -1;
		if (defBtId.Mid(6).ToLong(&l))
			text = _("button") + wxString::Format(wxT(" %d"), (int) l);
	}
	ctrl->Append(_("auto") + wxString(wxT(" (")) + text + wxT(")"), new wxString);

	// add all buttons except current
	int sel = 0;
	for (unsigned int i=0; i<m_menu->GetObjectsCount(); i++) {
		MenuObject* obj = m_menu->GetObject(i);
		if (obj->IsButton() && obj != m_object) {
			wxString id = obj->GetId();
			if (m_object->GetFocusDest(navButton) == id)
			sel = ctrl->GetCount();
			long l = -1;
			id.Mid(6).ToLong(&l);
			wxString text = _("button") + wxString::Format(wxT(" %d"), (int) l);
			if (obj->GetParam(wxT("text")).length())
				text += wxT(": ") + obj->GetParam(_T("text"));
			ctrl->Append(text, new wxString(id));
		}
	}
	for (unsigned int i=0; i<m_menu->GetActionsCount(); i++) {
		DVDAction* action = m_menu->GetAction(i);
		wxString id = action->GetId();
		if (m_object->GetFocusDest(navButton) == id)
			sel = ctrl->GetCount();
		ctrl->Append(id, new wxString(id));
	}
	ctrl->SetSelection(sel);
#ifdef __WXMSW__
	ctrl->SetSizeHints(ctrl->GetSize().GetWidth()*3/2, -1, ctrl->GetSize().GetWidth()*3/2, -1);
#endif
	sizer->Add(grid, 0, 0, 0);
}

bool MenuObjectPropDlg::SetValues() {
	// check Action
	if (m_object->IsButton() && !m_multObjects) {
		if (GetBool(4) && GetString(5).length() == 0) { // empty custom action
			wxMessageBox(_("Please enter the action command."),
			GetTitle(), wxOK|wxICON_ERROR, this);
			return false;
		}
		if (GetBool(4)) {
			DVDAction action(m_object->GetAction());
			action.SetCustom(GetString(5));
			if (!action.IsValid(m_dvd, m_tsi, m_pgci, true, m_object->GetId(), true, false)
					&& !s_config.GetAcceptInvalidActions())
				return false;
		}
	}

	int n = 0;

	// set action
	if (m_object->IsButton() && !m_multObjects) {
		DVDAction& action = m_object->GetAction();
		action.SetTsi(GetSelectedTsi() != m_tsi ? GetSelectedTsi() : -2);
		action.SetPgci(GetSelectedTsi() != m_tsi || GetSelectedPgci() != m_pgci || !IsSelectedMenu() ? GetSelectedPgci() : -1);
		action.SetMenu(IsSelectedMenu());
		if (GetSelectedTsi() != m_tsi && IsSelectedMenu() && GetSelectedPgci() > 0) {
			const StringSet& entries = m_dvd->GetPgcArray(GetSelectedTsi(), true)[GetSelectedPgci()]->GetEntries();
			action.SetEntry(entries.size() > 0 ? *entries.begin() : wxT(""));
		} else
			action.SetEntry(wxT(""));
		action.SetChapter(GetSelectedChapter());
		n += 3;
		action.SetPlayAll(GetBool(n++));
		if (GetBool(n++)) {
			if (GetString(n) == wxT("jump title 1;")) {
				action.SetTsi(-2);
				action.SetPgci(0);
				action.SetMenu(false);
				action.SetChapter(0);
				action.SetCustom(_T(""));
			} else
				action.SetCustom(GetString(n));
		} else
			action.SetCustom(_T(""));
		n++;
		action.SetAudio(GetInt(n++) - 1);
		action.SetSubtitle(GetInt(n++) - 1);

		wxString* id = (wxString*) GetClientData(n++);
		m_object->SetFocusDest(nbUP, *id);
		delete id;
		id = (wxString*) GetClientData(n++);
		m_object->SetFocusDest(nbLEFT, *id);
		delete id;
		id = (wxString*) GetClientData(n++);
		m_object->SetFocusDest(nbRIGHT, *id);
		delete id;
		id = (wxString*) GetClientData(n++);
		m_object->SetFocusDest(nbDOWN, *id);
		delete id;
	}

	// set look parameters
	for (int i = 0; i < m_object->GetObjectParamsCount(); i++) {
		MenuObjectParam* param = m_object->GetObjectParam(i);
		if (param->changeable && param->type == _T("colour")) {
			m_object->SetParamColour(param->name, GetColour(n++));
			m_object->SetParamColour(param->name, GetColour(n++), mbsHIGHLIGHTED);
			m_object->SetParamColour(param->name, GetColour(n++), mbsSELECTED);
		} else {
			if (param->type == _T("text")) {
				m_object->SetParam(param->name, GetString(n++));
				m_object->SetParamFont(param->name, GetFont(n++).GetChosenFont());
			} else if (param->type == _T("string") || param->type == _T("decimal"))
				m_object->SetParam(param->name, GetString(n++));
			else if (param->type.Mid(0, 7) == _T("integer"))
				m_object->SetParamInt(param->name, GetInt(n++));
			else if (param->type == _T("colour")) {
				m_object->SetParamColour(param->name, GetColour(n++));
				wxString opacity = wxString::Format(wxT("%g"), (double) GetInt(n++) / 100);
				m_object->SetParam(param->name, opacity, wxT("-opacity"));
			} else if (param->type == _T("image") && !m_multObjects) {
				if (m_object->IsButton()) {
					m_object->SetDisplayVideoFrame(m_displayVideoFrame);
					bool image = GetBool(n++); // image radio button
					wxString imgFile = GetString(n++);
					n++; // video radio button
					if (!image) {
						m_object->SetCustomVideoFrame(m_videoPos != m_defaultPos);
						m_object->SetParamImageVideo(param->name, GetVideoFilename(false), m_videoPos, m_videoDuration);
					} else
						m_object->SetParamImageVideo(param->name, imgFile, -1, -1);
				} else
					m_object->SetParam(param->name, GetString(n++));
			} else if (param->type == wxT("shadow")) {
				m_object->SetParam(param->name, GetBool(n++) ? wxT("visible") : wxT("hidden"), wxT("visibility"));
				m_object->SetParamColour(param->name, GetColour(n++));
				wxString opacity = wxString::Format(wxT("%g"), (double) GetInt(n++) / 100);
				m_object->SetParam(param->name, opacity, wxT("-opacity"));
				m_object->SetParamInt(param->name, GetInt(n++), wxT("x"));
				m_object->SetParamInt(param->name, GetInt(n++), wxT("y"));
				wxSVGElement* filter = m_object->GetElementById(param->element + wxT("Filter"));
				if (filter && ((wxSVGElement*)filter->GetFirstChild())->GetDtd() == wxSVG_FEGAUSSIANBLUR_ELEMENT) {
					wxSVGFEGaussianBlurElement* blur = (wxSVGFEGaussianBlurElement*) filter->GetFirstChild();
					blur->SetAttribute(wxT("stdDeviation"), GetString(n++));
				}
			}
		}
	}

	if (!m_multObjects) {
		// set position
		m_object->SetX(GetInt(n++));
		m_object->SetY(GetInt(n++));

		// set size
		m_object->SetDefaultSize(!GetBool(n++));
		if (!m_object->IsDefaultSize()) {
			m_object->SetWidth(GetInt(n++));
			m_object->SetHeight(GetInt(n++));
			m_object->SetKeepAspectRatio(GetBool(n++));
		}
	}
	m_object->UpdateSize();

	return true;
}
