/////////////////////////////////////////////////////////////////////////////
// Name:        ChaptersDlg.cpp
// Purpose:     The chapters dialog
// Author:      Alex Thuering
// Created:     19.04.2010
// RCS-ID:      $Id: ChaptersDlg.cpp,v 1.3 2011/10/03 08:52:15 ntalex Exp $
// Copyright:   (c) Alex Thuering
// Licence:     GPL
/////////////////////////////////////////////////////////////////////////////

#include "ChaptersDlg.h"
#include "CellPropDlg.h"
#include "Utils.h"
#include "Config.h"
#include <wx/regex.h>
#include <wx/imaglist.h>
#include <wxVillaLib/utils.h>
#include "rc/add.png.h"
#include "rc/remove.png.h"
#include "rc/preferences.png.h"

// begin wxGlade: ::extracode

// end wxGlade

enum {
	CHAPTERS_CTRL_ID = 2000,
	ADD_BT_ID,
	DEL_BT_ID,
	PROP_BT_ID,
	SLIDER_ID,
	TIME_CTRL_ID,
	TIME_SPIN_BT_ID,
	UNSELECT_TIMER_ID
};

BEGIN_EVENT_TABLE(ChaptersDlg, wxDialog)
    // begin wxGlade: ChaptersDlg::event_table
    EVT_BUTTON(ADD_BT_ID, ChaptersDlg::OnAddBt)
    EVT_BUTTON(DEL_BT_ID, ChaptersDlg::OnDelBt)
    EVT_BUTTON(PROP_BT_ID, ChaptersDlg::OnPropBt)
    EVT_COMMAND_SCROLL(SLIDER_ID, ChaptersDlg::OnSliderScroll)
    EVT_TEXT(TIME_CTRL_ID, ChaptersDlg::OnChangeTime)
    EVT_SPIN(TIME_SPIN_BT_ID, ChaptersDlg::OnTimeSpin)
    EVT_BUTTON(wxID_OK, ChaptersDlg::OnOkBt)
    // end wxGlade
    EVT_LIST_ITEM_SELECTED(CHAPTERS_CTRL_ID, ChaptersDlg::OnChapterSelect)
    EVT_LIST_ITEM_DESELECTED(CHAPTERS_CTRL_ID, ChaptersDlg::OnChapterSelect)
    EVT_LIST_ITEM_ACTIVATED(CHAPTERS_CTRL_ID, ChaptersDlg::OnChapterDClick)
    EVT_TIMER(UNSELECT_TIMER_ID, ChaptersDlg::OnUnselectTimer)
END_EVENT_TABLE();

class ChaptersCtrl: public wxListCtrl {
public:
	ChaptersCtrl(wxWindow *parent, wxWindowID id, vector<Cell*>& cells): wxListCtrl(parent, id, wxDefaultPosition, wxDefaultSize,
			wxLC_VIRTUAL|wxLC_REPORT|wxLC_NO_HEADER|wxLC_SORT_ASCENDING|wxSUNKEN_BORDER), m_cells(cells) {
		attrSelected = new wxListItemAttr();
		wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
		font.SetWeight(wxFONTWEIGHT_BOLD);
		attrSelected->SetFont(font);
		SetItemCount(cells.size());
	}
	wxString OnGetItemText(long item, long column) const {
		return Time2String(m_cells[item]->GetStart(), true);
	}
	int OnGetItemImage(long item) const {
		return !m_cells[item]->IsChapter() || m_cells[item]->GetEnd() >= 0 || m_cells[item]->GetPause() != 0
				 || m_cells[item]->GetCommands().length() > 0 ? 0 : -1;
	}
	wxListItemAttr* OnGetItemAttr(long item) const {
		wxListItemAttr* attr = wxListCtrl::OnGetItemAttr(item);
		return GetItemState(item, wxLIST_STATE_SELECTED) ? attrSelected : attr;
	}
private:
	vector<Cell*>& m_cells;
	wxListItemAttr* attrSelected;
};

ChaptersDlg::ChaptersDlg(wxWindow* parent, DVD* dvd, int tsi, int pgci, Vob* vob):
		wxDialog(parent, -1, wxT(""), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
		m_unselectTimer(this, UNSELECT_TIMER_ID) {
	m_dvd = dvd;
	m_tsi = tsi;
	m_pgci = pgci;
	m_vob = vob;
	VECTOR_COPY(m_vob->GetCells(), m_cells, Cell);
	m_selected = -1;
	
    // begin wxGlade: ChaptersDlg::ChaptersDlg
    m_chaptersLabel = new wxStaticText(this, wxID_ANY, _("Chapters:"));
    m_chaptersCtrl = new ChaptersCtrl(this, CHAPTERS_CTRL_ID, m_cells);
    m_addBt = new wxBitmapButton(this, ADD_BT_ID, wxNullBitmap);
    m_delBt = new wxBitmapButton(this, DEL_BT_ID, wxNullBitmap);
    m_propBt = new wxBitmapButton(this, PROP_BT_ID, wxNullBitmap);
    m_mediaCtrl = new MediaCtrlFF(this, wxID_ANY);
    m_slider = new wxSlider(this, SLIDER_ID, 0, 0, 10, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL|wxSL_TOP);
    m_timeLabel = new wxStaticText(this, wxID_ANY, _("Time:"));
    m_timeCtrl = new wxTextCtrl(this, TIME_CTRL_ID, wxEmptyString);
    m_timeSpinBt = new wxSpinButton(this, TIME_SPIN_BT_ID, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS);
    m_durLabel = new wxStaticText(this, wxID_ANY, _("Duration:"));
    m_durText = new wxStaticText(this, wxID_ANY, wxEmptyString);
    m_okBt = new wxButton(this, wxID_OK, _("OK"));
    m_cancelBt = new wxButton(this, wxID_CANCEL, _("Cancel"));

    set_properties();
    do_layout();
    // end wxGlade
    
    SetIcon(((wxTopLevelWindow*)wxGetTopLevelParent(parent))->GetIcon());
    m_chaptersCtrl->SetFocus();
}

ChaptersDlg::~ChaptersDlg() {
	VECTOR_CLEAR(m_cells, Cell);
}

void ChaptersDlg::set_properties() {
    // begin wxGlade: ChaptersDlg::set_properties
    SetTitle(_("Chapters"));
    m_chaptersCtrl->SetMinSize(wxSize(100, -1));
    m_addBt->SetSize(m_addBt->GetBestSize());
    m_delBt->SetSize(m_delBt->GetBestSize());
    m_propBt->SetSize(m_propBt->GetBestSize());
    m_mediaCtrl->SetMinSize(wxSize(300, 200));
    m_mediaCtrl->SetWindowStyle(wxBORDER_NONE);
    m_timeSpinBt->SetMinSize(wxSize(16, -1));
    m_okBt->SetDefault();
    // end wxGlade
    
    int x = 0;
    m_chaptersCtrl->GetTextExtent(wxT("00:00:00.000"), &x, NULL);
    m_chaptersCtrl->SetMinSize(wxSize(x + 40, -1));
    m_timeCtrl->GetTextExtent(wxT("00:00:00.000"), &x, NULL);
    m_timeCtrl->SetMinSize(wxSize(x + 10, -1));
    m_durText->GetTextExtent(wxT("00:00:00.000"), &x, NULL);
    m_durText->SetMinSize(wxSize(x + 10, -1));
    
    m_addBt->SetBitmapLabel(wxBITMAP_FROM_MEMORY(add));
    m_delBt->SetBitmapLabel(wxBITMAP_FROM_MEMORY(remove));
    m_propBt->SetBitmapLabel(wxBITMAP_FROM_MEMORY(preferences));
    wxImageList* imageListSmall = new wxImageList(16, 16, true);
    imageListSmall->Add(wxBITMAP_FROM_MEMORY(preferences));
    m_chaptersCtrl->SetImageList(imageListSmall, wxIMAGE_LIST_SMALL);
    wxListItem itemCol;
	itemCol.SetText(wxT("Start Time"));
	m_chaptersCtrl->InsertColumn(0, itemCol);
	m_chaptersCtrl->SetColumnWidth(0, m_chaptersCtrl->GetMinWidth() - 8);
}

void ChaptersDlg::do_layout() {
    // begin wxGlade: ChaptersDlg::do_layout
    wxBoxSizer* mainVSizer = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer* mainHSizer = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer* mediaSizer = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer* timeSizer = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer* chaptersVSizer = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer* chaptersHSizer = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer* chaptersButtonsSizer = new wxBoxSizer(wxVERTICAL);
    chaptersVSizer->Add(m_chaptersLabel, 0, wxBOTTOM, 2);
    chaptersHSizer->Add(m_chaptersCtrl, 1, wxRIGHT|wxEXPAND, 2);
    chaptersButtonsSizer->Add(m_addBt, 0, 0, 0);
    chaptersButtonsSizer->Add(m_delBt, 0, 0, 0);
    chaptersButtonsSizer->Add(m_propBt, 0, 0, 0);
    chaptersButtonsSizer->Add(20, 20, 0, wxEXPAND, 0);
    chaptersHSizer->Add(chaptersButtonsSizer, 0, wxLEFT|wxRIGHT|wxEXPAND, 2);
    chaptersVSizer->Add(chaptersHSizer, 1, wxEXPAND, 0);
    mainHSizer->Add(chaptersVSizer, 0, wxEXPAND, 0);
    mediaSizer->Add(m_mediaCtrl, 1, wxEXPAND, 0);
    mediaSizer->Add(m_slider, 0, wxEXPAND, 0);
    timeSizer->Add(m_timeLabel, 0, wxRIGHT|wxALIGN_CENTER_VERTICAL, 2);
    timeSizer->Add(m_timeCtrl, 0, 0, 0);
    timeSizer->Add(m_timeSpinBt, 0, wxRIGHT|wxEXPAND, 4);
    timeSizer->Add(m_durLabel, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 4);
    timeSizer->Add(m_durText, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 2);
    mediaSizer->Add(timeSizer, 0, wxEXPAND, 0);
    mainHSizer->Add(mediaSizer, 1, wxALL|wxEXPAND, 4);
    mainVSizer->Add(mainHSizer, 1, wxALL|wxEXPAND, 4);
    buttonSizer->Add(10, 10, 1, wxEXPAND, 0);
    buttonSizer->Add(m_okBt, 0, 0, 0);
    buttonSizer->Add(8, 8, 0, 0, 0);
    buttonSizer->Add(m_cancelBt, 0, 0, 0);
    buttonSizer->Add(10, 10, 1, wxEXPAND, 0);
    mainVSizer->Add(buttonSizer, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 4);
    SetSizer(mainVSizer);
    mainVSizer->Fit(this);
    Layout();
    // end wxGlade
}

/**<
 * Displays dialog
 */
int ChaptersDlg::ShowModal() {
	m_mediaCtrl->Load(m_vob->GetFilename());
	m_slider->SetMax(m_mediaCtrl->Length()/1000);
	m_timeSpinBt->SetMax(m_mediaCtrl->Length()/1000);
	m_durText->SetLabel(Time2String(m_mediaCtrl->Length(), true));
    if (m_chaptersCtrl->GetItemCount() > 0)
    	m_chaptersCtrl->SetItemState(0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
	return wxDialog::ShowModal();
}

void ChaptersDlg::SeekVideo(long pos, bool updateTimeCtrl) {
	m_slider->SetValue(lround(pos / 1000));
	m_timeSpinBt->SetValue(lround(pos / 1000));
	m_mediaCtrl->Seek((wxFileOffset) pos);
	if (updateTimeCtrl)
		m_timeCtrl->ChangeValue(Time2String(pos, true));
	if (m_selected >= 0 && m_cells[m_selected]->GetStart() != pos) {
		int lastSelected = m_selected;
		m_cells[m_selected]->SetStart(pos);
		m_chaptersCtrl->SetItem(m_selected, 0, Time2String(pos, true));
		// sort cells
		while (m_selected > 0 && m_cells[m_selected]->GetStart() < m_cells[m_selected - 1]->GetStart()) {
			Cell* tmp = m_cells[m_selected];
			m_cells[m_selected] = m_cells[m_selected - 1];
			m_cells[m_selected - 1] = tmp;
			m_selected--;
		}
		while (m_selected < (int) m_cells.size() - 1
				&& m_cells[m_selected]->GetStart() > m_cells[m_selected + 1]->GetStart()) {
			Cell* tmp = m_cells[m_selected];
			m_cells[m_selected] = m_cells[m_selected + 1];
			m_cells[m_selected + 1] = tmp;
			m_selected++;
		}
		m_chaptersCtrl->RefreshItems(0, m_cells.size() - 1);
		if (lastSelected != m_selected) {
			m_chaptersCtrl->SetItemState(m_selected, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
			m_chaptersCtrl->SetItemState(lastSelected, 0, wxLIST_STATE_SELECTED);
		}
	}
}

void ChaptersDlg::OnChapterSelect(wxListEvent &event) {
	bool selected = m_chaptersCtrl->GetSelectedItemCount() == 1;
	m_selected = selected ? m_chaptersCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) : -1;
	if (selected || event.GetEventObject() == NULL) {
		m_delBt->Enable(selected);
		m_propBt->Enable(selected);
		m_slider->Enable(selected);
		m_timeCtrl->Enable(selected);
		m_timeSpinBt->Enable(selected);
		SeekVideo(selected ? m_cells[m_selected]->GetStart() : 0);
	} else
		m_unselectTimer.Start(300, true);
}

void ChaptersDlg::OnUnselectTimer(wxTimerEvent& event) {
	if (m_chaptersCtrl->GetSelectedItemCount() != 1) {
		wxListEvent listEvent;
		OnChapterSelect(listEvent);
	}
}

void ChaptersDlg::OnChapterDClick(wxListEvent &event) {
	wxCommandEvent evt;
	OnPropBt(evt);
}

void ChaptersDlg::OnAddBt(wxCommandEvent &event) {
	long next = m_cells.size() > 0 ? m_cells.back()->GetStart() : 0;
	next += s_config.GetDefChapterLength() * 60000;
	m_cells.push_back(new Cell(next < m_mediaCtrl->Length() ? next : (long) m_mediaCtrl->Length()));
	m_chaptersCtrl->SetItemCount(m_cells.size());
	if (m_selected != -1)
		m_chaptersCtrl->SetItemState(m_selected, 0, wxLIST_STATE_SELECTED);
   	m_chaptersCtrl->SetItemState(m_chaptersCtrl->GetItemCount() - 1, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
	wxListEvent listEvent;
	OnChapterSelect(listEvent);
}

void ChaptersDlg::OnDelBt(wxCommandEvent &event) {
	if (m_chaptersCtrl->GetSelectedItemCount() != 1)
		return;
	long item = m_chaptersCtrl->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
	m_chaptersCtrl->DeleteItem(item);
	m_cells.erase(m_cells.begin() + item);
}

void ChaptersDlg::OnPropBt(wxCommandEvent &event) {
	if (m_selected < 0)
		return;
	CellPropDlg dialog(this, m_dvd, m_tsi, m_pgci, m_vob, m_cells[m_selected]);
	if (dialog.ShowModal() == wxID_OK) {
		m_chaptersCtrl->RefreshItem(m_selected);
		wxListEvent listEvent;
		OnChapterSelect(listEvent);
	}
}

void ChaptersDlg::OnSliderScroll(wxScrollEvent &event) {
	SeekVideo(((long)m_slider->GetValue())*1000);
}

void ChaptersDlg::OnChangeTime(wxCommandEvent &event) {
	wxRegEx re(wxT("^(([[:digit:]]+:)?[[:digit:]][[:digit:]]?:)?[[:digit:]][[:digit:]]?(\\.[[:digit:]]+)?$"));
	if (re.Matches(m_timeCtrl->GetValue()))
		SeekVideo(String2Time(m_timeCtrl->GetValue()), false);
}

void ChaptersDlg::OnTimeSpin(wxSpinEvent &event) {
	SeekVideo(((long)m_timeSpinBt->GetValue())*1000);
}

void ChaptersDlg::OnOkBt(wxCommandEvent &event) {
	EndModal(wxID_OK);
	m_vob->GetCells().swap(m_cells);
}

// wxGlade: add ChaptersDlg event handlers

