/////////////////////////////////////////////////////////////////////////////
// Name:        TitlesetManager.h
// Purpose:     Titleset Manager
// Author:      Alex Thuering
// Created:	27.01.2003
// RCS-ID:      $Id: TitlesetManager.cpp,v 1.13 2007/12/15 20:02:40 ntalex Exp $
// Copyright:   (c) Alex Thuering
// Licence:     GPL
/////////////////////////////////////////////////////////////////////////////

#include "TitlesetManager.h"
#include "TitlePropDlg.h"
#include "MenuPropDlg.h"
#include "MPEG.h"
#include "Config.h"
#include <wxVillaLib/ThumbnailFactory.h>
#include <wxVillaLib/ImageProc.h>
#include <wx/splitter.h>
#include <wx/dnd.h>
#include <wx/utils.h>

//////////////////////////////////////////////////////////////////////////////
///////////////////////////// TitleDnDFile ///////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

class TitleDnDFile : public wxFileDropTarget
{
  public:
    TitleDnDFile(TitlesetManager* pOwner): m_pOwner(pOwner) 
	{
	  SetDataObject(new wxFileDataObject);
#if wxCHECK_VERSION(2,6,0)
	  SetDefaultAction(wxDragMove);
#endif
	}
	
	virtual wxDragResult OnEnter(wxCoord x, wxCoord y, wxDragResult def)
	{
	  wxFileDropTarget::OnEnter(x, y, def);
	  return def;
	}
	
	virtual wxDragResult OnDragOver(wxCoord x, wxCoord y, wxDragResult def)
	{
	  defDrag = def; // wxWidgets bug 1100327 (wxGTK <= 2.6.0)
	  wxFileDropTarget::OnDragOver(x, y, def);
	  return def;
	}
	
	virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def)
	{
#if wxCHECK_VERSION(2,6,0)
	  defDrag = def;
#endif
	  wxFileDropTarget::OnData(x, y, def);
	  return def;
	}
	
	virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames)
	{
	  bool res = false;
	  for (int i = 0; i<(int)filenames.Count(); i++)
		res = AddFile(filenames[i], i == 0) || res;
	  return res;
	}
	
	bool AddFile(wxString filename, bool first)
	{
      wxString ext = filename.AfterLast('.').Lower();
	  if (wxImage::FindHandler(ext, -1))
      {
        m_pOwner->AddImage(filename, defDrag == wxDragMove && first);
		return true;
      }
	  else if (wxThumbnails::IsVideo(filename))
	  {
		if (!MPEG::IsValid(filename))
		{
		  wxLogError(filename + _(": not valid mpeg-file"));
		  return false;
		}
		m_pOwner->AddVideo(filename, defDrag == wxDragMove);
		return true;
	  }
	  else if (wxThumbnails::IsAudio(filename))
	  {
		m_pOwner->AddAudio(filename);
		return true;
	  }
      else if (ext == wxT("sub") ||
               ext == wxT("srt") ||
               ext == wxT("ssa") ||
               ext == wxT("smi") ||
               ext == wxT("rt") ||
               ext == wxT("txt") ||
               ext == wxT("aqt") ||
               ext == wxT("jss") ||
               ext == wxT("js") ||
               ext == wxT("ass"))
      {
        m_pOwner->AddSubtitles(filename);
		return true;
      }
      
	  wxLogError(filename + _(": unknown format"));
	  return false;
	}
	
  protected:
    TitlesetManager *m_pOwner;
	wxDragResult defDrag;
};

//////////////////////////////////////////////////////////////////////////////
/////////////////////////// TitlesetManager //////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

enum
{
  MENU_TITLE_DEL_ID = 2650,
  MENU_TITLE_PROP_ID,
  MENU_TITLE_ADD_ID,
  MENU_TITLE_MOVE_ID,
  MENU_MAIN_ADD_ID,
  MENU_ADD_MENU_ID,
  MENU_ADD_VMMENU_ID,
  MENU_ADD_TITLESET_ID,
  MENU_MOVE_TITLE_LEFT_ID,
  MENU_MOVE_TITLE_RIGHT_ID
};

BEGIN_EVENT_TABLE(TitlesetManager, wxThumbnails)
  EVT_MENU(MENU_ADD_MENU_ID, TitlesetManager::OnAddMenu)
  EVT_MENU(MENU_ADD_VMMENU_ID, TitlesetManager::OnAddVmMenu)
  EVT_MENU(MENU_ADD_TITLESET_ID, TitlesetManager::OnAddTitleset)
  EVT_UPDATE_UI(MENU_ADD_TITLESET_ID, TitlesetManager::OnAddTitlesetUpdateUI)
  EVT_MENU(MENU_MOVE_TITLE_LEFT_ID, TitlesetManager::OnMoveTitleLeft)
  EVT_MENU(MENU_MOVE_TITLE_RIGHT_ID, TitlesetManager::OnMoveTitleRight)
  EVT_UPDATE_UI(MENU_MOVE_TITLE_LEFT_ID, TitlesetManager::OnMoveTitleLeftUpdateUI)
  EVT_UPDATE_UI(MENU_MOVE_TITLE_RIGHT_ID, TitlesetManager::OnMoveTitleRightUpdateUI)
  EVT_MENU(MENU_TITLE_DEL_ID, TitlesetManager::OnDelete)
  EVT_MENU(MENU_TITLE_PROP_ID, TitlesetManager::OnProps)
END_EVENT_TABLE()

DEFINE_EVENT_TYPE(EVT_COMMAND_MENU_SELECTED)
DEFINE_EVENT_TYPE(EVT_COMMAND_DVD_CHANGED)

TitlesetManager::TitlesetManager(wxWindow* parent, int id):
  wxThumbnails(parent, id)
{
  SetThumbSize(112, 76);
  SetOrientaion(wxTHUMB_HORIZONTAL);
  SetDropTarget(new TitleDnDFile(this));
  EnableDragging(false);
  m_dvd = NULL;
  m_selectedMenu = -1;
  
  wxMenu* addMenu = new wxMenu;
  addMenu->Append(MENU_ADD_MENU_ID, _("&Menu"));
  addMenu->Append(MENU_ADD_VMMENU_ID, _("&vmMenu"));
  addMenu->Append(MENU_ADD_TITLESET_ID, _("&Titleset"));
  
  wxMenu* moveMenu = new wxMenu;
  moveMenu->Append(MENU_MOVE_TITLE_LEFT_ID, _("&Left"));
  moveMenu->Append(MENU_MOVE_TITLE_RIGHT_ID, _("&Right"));
  
  m_mainMenu = new wxMenu;
  m_mainMenu->Append(MENU_MAIN_ADD_ID, _("&Add"), addMenu);
  
  m_titleMenu = new wxMenu;
  m_titleMenu->Append(MENU_TITLE_ADD_ID, _("&Add"), addMenu);
  m_titleMenu->Append(MENU_TITLE_MOVE_ID, _("&Move"), moveMenu);
  m_titleMenu->Append(MENU_TITLE_DEL_ID, _("&Delete"));
  m_titleMenu->Append(MENU_TITLE_PROP_ID, _("&Properties..."));
  
  SetPopupMenu(m_titleMenu);
  SetGlobalPopupMenu(m_mainMenu);
}

TitlesetManager::~TitlesetManager()
{
}

void TitlesetManager::SetDVD(DVD* dvd)
{
  m_dvd = dvd;
  SetSelected(-1);
  m_selectedMenu = 0;
  UpdateItems();
}

void TitlesetManager::DrawThumbnail(wxBitmap& bmp, wxThumb& thumb, int index)
{
  if (!m_dvd)
	return;
  int id = thumb.GetId();
  int tsi = DVD::GetTsi(id);
  int pgci = DVD::GetPgci(id);
  int vobi = DVD::GetVobi(id);
  bool isMenu = DVD::IsMenu(id);
  Vob* vob = m_dvd->GetVob(tsi, isMenu, pgci, vobi);
  
  wxMemoryDC dc;
  dc.SelectObject(bmp);
  int x = m_tBorder/2;
  int y = m_tBorder/2;
  int tw = bmp.GetWidth() - m_tBorder + 2;
  int th = bmp.GetHeight() - m_tBorder + 2;
  int titleHeight = m_tTextHeight + 2;
  // background
  dc.SetPen(wxPen(*wxBLACK,0,wxTRANSPARENT));
  dc.SetBrush(wxBrush(GetBackgroundColour(), wxSOLID));
  dc.DrawRectangle(0, 0, bmp.GetWidth(), bmp.GetHeight());
  // rounded rectangle
  wxColour rectColour = isMenu ? wxColour(64,64,64) : wxColour(0,0,0);
  dc.SetBrush(wxBrush(rectColour, wxSOLID));
  dc.DrawRoundedRectangle(x, y, tw, th, 20);
  // draw begin & end of titleset
  if (IsBeginOfTitleset(tsi, pgci, vobi, isMenu))
  {
	int h = bmp.GetHeight();
	dc.SetPen(wxPen(*wxRED,0,wxSOLID));
	dc.DrawLine(1, 1, 10, 1);
	dc.DrawLine(1, 1, 1, 10);
	dc.DrawLine(1, h-2, 10, h-2);
	dc.DrawLine(1, h-2, 1, h-11);
  }
  if (IsEndOfTitleset(tsi, pgci, vobi, isMenu))
  {
	int h = bmp.GetHeight();
	int w = bmp.GetWidth();
	dc.SetPen(wxPen(*wxRED,0,wxSOLID));
	dc.DrawLine(w-1, 1, w-10, 1);
	dc.DrawLine(w-1, 1, w-1, 10);
	dc.DrawLine(w-1, h-2, w-10, h-2);
	dc.DrawLine(w-1, h-2, w-1, h-11);
  }
  // image
  wxBitmap img;
  if (vob->GetMenu())
  {
	if (!thumb.GetBitmap().Ok())
	{
      img = wxBitmap(vob->GetMenu()->GetImage(m_tWidth, m_tHeight-titleHeight));
      thumb.SetBitmap(img);
	}
    else
      img = thumb.GetBitmap();
  }
  else if (vob->GetSlideshow())
  {
	if (!thumb.GetBitmap().Ok())
	{
      img = wxBitmap(vob->GetSlideshow()->GetThumbImage(m_tWidth, m_tHeight-titleHeight));
      thumb.SetBitmap(img);
	}
    else
      img = thumb.GetBitmap();
  }
  else
    img = thumb.GetBitmap(this, m_tWidth, m_tHeight-titleHeight);
  if (index == m_pointed)
  {
    wxImage imgTmp = img.ConvertToImage();
    wxAdjustBrightness(imgTmp, wxRect(0,0,img.GetWidth(),img.GetHeight()),
      POINTED_BRIGHTNESS);
    img = wxBitmap(imgTmp);
  }
  wxRect imgRect(x + (m_tWidth-img.GetWidth())/2,
	y + titleHeight + (m_tHeight-titleHeight-img.GetHeight())/2,
    img.GetWidth(), img.GetHeight());      
  dc.DrawBitmap(img, imgRect.x, imgRect.y);
  // outline
  if (index == m_selectedMenu)
  {
	dc.SetPen(wxPen(*wxBLUE,0,wxSOLID));
	dc.SetBrush(wxBrush(*wxBLACK, wxTRANSPARENT));
	dc.DrawRectangle(imgRect.x-1, imgRect.y-1, imgRect.width+1, imgRect.height+1);
  }
  // draw title caption
  dc.SetTextForeground(*wxWHITE);
  wxString caption;
  if (isMenu && tsi<0)
	caption = _("vmMenu");
  else if (isMenu)
	caption = _("Menu");
  else
	caption = _("Title");
  caption += wxString::Format(_T(" %d"), pgci+1);
  if (vobi>0)
	caption += wxString::Format(_T("-%d"), vobi+1);
  int sw, sh;
  dc.GetTextExtent(caption, &sw, &sh);
  int tx = x + (m_tWidth-sw)/2;
  int ty = y + (titleHeight-sh)/2;
  dc.DrawText(caption, tx, ty);
  // draw caption
  for (int i=0; i<thumb.GetCaptionLinesCount(m_tWidth-m_tCaptionBorder); i++)
  {
	wxString caption = thumb.GetCaption(i);
	dc.GetTextExtent(caption, &sw, &sh);
	tx = x + (m_tWidth-sw)/2;
	ty = y + m_tHeight + i*m_tTextHeight + (m_tTextHeight-sh)/2;
	dc.DrawText(caption, tx, ty);
  }
  
  dc.SelectObject(wxNullBitmap);
}

int TitlesetManager::GetCaptionHeight(int begRow, int count)
{
  int capHeight = 0;
  for (int i=begRow; i<begRow+count; i++)
	if (i < (int) m_tCaptionHeight.GetCount())
	capHeight += m_tCaptionHeight[i]>0? m_tCaptionHeight[i] : 1;
  return capHeight*m_tTextHeight; 
}

void TitlesetManager::UpdateItems()
{
  wxThumbnailFactory::ClearQueue(this);
  
  int selectedMenuId = -1; // to update m_selectedMenu
  if (m_selectedMenu>=0 && m_selectedMenu<(int)m_items.Count())
	selectedMenuId = m_items[m_selectedMenu]->GetId();
  WX_CLEAR_ARRAY(m_items)
  Menus* menus = &m_dvd->GetVmgm();
  for (int pgci = 0; pgci<(int)menus->Count(); pgci++)
  {
	Pgc* pgc = (*menus)[pgci];
	if (!pgc->GetVobs().Count())
	  continue;
	wxThumb* thumb = new wxThumb(_T(""));
	thumb->SetId(DVD::MakeId(-1, pgci, 0, true));
	m_items.Add(thumb);
  }
  for (int tsi = 0; tsi<(int)m_dvd->GetTitlesets().Count(); tsi++)
  {
	Titleset* ts = m_dvd->GetTitlesets()[tsi];
	menus = &ts->GetMenus();
	for (int pgci = 0; pgci<(int)menus->Count(); pgci++)
	{
	  Pgc* pgc = (*menus)[pgci];
	  if (!pgc->GetVobs().Count())
		continue;
	  wxThumb* thumb = new wxThumb(_T(""));
	  thumb->SetId(DVD::MakeId(tsi, pgci, 0, true));
	  m_items.Add(thumb);
	}
	for (int pgci = 0; pgci<(int)ts->GetTitles().Count(); pgci++)
	{
	  Pgc* pgc = ts->GetTitles()[pgci];
	  for (int vobi = 0; vobi<(int)pgc->GetVobs().Count(); vobi++)
	  {
		Vob* vob = pgc->GetVobs()[vobi];
        wxString fname;
        wxString caption;
        if (vob->GetSlideshow())
        {
          if (vob->GetSlideshow()->Count() > 1)
            caption = wxString::Format(_("Slideshow (%d images)"),
              vob->GetSlideshow()->Count());
          else
            caption = _("Slideshow (1 image)");
        }
        else
        {
          fname = vob->GetFilename();
          if (!fname.length())
            fname = vob->GetVideoFilename();
          caption = fname.AfterLast(wxFILE_SEP_PATH).BeforeLast('.');
        }
        wxThumb* thumb = new wxThumb(fname, caption);
		thumb->SetId(DVD::MakeId(tsi, pgci, vobi, false));
		m_items.Add(thumb);
	  }
	}
  }
  if (selectedMenuId>=0) // update m_selectedMenu
	m_selectedMenu = GetIndex(selectedMenuId);
  UpdateProp();
  Refresh();
  ((wxSplitterWindow*)GetParent())->SetSashPosition(
	((wxSplitterWindow*)GetParent())->GetSashPosition()+(m_rows>1?0:1000));
}

int TitlesetManager::GetIndex(int tsi, int pgci, int vobi, bool menu)
{
  return GetIndex(DVD::MakeId(tsi, pgci, vobi, menu));
}

int TitlesetManager::GetIndex(int id)
{
  for (int i=0; i<(int)m_items.Count(); i++)
  {
	//wxMessageBox(wxString::Format(_T("find %d ? %d"), id, m_items[i]->GetId()));
	if (m_items[i]->GetId() == id)
	  return i;
  }
  return -1;
}

bool TitlesetManager::AddVideo(const wxString& fname, bool createTitle)
{
  if (m_dvd->GetTitlesets().Count() == 0)
    m_dvd->GetTitlesets().Add(new Titleset);
  
  PgcArray& pgcs = m_dvd->GetTitlesets().Last()->GetTitles();
  Pgc* pgc = pgcs.Count()>0 ? pgcs.Last() : NULL;
  Vob* vob = pgc && pgc->GetVobs().Count()>0 ? pgc->GetVobs().Last() : NULL;
  if (vob && vob->GetVideoFilename().length() &&
            !vob->GetAudioFilenames().Count())
  {
    wxLogError(wxString(_("The last title isn't complete.\n")) +
                        _("Please add an audio track to it."));
    return false;
  }
    
  vob = new Vob(_T(""));
  if (wxThumbnails::IsAudioVideo(fname)) // audio+video
    vob->SetFilename(fname);
  else // video
    vob->SetVideoFilename(fname);
  int n = 10;
  if (vob->GetDuration() > 0) {
    int duration = (int) vob->GetDuration() / 60;
  	n = duration / s_config.GetDefChapterLength();
  	if (n > 0 && duration - s_config.GetDefChapterLength()*n < s_config.GetDefChapterLength()/5)
  	  n--;
  }
  if (n>100)
    n = 100;
  int t = s_config.GetDefChapterLength();
  wxString cStr;
  for (int i = 0; i < n; i++)
  {
    if (cStr.length())
      cStr += wxT(",");
    if (t >= 60)
      cStr += wxString::Format(wxT("%d:%02d:00"), t/60, t%60);
    else
      cStr += wxString::Format(wxT("%02d:00"), t%60);
    t += s_config.GetDefChapterLength();
  }
  vob->SetChapters(cStr);
  if (createTitle || pgc == NULL)
  {
    pgc = new Pgc;
    pgc->SetPostCommands(_T("call vmgm menu 1;"));
    pgc->GetVobs().Add(vob);
    pgcs.Add(pgc);
  }
  else
    pgc->GetVobs().Add(vob);
  
  UpdateItems();
  SendDvdChangedEvent();
  return true;
}

bool TitlesetManager::AddAudio(const wxString& fname)
{
  if (m_dvd->GetTitlesets().Count() == 0)
    m_dvd->GetTitlesets().Add(new Titleset);
  
  PgcArray& pgcs = m_dvd->GetTitlesets().Last()->GetTitles();
  if (pgcs.Count()==0 || pgcs.Last()->GetVobs().Count()==0)
  {
    wxLogError(_("Please add a video track first."));
    return false;
  }
  Vob* vob = pgcs.Last()->GetVobs().Last();
  vob->GetAudioFilenames().Add(fname);
  UpdateItems();
  SendDvdChangedEvent();
  return true;
}

bool TitlesetManager::AddSubtitles(const wxString& fname)
{
  if (m_dvd->GetTitlesets().Count() == 0)
    m_dvd->GetTitlesets().Add(new Titleset);
  
  PgcArray& pgcs = m_dvd->GetTitlesets().Last()->GetTitles();
  if (pgcs.Count()==0 || pgcs.Last()->GetVobs().Count()==0)
  {
    wxLogError(_("Please add a video track first."));
    return false;
  }
  Vob* vob = pgcs.Last()->GetVobs().Last();
  vob->GetSubtitles().Add(new TextSub(fname));
  UpdateItems();
  SendDvdChangedEvent();
  return true;
}

void TitlesetManager::AddImage(const wxString& fname, bool createTitle)
{
  if (m_dvd->GetTitlesets().Count() == 0)
    m_dvd->GetTitlesets().Add(new Titleset);
  
  PgcArray& pgcs = m_dvd->GetTitlesets().Last()->GetTitles();
  Pgc* pgc = pgcs.Count()>0 ? pgcs.Last() : NULL;
  
  if (createTitle || pgc == NULL)
  {
    pgc = new Pgc;
    pgc->SetPostCommands(_T("call vmgm menu 1;"));
    pgcs.Add(pgc);
  }
  
  Slideshow* slideshow = pgc->GetSlideshow();
  if (slideshow == NULL)
  {
    slideshow = new Slideshow;
    Vob* vob = new Vob(slideshow);
    pgc->GetVobs().Add(vob);
  }
  slideshow->Add(new Slide(fname));
  
  UpdateItems();
  SendDvdChangedEvent();
}

void TitlesetManager::SelectMenu(int tsi, int pgci)
{
  m_selectedMenu = GetIndex(tsi, pgci, 0, true);
  SendMenuSelectedEvent();
}

void TitlesetManager::SelectFirstMenu()
{
  m_selectedMenu = -1;
  for (int tsi=-1; tsi<(int)m_dvd->GetTitlesets().Count(); tsi++)
  {
	if (m_dvd->GetMenu(tsi, 0))
	{
	  m_selectedMenu = GetIndex(tsi, 0, 0, true);
	  break;
	}
  }
  SendMenuSelectedEvent();
}

bool TitlesetManager::IsBeginOfTitleset(int tsi, int pgci, int vobi, bool isMenu)
{
  if (tsi<0 || (m_dvd->GetTitlesets().Count()<=1 && m_dvd->GetVmgm().Count()==0))
	return false;
  return pgci == 0 && vobi == 0 &&
	(isMenu || m_dvd->GetTitlesets()[tsi]->GetMenus().Count() == 0);
}

bool TitlesetManager::IsEndOfTitleset(int tsi, int pgci, int vobi, bool isMenu)
{
  if (tsi<0 || m_dvd->GetTitlesets().Count() < 2 ||
	  tsi == (int)m_dvd->GetTitlesets().Count()-1)
	return false;
  Titleset* ts = m_dvd->GetTitlesets()[tsi];
  return (isMenu &&
		  ts->GetTitles().Count() == 0 &&
		  pgci == (int)ts->GetMenus().Count()-1 &&
		  vobi == (int)ts->GetMenus()[pgci]->GetVobs().Count()-1) ||
		 (!isMenu &&
		  pgci == (int)ts->GetTitles().Count()-1 &&
		  vobi == (int)ts->GetTitles()[pgci]->GetVobs().Count()-1);
}

void TitlesetManager::SendMenuSelectedEvent()
{
  wxCommandEvent evt(EVT_COMMAND_MENU_SELECTED, this->GetId());
  GetEventHandler()->ProcessEvent(evt);
}

void TitlesetManager::SendDvdChangedEvent()
{
  wxCommandEvent evt(EVT_COMMAND_DVD_CHANGED, this->GetId());
  GetEventHandler()->ProcessEvent(evt);
}

void TitlesetManager::OnMouseDown(wxMouseEvent& event)
{
  wxThumbnails::OnMouseDown(event);
  // Popup menu
  if (event.RightDown())
	return;
  // select menu
  if (GetSelected()<0)
	return;
  int id = GetSelectedId();
  if (DVD::IsMenu(id))
	SelectMenu(DVD::GetTsi(id), DVD::GetPgci(id));
}

void TitlesetManager::OnMouseDClick(wxMouseEvent& WXUNUSED(event))
{
  wxCommandEvent evt;
  OnProps(evt);
}

void TitlesetManager::AddMenu()
{
  int tsi = m_dvd->GetTitlesets().Count()-1;
  if (GetSelected()>=0)
	tsi = DVD::GetTsi(GetSelectedId());
  int pgci = m_dvd->AddMenu(m_dvd->GetVideoFormat(), tsi);
  UpdateItems();
  SelectMenu(tsi, pgci);
  SendDvdChangedEvent();
}

void TitlesetManager::AddVmMenu()
{
  int tsi = -1;
  int pgci = m_dvd->AddMenu(m_dvd->GetVideoFormat(), tsi);
  UpdateItems();
  SelectMenu(tsi, pgci);
  SendDvdChangedEvent();
}

void TitlesetManager::AddTitleset()
{
  m_dvd->AddTitleset();
  AddMenu();
}

void TitlesetManager::OnAddTitlesetUpdateUI(wxUpdateUIEvent& event)
{
  int cnt = m_dvd->GetTitlesets().Count();
  event.Enable(cnt>0 &&	m_dvd->GetTitlesets()[cnt-1]->GetTitles().Count());
}

void TitlesetManager::OnMoveTitleLeft(wxCommandEvent& WXUNUSED(event))
{
  if (GetSelected()<0)
	return;
  int id = GetSelectedId();
  int tsi = DVD::GetTsi(id);
  int pgci = DVD::GetPgci(id);
  bool isMenu = DVD::IsMenu(id);
  PgcArray& pgcs = m_dvd->GetPgcArray(tsi,isMenu);
  if (pgci == 0)
	return;
  Pgc* pgc = pgcs[pgci]; pgcs[pgci] = pgcs[pgci-1]; pgcs[pgci-1] = pgc;
  if (isMenu)
	SelectMenu(tsi, pgci-1);
  UpdateItems();
  SendDvdChangedEvent();
}

void TitlesetManager::OnMoveTitleRight(wxCommandEvent& WXUNUSED(event))
{
  if (GetSelected()<0)
	return;
  int id = GetSelectedId();
  int tsi = DVD::GetTsi(id);
  int pgci = DVD::GetPgci(id);
  bool isMenu = DVD::IsMenu(id);
  PgcArray& pgcs = m_dvd->GetPgcArray(tsi,isMenu);
  if (pgci == (int)pgcs.Count()-1)
	return;
  Pgc* pgc = pgcs[pgci]; pgcs[pgci] = pgcs[pgci+1]; pgcs[pgci+1] = pgc;
  if (isMenu)
	SelectMenu(tsi, pgci+1);
  UpdateItems();
  SendDvdChangedEvent();
}

void TitlesetManager::OnMoveTitleLeftUpdateUI(wxUpdateUIEvent& event)
{
  if (GetSelected()<0)
	return;
  int id = GetSelectedId();
  int pgci = DVD::GetPgci(id);
  event.Enable(pgci>0);
}

void TitlesetManager::OnMoveTitleRightUpdateUI(wxUpdateUIEvent& event)
{
  if (GetSelected()<0)
	return;
  int id = GetSelectedId();
  int tsi = DVD::GetTsi(id);
  int pgci = DVD::GetPgci(id);
  bool isMenu = DVD::IsMenu(id);
  PgcArray& pgcs = m_dvd->GetPgcArray(tsi,isMenu);
  event.Enable(pgci<(int)pgcs.Count()-1);
}

void TitlesetManager::OnDelete(wxCommandEvent& WXUNUSED(event))
{
  if (GetSelected()<0)
	return;
  int id = GetSelectedId();
  int tsi = DVD::GetTsi(id);
  int pgci = DVD::GetPgci(id);
  bool isMenu = DVD::IsMenu(id);
  int vobi = DVD::GetVobi(id);
  if (isMenu)
  {
	Titleset* ts = NULL;
	if (tsi>=0)
	  ts = m_dvd->GetTitlesets()[tsi];
	Menus* menus = &m_dvd->GetVmgm();
	if (ts)
	  menus = &ts->GetMenus();
	if (pgci>=(int)menus->GetCount())
	  return;
	Pgc* pgc = (*menus)[pgci];
	if (vobi>=(int)pgc->GetVobs().Count())
	  return;
	delete pgc->GetVobs()[vobi];
	pgc->GetVobs().RemoveAt(vobi);
	// remove pgc if need
	if (pgc->GetVobs().Count() == 0)
	{
	  delete pgc;
	  menus->RemoveAt(pgci);
	}
	// remove titleset if need
	if (ts &&
		ts->GetTitles().Count() == 0 &&
		ts->GetMenus().Count() == 0 &&
		m_dvd->GetTitlesets().Count() > 1)
	{
	  delete ts;
	  m_dvd->GetTitlesets().RemoveAt(tsi);
	}
	// select next menu
	if (GetSelected() == m_selectedMenu)
	{
		if (pgci >= (int)menus->Count())
		  pgci = menus->Count()-1;
		if (pgci>=0)
		  SelectMenu(tsi, pgci);
		else
		  SelectFirstMenu();
	}
	else if (m_selectedMenu>=0)
	{
	  wxThumb* mThumb = m_items[m_selectedMenu];
	  int mTsi = (mThumb->GetId()>>24)-1;
	  int mPgci = ((mThumb->GetId()>>8) & 0xFFFF) / 2;
	  if (mTsi == tsi && mPgci > pgci)
		m_selectedMenu--;
	}
  }
  else // title
  {
	if (tsi>=(int)m_dvd->GetTitlesets().Count())
	  return;
	Titleset* ts = m_dvd->GetTitlesets()[tsi];
	
	//title
	if (pgci>=(int)ts->GetTitles().GetCount())
	  return;
	Pgc* pgc = ts->GetTitles()[pgci];
	if (vobi>=(int)pgc->GetVobs().Count())
	  return;
	// remove vob
	delete pgc->GetVobs()[vobi];
	pgc->GetVobs().RemoveAt(vobi);
	// remove title if need
	if (pgc->GetVobs().Count() == 0)
	{
	  delete pgc;
	  ts->GetTitles().RemoveAt(pgci);
	}
	// remove titleset if need
	if (ts->GetTitles().Count() == 0 &&
		ts->GetMenus().Count() == 0 &&
		m_dvd->GetTitlesets().Count() > 1)
	{
	  delete ts;
	  m_dvd->GetTitlesets().RemoveAt(tsi);
	}
  }
  SetSelected(-1);
  UpdateItems();
  SendDvdChangedEvent();
}

void TitlesetManager::OnProps(wxCommandEvent& WXUNUSED(event))
{
  if (GetSelected()<0)
	return;
  int id = GetSelectedId();
  int tsi = DVD::GetTsi(id);
  int pgci = DVD::GetPgci(id);
  bool isMenu = DVD::IsMenu(id);
  int vobi = DVD::GetVobi(id);
  if (isMenu)
  {
	MenuPropDlg propDlg(this->GetParent(), m_dvd, tsi, pgci);
	if (propDlg.ShowModal() == wxID_OK)
    {
      SendMenuSelectedEvent(); // updated MenuEditor
	  SendDvdChangedEvent();
    }
  }
  else //title
  {
	PgcArray& pgcs = m_dvd->GetPgcArray(tsi, false);
	Pgc* pgc = pgcs[pgci];
	TitlePropDlg propDlg(this->GetParent(), m_dvd, &pgcs.GetAudio(), &pgcs.GetVideo(),
	  pgc, pgc->GetVobs()[vobi]);
	if (propDlg.ShowModal() == wxID_OK)
	  SendDvdChangedEvent();
  }
}
