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

main_dlg.cpp (C-Munipack project)
Main 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 <glib.h>
#include <math.h>
#include <string.h>

#include "chart_main.h"
#include "chart_dlg.h"
#include "cmpack_chart_view.h"
#include "utils.h"

enum tMenuId
{
	MENU_FILE = 1
};

enum tCommandId
{
	CMD_EXIT_APP = 100,
	CMD_ZOOM_IN,
	CMD_ZOOM_OUT,
	CMD_ZOOM_11
};

//-------------------------   MAIN MENU   ---------------------------

static const CMenuBar::tMenuItem FileMenu[] = {
	{ CMenuBar::MB_ITEM,		CMD_EXIT_APP,		"E_xit", "exit" },
	{ CMenuBar::MB_END }
};

static const CMenuBar::tMenu MainMenu[] = {
	{ "_Files", MENU_FILE,	FileMenu },
	{ NULL }
};

//-------------------------   POPUP MENU   ------------------------------------

static const CPopupMenu::tPopupMenuItem ContextMenu[] = {
	{ CPopupMenu::MB_ITEM,	CMD_ZOOM_IN,	"Zoom _in" },
	{ CPopupMenu::MB_ITEM,	CMD_ZOOM_OUT,	"Zoom _out" },
	{ CPopupMenu::MB_ITEM,	CMD_ZOOM_11,	"_Fit to window" },
	{ CPopupMenu::MB_END }
};

//------------------------  TOOLBAR HELPERS   ---------------------------------

static GtkToolItem *toolbar_new_button_from_stock(GtkWidget *toolbar, const gchar *stock_id)
{
	GtkToolItem *tbtn = gtk_tool_button_new_from_stock(stock_id);
	gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tbtn, -1);
	return tbtn;
}

static GtkToolItem *toolbar_new_widget(GtkWidget *toolbar, GtkWidget *widget)
{
	GtkToolItem *item = gtk_tool_item_new();
	gtk_container_add(GTK_CONTAINER(item), widget);
	gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
	return item;
}

static GtkWidget *toolbar_new_entry(GtkWidget *toolbar)
{
	GtkWidget *entry = gtk_entry_new();
	gtk_entry_set_width_chars(GTK_ENTRY(entry), 10);
	gtk_entry_set_alignment(GTK_ENTRY(entry), 0.5);
	gtk_editable_set_editable(GTK_EDITABLE(entry), false);
	toolbar_new_widget(toolbar, entry);
	return entry;
}

static GtkWidget *toolbar_new_combo(GtkWidget *toolbar)
{
	GtkWidget *entry = gtk_combo_box_new();
	gtk_widget_set_size_request(entry, 120, -1);
	toolbar_new_widget(toolbar, entry);
	return entry;
}

static GtkWidget *toolbar_new_image(GtkWidget *toolbar, const char *icon)
{
	gchar *ficon = get_icon_file(icon);
	GtkWidget *img = gtk_image_new_from_file(ficon);
	g_free(ficon);
	toolbar_new_widget(toolbar, img);
	return img;
}

static GtkToolItem *toolbar_new_separator(GtkWidget *toolbar)
{
	GtkToolItem *tbtn = gtk_separator_tool_item_new();
	gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tbtn, -1);
	return tbtn;
}

//-------------------------   GRAPH TEST DIALOG   --------------------------------

CMainWindow::CMainWindow():m_pDlg(NULL), m_Updating(false), m_Image(NULL), m_ImageData(NULL),
	m_ActAperture(0), m_UpdatePos(false), m_TimerId(-1), m_StatusCtx(-1), 
	m_StatusMsg(-1), m_SelectedCount(0), m_SelectedItem(0), m_ChartData(NULL)
{
	GtkWidget *vbox, *scrwnd, *tbox;

	// Main window
	m_pDlg = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title(GTK_WINDOW (m_pDlg), "Chart test");
	gtk_window_set_position(GTK_WINDOW(m_pDlg), GTK_WIN_POS_CENTER);
	gtk_window_set_default_size(GTK_WINDOW(m_pDlg), 800, 600);
	g_signal_connect(G_OBJECT(m_pDlg), "delete_event", G_CALLBACK (exit_event), this);
	gtk_widget_realize(GTK_WIDGET(m_pDlg));

	// Window layout
	vbox = gtk_vbox_new(FALSE, 0);
	gtk_container_add(GTK_CONTAINER(m_pDlg), vbox);

	// Menu bar
	m_Menu.Create(MainMenu);
	m_Menu.RegisterCallback(MenuCallback, this);
	gtk_box_pack_start(GTK_BOX(vbox), m_Menu.Handle(), FALSE, FALSE, 0);

	// Toolbar
	tbox = gtk_toolbar_new();
	gtk_toolbar_set_style(GTK_TOOLBAR(tbox), GTK_TOOLBAR_ICONS);
	gtk_toolbar_set_orientation(GTK_TOOLBAR(tbox), GTK_ORIENTATION_HORIZONTAL);
	gtk_box_pack_start(GTK_BOX(vbox), tbox, false, false, 0);

	// Image
	m_Image = CImage::fromFile("test-fits.fts");
	if (m_Image)
		m_ImageData = m_Image->ToImageData(false, false, false, false);

	// Photometry file
	if (m_Data.Load("test-fits.pht")) 
		m_ChartData = m_Data.ToChartData(false);
		
	// Graph view
	m_pChart = cmpack_chart_view_new_with_model(m_ChartData);
	cmpack_chart_view_set_image(CMPACK_CHART_VIEW(m_pChart), m_ImageData);
	scrwnd = gtk_scrolled_window_new (NULL, NULL);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrwnd),
		GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS);
	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrwnd), 
		GTK_SHADOW_ETCHED_IN);
	gtk_container_add(GTK_CONTAINER(scrwnd), m_pChart);
	gtk_box_pack_start(GTK_BOX(vbox), scrwnd, TRUE, TRUE, 0);
	cmpack_chart_view_show_scales(CMPACK_CHART_VIEW(m_pChart), TRUE);
	cmpack_chart_view_show_grid(CMPACK_CHART_VIEW(m_pChart), TRUE);
	cmpack_chart_view_set_image(CMPACK_CHART_VIEW(m_pChart), m_ImageData);
	cmpack_chart_view_set_selection_mode(CMPACK_CHART_VIEW(m_pChart), GTK_SELECTION_SINGLE);
	cmpack_chart_view_set_mouse_control(CMPACK_CHART_VIEW(m_pChart), TRUE);

	gdouble coeff[6];
	memset(coeff, 0, 6*sizeof(gdouble));
	coeff[0] = -25;
	coeff[1] = 0.5;
	coeff[2] = 0.01;

	coeff[3] = -25;
	coeff[4] = 0.5;
	coeff[5] = 0.01;

	gint layerId = cmpack_chart_view_add_layer(CMPACK_CHART_VIEW(m_pChart));
	//cmpack_chart_view_add_qpcurve(CMPACK_CHART_VIEW(m_pChart), layerId, coeff, 50, 150, CMPACK_COLOR_DEFAULT);
	//cmpack_chart_view_add_mark(CMPACK_CHART_VIEW(m_pChart), layerId, 50, 50, 45, CMPACK_COLOR_DEFAULT);
	cmpack_chart_view_add_object(CMPACK_CHART_VIEW(m_pChart), layerId, 50, 50, CMPACK_COLOR_DEFAULT, "aaa");

	g_signal_connect(G_OBJECT(m_pChart), "selection-changed", G_CALLBACK (selection_changed), this);
	g_signal_connect(G_OBJECT(m_pChart), "item-activated", G_CALLBACK (item_activated), this);
	g_signal_connect(G_OBJECT(m_pChart), "mouse-moved", G_CALLBACK (mouse_moved), this);
	g_signal_connect(G_OBJECT(m_pChart), "button-press-event", G_CALLBACK(button_press_event), this);

	// Status bar
	m_pStatus = gtk_statusbar_new();
	gtk_box_pack_start(GTK_BOX(vbox), m_pStatus, FALSE, FALSE, 0);
	m_StatusCtx = gtk_statusbar_get_context_id(GTK_STATUSBAR(m_pStatus), "Main");

	// Popup menu
	m_Popup.Create(ContextMenu);
	m_Popup.RegisterCallback(PopupCallback, this);

	// Timers
	m_TimerId = g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 100, GSourceFunc(update_sbar), this, NULL);

	// Show window
	gtk_widget_show_all(vbox);
	gtk_window_present(GTK_WINDOW(m_pDlg));
}

CMainWindow::~CMainWindow()
{
	if (m_TimerId>=0)
		g_source_remove(m_TimerId);
	if (m_ChartData)
		g_object_unref(m_ChartData);
	if (m_ImageData)
		g_object_unref(m_ImageData);
}

gint CMainWindow::exit_event(GtkWidget *widget, GdkEvent *event, CMainWindow *pMe)
{
	gtk_main_quit();
	return FALSE;
}

void CMainWindow::OnCommand(int cmd_id)
{
	gdouble zoom;

	switch (cmd_id)
	{
	case CMD_EXIT_APP:
		// Exit application
		gtk_main_quit();
		break;

	case CMD_ZOOM_IN:
		// Increase zoom
		zoom = cmpack_chart_view_get_zoom(CMPACK_CHART_VIEW(m_pChart));
		cmpack_chart_view_set_zoom(CMPACK_CHART_VIEW(m_pChart), zoom+10.0);
		break;
	case CMD_ZOOM_OUT:	
		// Decrease zoom
		zoom = cmpack_chart_view_get_zoom(CMPACK_CHART_VIEW(m_pChart));
		cmpack_chart_view_set_zoom(CMPACK_CHART_VIEW(m_pChart), zoom-10.0);
		break;
	case CMD_ZOOM_11:
		// Fit to window
		cmpack_chart_view_set_zoom(CMPACK_CHART_VIEW(m_pChart), 0);
		break;
	}
}

void CMainWindow::selection_changed(GtkWidget *button, CMainWindow *pDlg)
{
	pDlg->OnSelectionChanged();
}

void CMainWindow::OnSelectionChanged(void)
{
	gint count, item;
	GList *rows = cmpack_chart_view_get_selected_rows(CMPACK_CHART_VIEW(m_pChart));
	if (rows) {
		count = g_list_length(rows);
		item = GPOINTER_TO_INT(rows->data);
		if (count!=m_SelectedCount || item!=m_SelectedItem) {
			m_SelectedCount = count;
			m_SelectedItem = item;
			UpdateStatus();
		}
		g_list_free(rows);
	} else {
		if (m_SelectedCount>0) {
			m_SelectedCount = 0;
			m_SelectedItem = -1;
			UpdateStatus();
		}
	}
}

void CMainWindow::item_activated(GtkWidget *button, gint row, CMainWindow *pDlg)
{
	pDlg->OnItemActivated(row);
}

void CMainWindow::OnItemActivated(gint row)
{
}

void CMainWindow::mouse_moved(GtkWidget *button, CMainWindow *pDlg)
{
	pDlg->m_UpdatePos = true;
}

gboolean CMainWindow::update_sbar(CMainWindow *pDlg)
{
	if (pDlg->m_UpdatePos && pDlg->m_SelectedCount==0) {
		pDlg->m_UpdatePos = false;
		pDlg->UpdateStatus();
	}
	return TRUE;
}

void CMainWindow::UpdateStatus(void)
{
	gchar buf[256];

	if (m_StatusMsg>=0) {
		gtk_statusbar_pop(GTK_STATUSBAR(m_pStatus), m_StatusCtx);
		m_StatusMsg = -1;
	}

	if (m_SelectedCount>0) {
		if (m_SelectedCount==1) {
			gint id = (int)cmpack_chart_data_get_param(m_ChartData, m_SelectedItem);
			sprintf(buf, "Object #%d", id);
		} else 
			sprintf(buf, "%d objects selected", m_SelectedCount);
		m_StatusMsg = gtk_statusbar_push(GTK_STATUSBAR(m_pStatus), m_StatusCtx, buf);
	} else {
		gdouble x, y;
		if (cmpack_chart_view_mouse_pos(CMPACK_CHART_VIEW(m_pChart), &x, &y)) {
			sprintf(buf, "x = %.0f, y = %.0f", x, y);
			m_StatusMsg = gtk_statusbar_push(GTK_STATUSBAR(m_pStatus), m_StatusCtx, buf);
		}
	}
}

void CMainWindow::MenuCallback(CCBObject *sender, int message, int wparam, void* lparam, void* cb_data)
{
	CMainWindow *pMe = (CMainWindow*)cb_data;

	switch (message)
	{
	case CMenuBar::CB_ACTIVATE:
		// Menu bar command
		pMe->OnCommand(wparam);
		break;
	}
}

void CMainWindow::PopupCallback(CCBObject *sender, int message, int wparam, void* lparam, void* cb_data)
{
	CMainWindow *pMe = (CMainWindow*)cb_data;

	switch (message)
	{
	case CPopupMenu::CB_ACTIVATE:
		// Popup menu command
		pMe->OnCommand(wparam);
		break;
	}
}

gboolean CMainWindow::button_press_event(GtkWidget *widget, GdkEventButton *event, CMainWindow *pMe)
{
	if (event->button == 3) {
		pMe->OnContextMenu(widget, event);
		return TRUE;
	}
	return FALSE;
}

void CMainWindow::OnContextMenu(GtkWidget *widget, GdkEventButton *event)
{
	gtk_widget_grab_focus(m_pChart);
	m_Popup.Execute(event);
}
