/////////////////////////////////////////////////////////////////////////////
// Name:        DVDAction.h
// Purpose:     Stores a DVD Action
// Author:      Alex Thuering
// Created:     03.09.2009
// RCS-ID:      $Id: DVDAction.cpp,v 1.9 2010/01/12 20:43:46 ntalex Exp $
// Copyright:   (c) Alex Thuering
// Licence:     GPL
/////////////////////////////////////////////////////////////////////////////

#include "DVDAction.h"
#include "DVD.h"
#include <wxSVGXML/svgxmlhelpr.h>
#include <wx/sstream.h>

DVDAction::DVDAction(bool vmg, DVDActionType actionType, wxString id) {
	m_vmg = vmg;
	m_actionType = actionType;
	m_id = id;
	m_tsi = -2; // current titleset
	m_pgci = 1; // title 1
	m_chapter = 0; // chapter 1
	m_playAll = false;
	m_audio = -1;
	m_subtitle = -1;
}

wxString DVDAction::GetId(bool translate) {
	return m_id;
}

wxString DVDAction::AsString(DVD* dvd, bool translate) {
	wxString action;
	if (m_audio >= 0)
		action = translate ? wxString::Format(_("select audio track %d and "), m_audio + 1)
			: wxString::Format(wxT("audio=%d; "), m_audio);
	if (m_subtitle >= 0)
		action = translate ? wxString::Format(_("select subtitle track %d and "), m_subtitle + 1)
			: wxString::Format(wxT("subtitle=%d; "), m_subtitle > 0 ? m_subtitle + 63 : 0);
	if (m_custom.length()) // custom action selected
		return action + m_custom;
	// jump to selected
	action += translate ? _("jump to") : wxT("jump");
	action += wxT(" ");
	if (GetPgci() == -1) // jump to cell 1
		return action + (translate ? _("start of current menu") : wxT("cell 1;"));
	int tsi = GetTsi();
	bool menu = IsMenu();
	wxString entry = GetEntry();
	int pgci = GetPgci();
	if (tsi >= 0 && (!m_vmg || menu || translate)) { // don't use titleset for jumping to title from vmg
		action += translate ? _("titleset") : wxT("titleset");
		action += wxString::Format(wxT(" %d "), tsi + 1);
	}
	if (menu) {
		if (tsi == -1)
			action += translate ? _("vmMenu") : wxT("vmgm menu");
		else
			action += translate ? _("menu") : wxT("menu");
	} else
		action += translate ? _("title") : wxT("title");
	if (entry.length() > 0) {
		action += wxT(" entry ") + entry;
	} else if (!menu || pgci > 0 || tsi == -2 || translate) {
		int n = pgci + 1;
		if (m_vmg && !menu && !translate) // use sequence number of title for jumping to title from vmg
			for (int i = 0; i < tsi; i++)
				n += dvd->GetTitlesets()[i]->GetTitles().Count();
		action += wxString::Format(wxT(" %d"), n);
	}
	if (GetChapter() > 0 && (!m_vmg
			|| dvd->IsJumppadsEnabled())) { // cannot jump to chapter from vmg if jumppad disabled 
		action += wxT(" ");
		action += translate ? _("chapter") : wxT("chapter");
		action += wxString::Format(wxT(" %d"), GetChapter() + 1);
	}
	if (!translate)
		action += wxT(";");
	return action;
}

/** Returns true if action is valid */
bool DVDAction::IsValid(DVD* dvd, int tsi, int pgci, bool menu, wxString buttonId, bool showMessage) {
	if (IsCustom())
		return true; // TODO check custom action
	wxString msg;
	int actionTsi = GetTsi() != -2 ? GetTsi() : tsi;
	int actionPgci = GetPgci() != -1 ? GetPgci() : pgci;
	int actionMenu = IsMenu();
	int actionChapter = GetChapter();
	if (actionTsi >= (int) dvd->GetTitlesets().GetCount()) {
		msg = _("titleset") + wxString::Format(wxT(" %d "), actionTsi + 1) + _("does not exists");
	} else {
		PgcArray& actionPgcs = dvd->GetPgcArray(actionTsi, actionMenu);
		if (actionPgci >= (int) actionPgcs.GetCount()) {
			if (dvd->GetTitlesets().GetCount() > 1 || actionTsi > 0)
				msg = _("titleset") + wxString::Format(wxT(" %d "), actionTsi + 1);
			if (actionTsi == -1)
				msg = _("vmMenu") + wxString::Format(wxT(" %d "), actionPgci + 1) + _("does not exists");
			else if (actionMenu)
				msg += _("menu") + wxString::Format(wxT(" %d "), actionPgci + 1) + _("does not exists");
			else
				msg += _("title") + wxString::Format(wxT(" %d "), actionPgci + 1) + _("does not exists");
		} else if (!actionMenu && actionChapter >= (int)actionPgcs[actionPgci]->GetChapterCount()) {
			if (dvd->GetTitlesets().GetCount() > 1 || actionTsi > 0)
				msg = _("titleset") + wxString::Format(wxT(" %d "), actionTsi + 1);
			msg += _("title") + wxString::Format(wxT(" %d "), actionPgci + 1) + _("chapter")
				 + wxString::Format(wxT(" %d "), actionChapter + 1) + _("does not exists");
		}
	}
	if (msg.Length()) {
		wxString source;
		if (tsi >= 0) {
			if (dvd->GetTitlesets().GetCount() > 1)
				source = _("titleset") + wxString::Format(wxT(" %d "), tsi + 1);
			source += (menu ? _("menu") : _("title")) + wxString::Format(wxT(" %d"), pgci + 1);
		} else
			source = _("vmMenu") + wxString::Format(wxT(" %d"), pgci + 1);
		if (buttonId.Length())
			source += wxT(" ") + buttonId;
		if (showMessage)
			wxLogError(source + wxT(": ") + wxString(_("invalid action")) + wxT(" (") + msg + wxT(")"));
		return false;
	}
	return true;
}

wxSvgXmlNode* DVDAction::GetXML(DVDFileType type, DVD* dvd) {
	wxSvgXmlNode* rootNode = new wxSvgXmlNode(wxSVGXML_ELEMENT_NODE, wxT("action"));
	switch (type) {
	case DVDSTYLER_XML:
		if (m_actionType == MENU_ACTION)
			rootNode->AddProperty(wxT("id"), GetId());
		if (!GetCustom().length()) {
			if (GetTsi() > -2)
				rootNode->AddProperty(wxT("tsi"), wxString::Format(wxT("%d"), GetTsi()));
			if (GetPgci() > -1)
				rootNode->AddProperty(wxT("pgci"), wxString::Format(wxT("%d"), (GetPgci()*2 + (IsMenu() ? 0 : 1))));
			if (GetChapter() > 0)
				rootNode->AddProperty(wxT("chapter"), wxString::Format(wxT("%d"), GetChapter()));
			if (GetEntry().length() > 0)
				rootNode->AddProperty(wxT("entry"), GetEntry());
			if (IsPlayAll())
				rootNode->AddProperty(wxT("playAll"), wxT("true"));
			if (GetAudio() >= 0)
				rootNode->AddProperty(wxT("audio"), wxString::Format(wxT("%d"), GetAudio()));
			if (GetSubtitle() >= 0)
				rootNode->AddProperty(wxT("subtitle"), wxString::Format(wxT("%d"), GetSubtitle()));
		} else
			rootNode->AddChild(new wxSvgXmlNode(wxSVGXML_TEXT_NODE, wxEmptyString, GetCustom()));
		break;
	case SPUMUX_XML:
		rootNode->AddProperty(wxT("name"), GetId());
		break;
	case DVDAUTHOR_XML:
		rootNode->AddProperty(wxT("name"), GetId());
		rootNode->AddChild(new wxSvgXmlNode(wxSVGXML_TEXT_NODE, wxEmptyString, AsString(dvd)));
		break;
	default:
		break;
	}
	return rootNode;
}

bool DVDAction::PutXML(wxSvgXmlNode* node) {
	if (m_actionType == MENU_ACTION)
		node->GetPropVal(wxT("id"), &m_id);
	long lval;
	wxString val;
	if (node->GetPropVal(wxT("tsi"), &val) && val.ToLong(&lval))
		SetTsi(lval);
	if (node->GetPropVal(wxT("pgci"), &val) && val.ToLong(&lval)) {
		SetPgci(lval / 2);
		SetMenu(lval % 2 == 0);
	} else {
		SetPgci(-1);
		SetMenu(true);
	}
	if (node->GetPropVal(wxT("entry"), &val))
		SetEntry(val);
	if (node->GetPropVal(wxT("chapter"), &val) && val.ToLong(&lval))
		SetChapter(lval);
	if (node->GetPropVal(wxT("playAll"), &val))
		SetPlayAll(val == wxT("true"));
	if (node->GetPropVal(wxT("audio"), &val) && val.ToLong(&lval))
		SetAudio(lval);
	if (node->GetPropVal(wxT("subtitle"), &val) && val.ToLong(&lval))
		SetSubtitle(lval);
	if (node->GetChildren() && (node->GetChildren()->GetType() == wxSVGXML_TEXT_NODE
			|| node->GetChildren()->GetType() == wxSVGXML_CDATA_SECTION_NODE))
		SetCustom(node->GetChildren()->GetContent().Strip(wxString::both));
	return true;
}

/** Stores object data to string */
wxString DVDAction::Serialize() {
	wxSvgXmlDocument xml;
	xml.SetRoot(GetXML(DVDSTYLER_XML, NULL));
	wxStringOutputStream stream;
	xml.Save(stream);
	return stream.GetString();
}

/** Restores object from data */
void DVDAction::Deserialize(const wxString& data) {
	wxStringInputStream stream(data);
	wxSvgXmlDocument xml;
	xml.Load(stream);
	PutXML(xml.GetRoot());
}
