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

preview_dlg.cpp (C-Munipack project)
The preview 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 <math.h>

#include "main.h"
#include "utils.h"
#include "showheader_dlg.h"
#include "showwcsdata_dlg.h"
#include "frameinfo_dlg.h"
#include "configuration.h"

enum tFieldId
{
	LABEL_FRAME,
	LABEL_FILENAME,
	LABEL_DIRPATH,
	LABEL_DATETIME,
	LABEL_JULDAT,
	LABEL_FILTER,
	LABEL_EXPTIME,
	LABEL_CCDTEMP,
	LABEL_AVGFRAMES,
	LABEL_SUMFRAMES,
	LABEL_BIAS,
	LABEL_DARK,
	LABEL_FLAT,
	LABEL_TIME,
	LABEL_STARS,
	LABEL_MATCHED,
	LABEL_SOURCE,
	LABEL_CALIBRATION,
	LABEL_PHOTOMETRY
};

//-------------------------   CHOOSE STARS DIALOG   --------------------------------

CFrameInfoDlg::CFrameInfoDlg(GtkWindow *pParent):CInfoDlg(pParent, 0), m_pFile(NULL)
{
	gtk_widget_set_size_request(m_pDlg, 600, -1);

	// Labels
	AddHeading(LABEL_FRAME, 0, 0, "Frame");
	AddField(LABEL_DATETIME, 0, 1, "Date and time (UTC)");
	AddField(LABEL_JULDAT, 0, 2, "Julian date");
	AddField(LABEL_FILTER, 0, 3, "Optical filter", PANGO_ELLIPSIZE_END);
	AddField(LABEL_EXPTIME, 0, 4, "Exposure duration");
	AddField(LABEL_CCDTEMP, 0, 5, "CCD temperature");
	AddField(LABEL_AVGFRAMES, 0, 6, "Subframes averaged");
	AddField(LABEL_SUMFRAMES, 0, 7, "Subframes summed");
	AddSeparator(0, 8);
	AddHeading(LABEL_SOURCE, 0, 9, "Source file");
	AddField(LABEL_FILENAME, 0, 10, "File name", PANGO_ELLIPSIZE_MIDDLE);
	AddField(LABEL_DIRPATH, 0, 11, "Location", PANGO_ELLIPSIZE_MIDDLE);
	AddSeparator(0, 12);
	AddHeading(LABEL_CALIBRATION, 0, 13, "Calibration");
	AddField(LABEL_BIAS, 0, 14, "Bias frame", PANGO_ELLIPSIZE_MIDDLE);
	AddField(LABEL_DARK, 0, 15, "Dark frame", PANGO_ELLIPSIZE_MIDDLE);
	AddField(LABEL_FLAT, 0, 16, "Flat frame", PANGO_ELLIPSIZE_MIDDLE);
	AddField(LABEL_TIME, 0, 17, "Time correction");
	AddSeparator(0, 18);
	AddHeading(LABEL_PHOTOMETRY, 0, 19, "Photometry and matching");
	AddField(LABEL_STARS, 0, 20, "Stars found");
	AddField(LABEL_MATCHED, 0, 21, "Stars matched");
	gtk_widget_show_all(m_Tab);

	// Separator
	gtk_box_pack_start(GTK_BOX(m_Box), gtk_label_new(NULL), FALSE, TRUE, 0);

	GtkWidget *tbox = gtk_table_new(3, 4, FALSE);
	gtk_table_set_row_spacings(GTK_TABLE(tbox), 4);
	gtk_table_set_col_spacings(GTK_TABLE(tbox), 8);
	gtk_box_pack_start(GTK_BOX(m_Box), tbox, FALSE, TRUE, 0);
	GtkWidget *label1 = gtk_label_new("Original image");
	gtk_misc_set_alignment(GTK_MISC(label1), 0, 0.5);
	gtk_table_attach(GTK_TABLE(tbox), label1, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
	GtkWidget *label2 = gtk_label_new("Calibrated image");
	gtk_misc_set_alignment(GTK_MISC(label2), 0, 0.5);
	gtk_table_attach(GTK_TABLE(tbox), label2, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
	GtkWidget *label3 = gtk_label_new("Photometry image");
	gtk_misc_set_alignment(GTK_MISC(label3), 0, 0.5);
	gtk_table_attach(GTK_TABLE(tbox), label3, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
	m_OrigHdrBtn = gtk_button_new_with_label("Show header");
	gtk_table_attach(GTK_TABLE(tbox), m_OrigHdrBtn, 1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
	m_OrigWcsBtn = gtk_button_new_with_label("Show WCS data");
	gtk_table_attach(GTK_TABLE(tbox), m_OrigWcsBtn, 2, 3, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
	m_TempHdrBtn = gtk_button_new_with_label("Show header");
	gtk_table_attach(GTK_TABLE(tbox), m_TempHdrBtn, 1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
	m_TempWcsBtn = gtk_button_new_with_label("Show WCS data");
	gtk_table_attach(GTK_TABLE(tbox), m_TempWcsBtn, 2, 3, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
	m_PhotHdrBtn = gtk_button_new_with_label("Show header");
	gtk_table_attach(GTK_TABLE(tbox), m_PhotHdrBtn, 1, 2, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
	m_PhotWcsBtn = gtk_button_new_with_label("Show WCS data");
	gtk_table_attach(GTK_TABLE(tbox), m_PhotWcsBtn, 2, 3, 2, 3, GTK_FILL, GTK_FILL, 0, 0);
	m_OrigFileLbl = gtk_label_new(NULL);
	gtk_misc_set_alignment(GTK_MISC(m_OrigFileLbl), 0, 0.5);
	gtk_table_attach_defaults(GTK_TABLE(tbox), m_OrigFileLbl, 3, 4, 0, 1);
	m_TempFileLbl = gtk_label_new(NULL);
	gtk_misc_set_alignment(GTK_MISC(m_TempFileLbl), 0, 0.5);
	gtk_table_attach_defaults(GTK_TABLE(tbox), m_TempFileLbl, 3, 4, 1, 2);
	m_PhotFileLbl = gtk_label_new(NULL);
	gtk_misc_set_alignment(GTK_MISC(m_PhotFileLbl), 0, 0.5);
	gtk_table_attach_defaults(GTK_TABLE(tbox), m_PhotFileLbl, 3, 4, 2, 3);
		
	g_signal_connect(G_OBJECT(m_OrigHdrBtn), "clicked", G_CALLBACK(button_clicked), this);
	g_signal_connect(G_OBJECT(m_TempHdrBtn), "clicked", G_CALLBACK(button_clicked), this);
	g_signal_connect(G_OBJECT(m_PhotHdrBtn), "clicked", G_CALLBACK(button_clicked), this);
	g_signal_connect(G_OBJECT(m_OrigWcsBtn), "clicked", G_CALLBACK(button_clicked), this);
	g_signal_connect(G_OBJECT(m_TempWcsBtn), "clicked", G_CALLBACK(button_clicked), this);
	g_signal_connect(G_OBJECT(m_PhotWcsBtn), "clicked", G_CALLBACK(button_clicked), this);

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

CFrameInfoDlg::~CFrameInfoDlg()
{
	if (m_pFile)
		gtk_tree_row_reference_free(m_pFile);
}

void CFrameInfoDlg::Show(GtkTreePath *pFile)
{
	char buf[512], msg[512];
	CmpackDateTime dt;
	GtkTreeModel *pModel = g_Project->FileList();

	if (m_pFile) {
		gtk_tree_row_reference_free(m_pFile);
		m_pFile = NULL;
	}

	// Get frame data
	if (pFile) {
		m_pFile = gtk_tree_row_reference_new(pModel, pFile);

		// Enable/disable controls
		int frameId = g_Project->GetFrameID(pFile);
		double jd = g_Project->GetJulDate(pFile);
		gchar *report = g_Project->GetLastMessage(pFile), *orig_path = g_Project->GetSourceFile(pFile), *temp_file = g_Project->GetImageFileName(pFile);
		gchar *phot_file = g_Project->GetPhotFileName(pFile), *filter = g_Project->GetColorFilter(pFile);
		gchar *bias_file = g_Project->GetBiasFrameFile(pFile), *dark_file = g_Project->GetDarkFrameFile(pFile), *flat_file = g_Project->GetFlatFrameFile(pFile);
		double timecorr = g_Project->GetTimeCorrection(pFile), exptime = g_Project->GetExposure(pFile), ccdtemp = g_Project->GetCCDTemperature(pFile);
		int avg_frames = g_Project->GetAveragedFrames(pFile), sum_frames = g_Project->GetAccumulatedFrames(pFile);
		int nstars = g_Project->GetStars(pFile), matched_stars = g_Project->GetMatchedStars(pFile);

		// Init internal variables
		sprintf(buf, "Frame #%d - properties - %s", frameId, g_AppTitle);
		gtk_window_set_title(GTK_WINDOW(m_pDlg), buf);
		// Update properties
		if (orig_path) {
			gchar *basename = g_path_get_basename(orig_path);
			SetField(LABEL_FILENAME, basename);
			g_free(basename);
			gchar *dirpath = g_path_get_dirname(orig_path);
			SetField(LABEL_DIRPATH, dirpath);
			g_free(dirpath);
		} else {
			SetField(LABEL_FILENAME, "Not available");
			SetField(LABEL_DIRPATH, "Not available");
		}
		if (jd>0) {
			cmpack_decodejd(jd, &dt);
			sprintf(buf, "%04d-%02d-%02d %d:%02d:%02d.%03d", dt.date.year, dt.date.month, dt.date.day,
				dt.time.hour, dt.time.minute, dt.time.second, dt.time.milisecond);
			SetField(LABEL_DATETIME, buf);
			SetField(LABEL_JULDAT, jd, JD_PREC);
		} else {
			SetField(LABEL_DATETIME, "Not available");
			SetField(LABEL_JULDAT, "Not available");
		}
		if (filter)
			SetField(LABEL_FILTER, filter);
		else
			SetField(LABEL_FILTER, "Not available");
		if (exptime>=0.0)
			SetField(LABEL_EXPTIME, exptime, 3, "second(s)");
		else
			SetField(LABEL_EXPTIME, "Not available");
		if (ccdtemp>-999 && ccdtemp<999)
			SetField(LABEL_CCDTEMP, ccdtemp, 2, "\xC2\xB0""C");
		else
			SetField(LABEL_CCDTEMP, "Not available");
		if (avg_frames>0)
			SetField(LABEL_AVGFRAMES, avg_frames, "frame(s)");
		else
			SetField(LABEL_AVGFRAMES, "Not available");
		if (sum_frames>0)
			SetField(LABEL_SUMFRAMES, sum_frames, "frame(s)");
		else
			SetField(LABEL_SUMFRAMES, "Not available");
		if (bias_file)
			SetField(LABEL_BIAS, bias_file);
		else
			SetField(LABEL_BIAS, "Not used");
		if (dark_file)
			SetField(LABEL_DARK, dark_file);
		else
			SetField(LABEL_DARK, "Not used");
		if (flat_file)
			SetField(LABEL_FLAT, flat_file);
		else
			SetField(LABEL_FLAT, "Not used");
		if (timecorr!=0) {
			double days;
			int msecs = (int)(modf(fabs(timecorr)/86400.0, &days)*86400000);
			*msg = '\0';
			if (days>0) {
				sprintf(buf, "%d %s ", (int)days, (days==1 ? "day" : "days"));
				strcat(msg, buf);
			} 
			int hours = msecs/3600000;
			if (hours>0) {
				sprintf(buf, "%d %s ", hours, (hours==1 ? "hour" : "hours"));
				strcat(msg, buf);
			} 
			int minutes = (msecs/60000)%60;
			if (minutes>0) {
				sprintf(buf, "%d %s ", minutes, (minutes==1 ? "minute" : "minutes"));
				strcat(msg, buf);
			} 
			int seconds = (msecs/1000)%60;
			msecs = msecs%1000;
			if (seconds>0 || msecs>0) {
				if (seconds>0 && msecs==0) 
					sprintf(buf, "%.2d %s ", seconds, (seconds==1 ? "second" : "seconds"));
				else if (seconds==0 && msecs>0)
					sprintf(buf, "%.2d %s ", msecs, (msecs==1 ? "millisecond" : "milliseconds"));
				else 
					sprintf(buf, "%.2d.%.3d %s ", seconds, msecs, "seconds");
				strcat(msg, buf);
			}
			strcat(msg, (timecorr>0 ? "to future" : "to past"));
			SetField(LABEL_TIME, msg);
		} else
			SetField(LABEL_TIME, "Not used");
		if (nstars >= 0)
			SetField(LABEL_STARS, nstars, "star(s)");
		else
			SetField(LABEL_STARS, "Not available");
		if (matched_stars >= 0)
			SetField(LABEL_MATCHED, matched_stars, "star(s)");
		else
			SetField(LABEL_MATCHED, "Not available");
		// Enable/disable buttons
		{
			GError *error = NULL;
			CCCDFile *orig = LoadOrig(&error);
			if (error) {
				gtk_label_set_text(GTK_LABEL(m_OrigFileLbl), error->message);
				g_error_free(error);
			} else
				gtk_label_set_text(GTK_LABEL(m_OrigFileLbl), NULL);
			gtk_widget_set_sensitive(m_OrigHdrBtn, orig!=NULL);
			gtk_widget_set_sensitive(m_OrigWcsBtn, orig!=NULL && orig->Wcs()!=NULL);
			delete orig;
		}
		{
			GError *error = NULL;
			CCCDFile *temp = LoadTemp(&error);
			if (error) {
				gtk_label_set_text(GTK_LABEL(m_TempFileLbl), error->message);
				g_error_free(error);
			} else
				gtk_label_set_text(GTK_LABEL(m_TempFileLbl), NULL);
			gtk_widget_set_sensitive(m_TempHdrBtn, temp!=NULL);
			gtk_widget_set_sensitive(m_TempWcsBtn, temp!=NULL && temp->Wcs()!=NULL);
			delete temp;
		}
		{
			GError *error = NULL;
			CPhot *phot = LoadPhot(&error);
			if (error) {
				gtk_label_set_text(GTK_LABEL(m_PhotFileLbl), error->message);
				g_error_free(error);
			} else
				gtk_label_set_text(GTK_LABEL(m_PhotFileLbl), NULL);
			gtk_widget_set_sensitive(m_PhotHdrBtn, phot!=NULL);
			gtk_widget_set_sensitive(m_PhotWcsBtn, phot!=NULL && phot->Wcs()!=NULL);
			delete phot;
		}

		g_free(orig_path);
		g_free(filter);
		g_free(temp_file);
		g_free(phot_file);
		g_free(bias_file);
		g_free(dark_file);
		g_free(flat_file);
		g_free(report);
	}

	CInfoDlg::ShowModal();
}

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

void CFrameInfoDlg::OnButtonClicked(GtkWidget *pBtn)
{
	if (pBtn==GTK_WIDGET(m_OrigHdrBtn))
		ShowHeader_Orig();
	else if (pBtn==GTK_WIDGET(m_TempHdrBtn))
		ShowHeader_Temp();
	else if (pBtn==GTK_WIDGET(m_PhotHdrBtn))
		ShowHeader_Phot();
	if (pBtn==GTK_WIDGET(m_OrigWcsBtn))
		ShowWcsData_Orig();
	else if (pBtn==GTK_WIDGET(m_TempWcsBtn))
		ShowWcsData_Temp();
	else if (pBtn==GTK_WIDGET(m_PhotWcsBtn))
		ShowWcsData_Phot();
}

CCCDFile *CFrameInfoDlg::LoadOrig(GError **error)
{
	bool positiveWest = g_Project->Profile()->GetBool(CProfile::POSITIVE_WEST);

	if (!m_pFile)
		return NULL;

	GtkTreePath *pPath = gtk_tree_row_reference_get_path(m_pFile);
	if (!pPath) 
		return NULL;

	gchar *orig_file = g_Project->GetSourceFile(pPath);
	if (!orig_file) {
		gtk_tree_path_free(pPath);
		return NULL;
	}

	CCCDFile *file = new CCCDFile();
	if (!file->Open(orig_file, CMPACK_OPEN_READONLY, (!positiveWest ? 0 : CMPACK_OPENF_POSITIVE_WEST), error)) {
		delete file;
		file = NULL;
	}

	g_free(orig_file);
	gtk_tree_path_free(pPath);
	return file;
}

void CFrameInfoDlg::ShowHeader_Orig(void)
{
	GError *error = NULL;
	CCCDFile *file = LoadOrig(&error);
	if (file) {
		CShowHeaderDlg dlg(GTK_WINDOW(m_pDlg));
		gchar *basename = g_path_get_basename(file->Path());
		dlg.Execute(file, basename);
		g_free(basename);
		delete file;
	} else {
		if (error) {
			ShowError(GTK_WINDOW(m_pDlg), error->message);
			g_error_free(error);
		}
	}
}

void CFrameInfoDlg::ShowWcsData_Orig(void)
{
	GError *error = NULL;
	CCCDFile *file = LoadOrig(&error);
	if (file) {
		if (file->Wcs()) {
			CShowWcsDataDlg dlg(GTK_WINDOW(m_pDlg));
			gchar *basename = g_path_get_basename(file->Path());
			dlg.Execute(*file->Wcs(), basename);
			g_free(basename);
		}
		delete file;
	} else {
		if (error) {
			ShowError(GTK_WINDOW(m_pDlg), error->message);
			g_error_free(error);
		}
	}
}

CCCDFile *CFrameInfoDlg::LoadTemp(GError **error)
{
	bool positiveWest = g_Project->Profile()->GetBool(CProfile::POSITIVE_WEST);

	if (!m_pFile)
		return NULL;

	GtkTreePath *pPath = gtk_tree_row_reference_get_path(m_pFile);
	if (!pPath) 
		return NULL;

	gchar *temp_file = g_Project->GetImageFileName(pPath);
	if (!temp_file) {
		gtk_tree_path_free(pPath);
		return NULL;
	}

	if ((g_Project->GetState(pPath) & CFILE_CONVERSION) == 0) {
		gtk_tree_path_free(pPath);
		g_free(temp_file);
		return NULL;
	}

	gchar *fpath = g_build_filename(g_Project->DataDir(), temp_file, NULL);
	CCCDFile *file = new CCCDFile();
	if (!file->Open(fpath, CMPACK_OPEN_READONLY, (!positiveWest ? 0 : CMPACK_OPENF_POSITIVE_WEST), error)) {
		delete file;
		file = NULL;
	}

	g_free(fpath);
	g_free(temp_file);
	gtk_tree_path_free(pPath);
	return file;
}

void CFrameInfoDlg::ShowHeader_Temp(void)
{
	GError *error = NULL;
	CCCDFile *file = LoadTemp(&error);
	if (file) {
		CShowHeaderDlg dlg(GTK_WINDOW(m_pDlg));
		gchar *basename = g_path_get_basename(file->Path());
		dlg.Execute(file, basename);
		g_free(basename);
		delete file;
	} else {
		if (error) {
			ShowError(GTK_WINDOW(m_pDlg), error->message);
			g_error_free(error);
		}
	}
}

void CFrameInfoDlg::ShowWcsData_Temp(void)
{
	GError *error = NULL;
	CCCDFile *file = LoadTemp(&error);
	if (file) {
		if (file->Wcs()) {
			CShowWcsDataDlg dlg(GTK_WINDOW(m_pDlg));
			gchar *basename = g_path_get_basename(file->Path());
			dlg.Execute(*file->Wcs(), basename);
			g_free(basename);
		}
		delete file;
	} else {
		if (error) {
			ShowError(GTK_WINDOW(m_pDlg), error->message);
			g_error_free(error);
		}
	}
}

CPhot *CFrameInfoDlg::LoadPhot(GError **error)
{
	if (!m_pFile)
		return NULL;

	GtkTreePath *pPath = gtk_tree_row_reference_get_path(m_pFile);
	if (!pPath) 
		return NULL;

	if ((g_Project->GetState(pPath) & CFILE_PHOTOMETRY)==0) {
		gtk_tree_path_free(pPath);
		return NULL;
	}

	gchar *pht_file = g_Project->GetPhotFile(pPath);
	if (!pht_file) {
		gtk_tree_path_free(pPath);
		return NULL;
	}

	CPhot *phot = new CPhot();
	if (!phot->Load(pht_file, error)) {
		delete phot;
		phot = NULL;
	}

	g_free(pht_file);
	gtk_tree_path_free(pPath);
	return phot;
}

void CFrameInfoDlg::ShowHeader_Phot(void)
{
	GError *error = NULL;
	CPhot *phot = LoadPhot(&error);
	if (phot) {
		CShowHeaderDlg dlg(GTK_WINDOW(m_pDlg));
		gchar *basename = g_path_get_basename(phot->Path());
		dlg.Execute(phot, basename);
		g_free(basename);
		delete phot;
	} else {
		if (error) {
			ShowError(GTK_WINDOW(m_pDlg), error->message);
			g_error_free(error);
		}
	}
}

void CFrameInfoDlg::ShowWcsData_Phot(void)
{
	GError *error = NULL;
	CPhot *phot = LoadPhot(&error);
	if (phot) {
		if (phot->Wcs()) {
			CShowWcsDataDlg dlg(GTK_WINDOW(m_pDlg));
			gchar *basename = g_path_get_basename(phot->Path());
			dlg.Execute(*phot->Wcs(), basename);
			g_free(basename);
		}
		delete phot;
	} else {
		if (error) {
			ShowError(GTK_WINDOW(m_pDlg), error->message);
			g_error_free(error);
		}
	}
}
