/**************************************************************

matching_dlg.cpp (C-Munipack project)
The 'Match stars' dialog
Copyright (C) 2008 David Motl, dmotl@volny.cz

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 2
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

**************************************************************/

#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "project.h"
#include "configuration.h"
#include "configuration.h"
#include "matching_dlg.h"
#include "progress_dlg.h"
#include "catfile_dlg.h"
#include "phtfile_dlg.h"
#include "main.h"
#include "utils.h"
#include "proc_classes.h"
#include "ctxhelp.h"
#include "project_dlg.h"
#include "matching_st.h"
#include "matching_mt.h"

//-------------------------   HELPER FUNCTIONS   --------------------------------

// Make list of row references
static gboolean make_list(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, GList **list)
{
	GtkTreeRowReference *rowref = gtk_tree_row_reference_new(model, path);
	*list = g_list_append(*list, rowref);
	return FALSE;
}

//-------------------------   CHILD TABS   --------------------------------

CMatchingTab::CMatchingTab(CMatchingDlg *parent):m_pParent(parent), m_Box(NULL) 
{
	m_Box = gtk_vbox_new(FALSE, 4);
	gtk_container_set_border_width(GTK_CONTAINER(m_Box), 0);
}

GtkWindow *CMatchingTab::parentWindow() const 
{ 
	return GTK_WINDOW(m_pParent->m_pDlg); 
}

GtkBox *CMatchingTab::optionsBox() const
{
	return GTK_BOX(m_pParent->m_OptionsBox);
}

//-------------------------   MAIN WINDOW   --------------------------------

CMatchingDlg::CMatchingDlg(GtkWindow *pParent):m_pParent(pParent), m_FileList(NULL),
	m_InFiles(0), m_OutFiles(0), m_currentTab(-1)
{
	int mon;
	GtkWidget *label;
	GdkRectangle rc;

	// Dialog with buttons
	m_pDlg = gtk_dialog_new_with_buttons("Match stars", pParent, 
		(GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
		GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, 
		GTK_STOCK_HELP, GTK_RESPONSE_HELP, NULL);
	gtk_dialog_widget_standard_tooltips(GTK_DIALOG(m_pDlg));
	gtk_window_set_position(GTK_WINDOW(m_pDlg), GTK_WIN_POS_CENTER);
	gtk_dialog_set_tooltip_by_response(GTK_DIALOG(m_pDlg), GTK_RESPONSE_ACCEPT, "Start the process");
	g_signal_connect(G_OBJECT(m_pDlg), "response", G_CALLBACK(response_dialog), this);

	// Dialog icon
	gchar *icon = get_icon_file("matchstars");
	gtk_window_set_icon(GTK_WINDOW(m_pDlg), gdk_pixbuf_new_from_file(icon, NULL));
	g_free(icon);

	// Dialog layout
	GtkWidget *vbox = gtk_vbox_new(FALSE, 4);
	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(m_pDlg)->vbox), vbox, TRUE, TRUE, 0);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 8);

	// Dialog size
	GdkScreen *scr = gtk_window_get_screen(pParent);
	mon = gdk_screen_get_monitor_at_window(scr, GTK_WIDGET(pParent)->window);
	gdk_screen_get_monitor_geometry(scr, mon, &rc);
	if (rc.width>0 && rc.height>0)
		gtk_window_set_default_size(GTK_WINDOW(m_pDlg), RoundToInt(0.7*rc.width), RoundToInt(0.7*rc.height));

	// Mode selection
	m_TargetFrame = gtk_vbox_new(TRUE, 4);
	gtk_box_pack_start(GTK_BOX(vbox), m_TargetFrame, FALSE, TRUE, 0);
	label = gtk_label_new(NULL);
	gtk_label_set_markup(GTK_LABEL(label), "<b>Select target type:</b>");
	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
	gtk_box_pack_start(GTK_BOX(m_TargetFrame), label, FALSE, TRUE, 0);
	m_STMode = gtk_radio_button_new_with_label(NULL, "Stationary target (variable star, exoplanet, etc.)");
	gtk_widget_set_tooltip_text(m_STMode, "Choose this option to make a light curve of an object that does not move");
	g_signal_connect(G_OBJECT(m_STMode), "toggled", G_CALLBACK(button_clicked), this);
	gtk_box_pack_start(GTK_BOX(m_TargetFrame), m_STMode, TRUE, TRUE, 0);
	GSList *group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(m_STMode));
	m_MTMode = gtk_radio_button_new_with_label(group, "Moving target (minor Solar System planets)");
	gtk_widget_set_tooltip_text(m_MTMode, "Choose this option to track moving target through the data set");
	g_signal_connect(G_OBJECT(m_MTMode), "toggled", G_CALLBACK(button_clicked), this);
	gtk_box_pack_start(GTK_BOX(m_TargetFrame), m_MTMode, TRUE, TRUE, 0);
	
	// Bottom toolbox
	m_OptionsBox = gtk_hbox_new(FALSE, 8);
	m_OptionsBtn = gtk_button_new_with_label("Options");
	gtk_widget_set_tooltip_text(m_OptionsBtn, "Edit project settings");
	gtk_box_pack_start(GTK_BOX(m_OptionsBox), m_OptionsBtn, 0, 0, 0);
	g_signal_connect(G_OBJECT(m_OptionsBtn), "clicked", G_CALLBACK(button_clicked), this);
	gtk_box_pack_end(GTK_BOX(vbox), m_OptionsBox, FALSE, TRUE, 0);

	m_Tabs[0] = new CMatchingSTTab(this);
	gtk_box_pack_start(GTK_BOX(vbox), m_Tabs[0]->widget(), TRUE, TRUE, 0);
	m_Tabs[1] = new CMatchingMTTab(this);
	gtk_box_pack_start(GTK_BOX(vbox), m_Tabs[1]->widget(), TRUE, TRUE, 0);

	gtk_widget_show_all(GTK_DIALOG(m_pDlg)->vbox);
}

CMatchingDlg::~CMatchingDlg()
{
	gtk_widget_destroy(m_pDlg);
	g_list_free(m_FileList);
}

void CMatchingDlg::Execute(void)
{
	char msg[256];

	m_currentTab = -1;
	g_list_foreach(m_FileList, (GFunc)gtk_tree_row_reference_free, NULL);
	g_list_free(m_FileList);
	m_FileList = NULL;

	GError *error = NULL;
	if (!m_Tabs[0]->OnInitDialog(CMatchingTab::INIT_MATCH, NULL, NULL, &error) || !m_Tabs[1]->OnInitDialog(CMatchingTab::INIT_MATCH, NULL, NULL, &error)) {
		if (error) {
			ShowError(m_pParent, error->message);
			g_error_free(error);
		}
		return;
	}
	gtk_widget_hide(m_Tabs[0]->widget());
	m_Tabs[0]->OnTabHide();
	gtk_widget_hide(m_Tabs[1]->widget());
	m_Tabs[1]->OnTabHide();

	gtk_widget_show(m_TargetFrame);
	if (g_Project->GetTargetType() == STATIONARY_TARGET) {
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_STMode), TRUE);
		SelectMode(STATIONARY_TARGET);
	} else {
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_MTMode), TRUE);
		SelectMode(MOVING_TARGET);
	}
	
	if (gtk_dialog_run(GTK_DIALOG(m_pDlg))!=GTK_RESPONSE_ACCEPT) {
		gtk_widget_hide(m_pDlg);
		return;
	}
	gtk_widget_hide(m_pDlg);

	g_Project->ClearReference();
	
	// Always all files
	gtk_tree_model_foreach(g_Project->FileList(), GtkTreeModelForeachFunc(make_list), &m_FileList);
	if (m_FileList) {
		CProgressDlg pDlg(m_pParent, "Matching photometry files");
		pDlg.SetMinMax(0, g_list_length(m_FileList));
		bool retval = pDlg.Execute(ExecuteProc, this, &error) != 0;
		g_Project->applyPendingUpdates();
		if (!retval) {
			if (error) {
				ShowError(m_pParent, error->message, true);
				g_error_free(error);
			}
		} else if (m_OutFiles==0) {
			ShowError(m_pParent, "No file was successfully processed.", true);
		} else if (m_OutFiles!=m_InFiles) {
			sprintf(msg, "%d file(s) were successfully processed, %d file(s) failed.", 
				m_OutFiles, m_InFiles-m_OutFiles);
			ShowWarning(m_pParent, msg, true);
		} else {
			sprintf(msg, "All %d file(s) were successfully processed.", m_OutFiles);
			ShowInformation(m_pParent, msg, true);
		}
		g_list_foreach(m_FileList, (GFunc)gtk_tree_row_reference_free, NULL);
		g_list_free(m_FileList);
		m_FileList = NULL;
	}
	g_Project->Save();
}

bool CMatchingDlg::SelectFile(char **fpath)
{
	m_currentTab = -1;
	g_list_foreach(m_FileList, (GFunc)gtk_tree_row_reference_free, NULL);
	g_list_free(m_FileList);
	m_FileList = NULL;

	GError *error = NULL;
	if (!m_Tabs[0]->OnInitDialog(CMatchingTab::INIT_SELECT_FILE, NULL, fpath, &error)) {
		if (error) {
			ShowError(m_pParent, error->message);
			g_error_free(error);
		}
		return false;
	}

	gtk_widget_hide(m_TargetFrame);
	gtk_widget_hide(m_Tabs[0]->widget());
	m_Tabs[0]->OnTabHide();
	gtk_widget_hide(m_Tabs[1]->widget());
	m_Tabs[1]->OnTabHide();
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_STMode), TRUE);
	SelectMode(STATIONARY_TARGET);

	bool retval = gtk_dialog_run(GTK_DIALOG(m_pDlg)) == GTK_RESPONSE_ACCEPT;
	gtk_widget_hide(m_pDlg);
	if (retval) 
		((CMatchingSTTab*)m_Tabs[0])->SelectFile(fpath);
	return retval;
}

bool CMatchingDlg::SelectFrame(int *frame_id)
{
	m_currentTab = -1;
	g_list_foreach(m_FileList, (GFunc)gtk_tree_row_reference_free, NULL);
	g_list_free(m_FileList);
	m_FileList = NULL;

	GError *error = NULL;
	if (!m_Tabs[0]->OnInitDialog(CMatchingTab::INIT_SELECT_FRAME, frame_id, NULL, &error)) {
		if (error) {
			ShowError(m_pParent, error->message);
			g_error_free(error);
		}
		return false;
	}

	gtk_widget_hide(m_TargetFrame);
	gtk_widget_hide(m_Tabs[0]->widget());
	m_Tabs[0]->OnTabHide();
	gtk_widget_hide(m_Tabs[1]->widget());
	m_Tabs[1]->OnTabHide();
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_STMode), TRUE);
	SelectMode(STATIONARY_TARGET);

	bool retval = gtk_dialog_run(GTK_DIALOG(m_pDlg)) == GTK_RESPONSE_ACCEPT;
	gtk_widget_hide(m_pDlg);
	if (retval) 
		((CMatchingSTTab*)m_Tabs[0])->SelectFrame(frame_id);
	return retval;
}

void CMatchingDlg::response_dialog(GtkDialog *pDlg, gint response_id, CMatchingDlg *pMe)
{
	if (!pMe->OnResponseDialog(response_id))
		g_signal_stop_emission_by_name(pDlg, "response");
}

bool CMatchingDlg::OnResponseDialog(gint response_id)
{
	switch (response_id)
	{
	case GTK_RESPONSE_ACCEPT:
		if (m_currentTab>=0) {
			GError *error = NULL;
			if (!m_Tabs[m_currentTab]->OnResponseDialog(response_id, &error)) {
				if (error) {
					ShowError(m_pParent, error->message, true);
					g_error_free(error);
				}
				return false;
			}
		}
		break;

	case GTK_RESPONSE_HELP:
		// Show context help
		g_MainWnd->ShowHelp(GTK_WINDOW(m_pDlg), IDH_MATCH_STARS);
		return false;
	}
	return true;
}

int CMatchingDlg::ExecuteProc(CProgressDlg *sender, void *userdata)
{
	return ((CMatchingDlg*)userdata)->ProcessFiles(sender);
}

int CMatchingDlg::ProcessFiles(CProgressDlg *sender)
{
	if (m_currentTab>=0)
		return m_Tabs[m_currentTab]->ProcessFiles(m_FileList, m_InFiles, m_OutFiles, sender);
	return 0;
}

void CMatchingDlg::button_clicked(GtkWidget *button, CMatchingDlg *pDlg)
{
	pDlg->OnButtonClicked(button);
}

void CMatchingDlg::OnButtonClicked(GtkWidget *pBtn)
{
	if (pBtn==m_MTMode) 
		SelectMode(MOVING_TARGET);
	else if (pBtn==m_STMode) 
		SelectMode(STATIONARY_TARGET);
	else if (pBtn==m_OptionsBtn)
		EditPreferences();
}

void CMatchingDlg::SelectMode(tTargetType mode)
{
	switch (mode)
	{
	case STATIONARY_TARGET:
		SelectTab(0);
		break;
	case MOVING_TARGET:
		SelectTab(1);
		break;
	default:
		break;
	}
}

void CMatchingDlg::SelectTab(int tabIndex)
{
	assert(tabIndex>=0);
	if (m_currentTab != tabIndex) {
		if (m_currentTab>=0) {
			m_Tabs[m_currentTab]->OnTabHide();
			gtk_widget_hide(m_Tabs[m_currentTab]->widget());
		}
		m_currentTab = tabIndex;
		gtk_widget_show(m_Tabs[m_currentTab]->widget());
		m_Tabs[m_currentTab]->OnTabShow();
	}
}

void CMatchingDlg::EditPreferences(void)
{
	CEditProjectDlg pDlg(GTK_WINDOW(m_pDlg));
	pDlg.Execute(PAGE_MATCHING);
}

