/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 8 c-style: "K&R" -*- */

/* Gnome gxsm - Gnome X Scanning Microscopy
 * universal STM/AFM/SARLS/SPALEED/... controlling and
 * data analysis software
 *
 * Gxsm Plugin Name: uksoft2001_im_export.C
 * ========================================
 * 
 * Copyright (C) 1999 The Free Software Foundation
 *
 * Authors: Percy Zahl <zahl@fkp.uni-hannover.de>
 * additional features: Andreas Klust <klust@fkp.uni-hannover.de>
 *
 * 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.
 */

/* Please do not change the Begin/End lines of this comment section!
 * this is a LaTeX style section used for auto generation of the PlugIn Manual 
 * Chapter. Add a complete PlugIn documentation inbetween the Begin/End marks!
 * --------------------------------------------------------------------------------
% BeginPlugInDocuSection
% PlugInDocuCaption: UKSOFT/U-view Import (ELMITEC LEEM)
% PlugInName: uksoft2001_im_Export
% PlugInAuthor: Percy Zahl
% PlugInAuthorEmail: zahl@users.sf.net
% PlugInMenuPath: File/Import/UKSOFT

% PlugInDescription
The \GxsmEmph{uksoft\_im\_export} plug-in allows importing of single
and multidimensional sets of \GxsmFile{.dat} and multiple image/movie
\GxsmFile{.dav} files in the UKSOFT-2001 data format generated by
U-view/Elmitec-LEEM Control Software.

It is recommended to configure \GxsmPref{Instrument}{Type} to ''CCD''
to make use of a simplified CCD-Hi/Low scaling method. Use the
''Direct'' view mode.

% PlugInUsage
The plug-in is called by \GxsmMenu{File/Import/UKSOFT}.
Select a single \GxsmFile{.dat} or \GxsmFile{.dav} file.

For automatic reading of multidimensional image series the files has
to be in one director and the file names have to be numbered in one or
two dimensions like this or similar:

\begin{verbatim}
RuO2_CO_10mu_000_000.dat
RuO2_CO_10mu_000_001.dat
RuO2_CO_10mu_000_002.dat
RuO2_CO_10mu_001_000.dat
RuO2_CO_10mu_001_001.dat
RuO2_CO_10mu_001_002.dat
...
\end{verbatim}


Select the first file and replace the relevant digits by a valid
integer C format string identifier, i.e.:
\GxsmNote{GTK3: use CTRL-L after selecting a file to allow (show the edit field) edit the file pattern!!}

\begin{verbatim}
RuO2_CO_10mu_%03d_%03d.dat
\end{verbatim}

Click OK and the Multi-File import setup dialog will show up. Setup
the number of images for each dimension (Max Index) to read and use
Offset and Step for optional skipping of images. If only one index is
present, it is assumed to be the Layer (Value) dimension.

\GxsmScreenShotDual{UKSOFT2001_file_dialog}{UKSOFT/U-view import file dialog}{UKSOFT2001_multifile}{ setup for multi dimensional image processing}

%% OptPlugInKnownBugs

%% OptPlugInRefs


% EndPlugInDocuSection
 * -------------------------------------------------------------------------------- 
 */

#include <gtk/gtk.h>
#include "config.h"
#include "plugin.h"
#include "dataio.h"
#include "action_id.h"
#include "util.h"
#include "xsmtypes.h"
#include "glbvars.h"
#include "surface.h"
#include "gapp_service.h"

// custom includes go here
// -- START EDIT --
// -- END EDIT --

// File header UKSOFT -- size: 104
typedef struct {
	gchar id[20];
	gint16 size;
	gint16 version;
	gint16 BitsPerPixel;
	gchar  align8[6];
	gint64 starttime;
	gint16 ImageWidth, ImageHeight;
	gint16 NrImages;
	gint16 spareShort;
	gchar spare[56];
} UKSOFT2001_FileHeader;

// Image header UKSOFT -- size: 48  -- fileheader.version < 5
typedef struct {
	gint16 size;
	gint16 version;
	gchar  align8[4];
	gint64 imagetime;
	gint32 LEEMdata1_source;
	gfloat LEEMdata1_data;
	gint16 spin;
	gint16 spareShort;
	gfloat LEEMdata2_data;
	gchar spare[16];
} UKSOFT2001_ImageHeader_lsv5;

// Image header UKSOFT -- size: 288  -- fileheader.version >= 5
typedef struct {
	gint16 size;
	gint16 version;
	gchar  align8[4];
	gint64 imagetime;
	gchar spare[8];
	gint16 spin;
	gint16 LEEMdataVersion;
	gchar LEEMdata[256];
	gchar space[4];
} UKSOFT2001_ImageHeader_gev5;

// Image header UKSOFT -- size: 288  -- fileheader.version >= 8
typedef struct {
	gint16 size;          // @20
	gint16 version;       //  22
	gchar  align8[4];     //  24
	gint64 imagetime;     //  28
	gchar  spare[8];      //  36
	gint16 spin;          //  44
	gint16 LEEMdataVersion; // 46
	gchar LEEMdata[256];
	gchar space[4];
} UKSOFT2001_ImageHeader_gev8;

typedef struct {
	unsigned char source;
	gchar arg[64];
} UKSOFT2001_LEEMData;


static inline guint16 swap_u16 (guint16 x){
        return ((x & 0xff) << 8) | ((x >> 8) & 0xff);
}

static inline guint32 swap_u32 (guint32 x){
        return ((x & 0xff) << 24) | (((x >> 8)  & 0xff) << 16) | (((x >> 16) & 0xff) << 8) | ((x >> 24) & 0xff);
}

static inline guint64 swap_u64 (guint64 x){
        return ( (((x      ) & 0xff) << 56) | (((x >>  8)  & 0xff) << 48) | (((x >> 16) & 0xff) << 40) | (((x >> 24) & 0xff) << 32)	
	       | (((x >> 32) & 0xff) << 24) | (((x >> 40)  & 0xff) << 16) | (((x >> 48) & 0xff) <<  8) | (((x >> 56) & 0xff)      ) );
}
// -mno-strict-align ??? 
static inline gfloat check_and_swap_float (gfloat *x){
	if (WORDS_BIGENDIAN){
		guint32 u32 = * ((guint32*)x);
		gfloat   f;
		u32 = swap_u32 (u32);
		f = * ((gfloat*)(&u32));
		return f;
	} else return *x;
}


// Still Image:
// Fileheader, Imageheader, Imagedatablock [WxH shorts]

// Video Image Sequence:
// Fileheader, Imageheader_1, Imagedatablock_1 [WxH shorts], ...,  Imageheader_n, Imageblock_n

// enable std namespace
using namespace std;

// Plugin Prototypes
static void uksoft2001_im_export_init (void);
static void uksoft2001_im_export_query (void);
static void uksoft2001_im_export_about (void);
static void uksoft2001_im_export_configure (void);
static void uksoft2001_im_export_cleanup (void);

static void uksoft2001_im_export_filecheck_load_callback (gpointer data );
static void uksoft2001_im_export_filecheck_save_callback (gpointer data );

static void uksoft2001_im_export_import_callback (GSimpleAction *simple, GVariant *parameter, gpointer user_data);
static void uksoft2001_im_export_export_callback (GSimpleAction *simple, GVariant *parameter, gpointer user_data);

// Fill in the GxsmPlugin Description here
GxsmPlugin uksoft2001_im_export_pi = {
  NULL,                   // filled in and used by Gxsm, don't touch !
  NULL,                   // filled in and used by Gxsm, don't touch !
  0,                      // filled in and used by Gxsm, don't touch !
  NULL,                   // The Gxsm-App Class Ref.pointer (called "gapp" in Gxsm) is 
                          // filled in here by Gxsm on Plugin load, 
                          // just after init() is called !!!
// -- START EDIT --
  "UKSOFT2001-ImExport",            // PlugIn name
  NULL,                   // PlugIn's Categorie, set to NULL for all, I just don't want this always to be loaded!
  // Description, is shown by PluginViewer (Plugin: listplugin, Tools->Plugin Details)
  NULL,
  "Percy Zahl",
  "file-import-section,file-export-section", // sep. im/export menuentry path by comma!
  N_("UKSOFT-LEEM,UKSOFT-LEEM"), // menu entry (same for both)
  N_("UKSOFT import (LEEM LOAD: use CRTL-L to edit. May use ..%03d.. for indexed multi frame loading), UKSOFT export (SAVE)"), // short help for menu entry
  N_("UKSOFT 2001/UView import filter (Elimtec LEEM 2001-2016)."), // info
// -- END EDIT --
  NULL,          // error msg, plugin may put error status msg here later
  NULL,          // Plugin Status, managed by Gxsm, plugin may manipulate it too
  uksoft2001_im_export_init,
  uksoft2001_im_export_query,
  // about-function, can be "NULL"
  // can be called by "Plugin Details"
  uksoft2001_im_export_about,
  // configure-function, can be "NULL"
  // can be called by "Plugin Details"
  uksoft2001_im_export_configure,
  // run-function, can be "NULL", if non-Zero and no query defined, 
  // it is called on menupath->"plugin"
  NULL,
  // cleanup-function, can be "NULL"
  // called if present at plugin removal
  uksoft2001_im_export_import_callback, // direct menu entry callback1 or NULL
  uksoft2001_im_export_export_callback, // direct menu entry callback2 or NULL

  uksoft2001_im_export_cleanup
};

// Text used in Aboutbox, please update!!
static const char *about_text = N_("This GXSM plugin imports UKSOFT2001 (UView) image data files (CCD/ELMITEC-LEEM)");

static const char *file_mask = "*.da[tv]";

int offset_index_value=0;
int step_index_value=1;
int max_index_value=1;
double start_value=0.;
double step_value=1.;

int offset_index_time=0;
int step_index_time=1;
int max_index_time=1;
double start_time=0.;
double step_time=1.;

double realtime0=0.;
double realtime0_user=0.;

double Temp_Offset=0.;

#define FILE_DIM_V 0x01
#define FILE_DIM_T 0x02
#define FILE_DIM_VIDEO 0x04
int file_dim=0;

// Symbol "get_gxsm_plugin_info" is resolved by dlsym from Gxsm, used to get Plugin's info!! 
// Essential Plugin Function!!
GxsmPlugin *get_gxsm_plugin_info ( void ){ 
  uksoft2001_im_export_pi.description = g_strdup_printf(N_("Gxsm im_export plugin %s"), VERSION);
  return &uksoft2001_im_export_pi; 
}

// Query Function, installs Plugin's in File/Import and Export Menupaths!
// ----------------------------------------------------------------------
// Import Menupath is "File/Import/PNG"
// Export Menupath is "File/Export/PNGt"
// ----------------------------------------------------------------------

static void uksoft2001_im_export_query(void)
{

	if(uksoft2001_im_export_pi.status) g_free(uksoft2001_im_export_pi.status); 
	uksoft2001_im_export_pi.status = g_strconcat (
		N_("Plugin query has attached "),
		uksoft2001_im_export_pi.name, 
		N_(": File IO Filters are ready to use."),
		NULL);
	
	// register this plugins filecheck functions with Gxsm now!
	// This allows Gxsm to check files from DnD, open, 
	// and cmdline sources against all known formats automatically - no explicit im/export is necessary.
	uksoft2001_im_export_pi.app->ConnectPluginToLoadFileEvent (uksoft2001_im_export_filecheck_load_callback);
	//	uksoft2001_im_export_pi.app->ConnectPluginToSaveFileEvent (uksoft2001_im_export_filecheck_save_callback);
}


// 5.) Start here with the plugins code, vars def., etc.... here.
// ----------------------------------------------------------------------
//


// init-Function
static void uksoft2001_im_export_init(void)
{
	PI_DEBUG (DBG_L2, uksoft2001_im_export_pi.name << " Plugin Init");
}

// about-Function
static void uksoft2001_im_export_about(void)
{
	const gchar *authors[] = { uksoft2001_im_export_pi.authors, NULL};
	gtk_show_about_dialog (NULL,
			       "program-name",  uksoft2001_im_export_pi.name,
			       "version", VERSION,
			       "license", GTK_LICENSE_GPL_3_0,
			       "comments", about_text,
			       "authors", authors,
			       NULL
			       );
}

// configure-Function
static void uksoft2001_im_export_configure(void)
{
	if(uksoft2001_im_export_pi.app){
		XsmRescourceManager xrm("UKSOFT2001_IM_EXPORT");

		xrm.Get ("file_max_index_value", &max_index_value, "1");
		xrm.Get ("file_offset_index_value", &offset_index_value, "0");
		xrm.Get ("file_step_index_value", &step_index_value, "1");
		xrm.Get ("file_start_value", &start_value, "0");
		xrm.Get ("file_step_value", &step_value, "1");

		xrm.Get ("file_max_index_time", &max_index_time, "1");
		xrm.Get ("file_offset_index_time", &offset_index_time, "0");
		xrm.Get ("file_step_index_time", &step_index_time, "1");
		xrm.Get ("file_start_time", &start_time, "0");
		xrm.Get ("file_step_time", &step_time, "1");

		xrm.Get ("file_realttime0_user", &realtime0_user, "0.");
		xrm.Get ("file_temp_offset_user", &Temp_Offset, "0.");

		GtkDialogFlags flags =  (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT);
		GtkWidget *dialog = gtk_dialog_new_with_buttons (N_("UKSoft 2001 Multi Image Import"),
								 GTK_WINDOW (main_get_gapp()->get_app_window ()),
								 flags,
								 _("_OK"),
								 GTK_RESPONSE_ACCEPT,
								 _("_Cancel"),
								 GTK_RESPONSE_REJECT,
								 NULL);
		BuildParam bp;
		gtk_box_append (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), bp.grid);

		if (file_dim & FILE_DIM_V){
                        bp.grid_add_ec ("Max Index Values", uksoft2001_im_export_pi.app->xsm->Unity, &max_index_value, 1., 1e6, ".0f"); bp.new_line ();
			bp.grid_add_ec ("Index Offset", uksoft2001_im_export_pi.app->xsm->Unity, &offset_index_value, -1e6, 1e6, ".0f"); bp.new_line ();
			bp.grid_add_ec ("Index Step", uksoft2001_im_export_pi.app->xsm->Unity, &step_index_value, -1000, 1000, ".0f"); bp.new_line ();
			bp.grid_add_ec ("Start Value", uksoft2001_im_export_pi.app->xsm->Unity, &start_value, -1e6, 1e6, ".3f"); bp.new_line ();
			bp.grid_add_ec ("Step Value", uksoft2001_im_export_pi.app->xsm->Unity, &step_value, -1e6, 1e6, ".3f"); bp.new_line ();
		}		

		if (file_dim & FILE_DIM_T){
			bp.grid_add_ec ("Max Index Times", uksoft2001_im_export_pi.app->xsm->Unity, &max_index_time, 1., 1e6, ".0f"); bp.new_line ();
			bp.grid_add_ec ("Index Offset", uksoft2001_im_export_pi.app->xsm->Unity, &offset_index_time, -1e6, 1e6, ".0f"); bp.new_line ();
			bp.grid_add_ec ("Index Step", uksoft2001_im_export_pi.app->xsm->Unity, &step_index_time, -1000, 1000, ".0f"); bp.new_line ();
			bp.grid_add_ec ("Start Time", uksoft2001_im_export_pi.app->xsm->Unity, &start_time, -1e6, 1e6, ".3f"); bp.new_line ();
			bp.grid_add_ec ("Step Time", uksoft2001_im_export_pi.app->xsm->Unity, &step_time, -1e6, 1e6, ".3f"); bp.new_line ();
		}		
		bp.grid_add_ec ("Time Origin", uksoft2001_im_export_pi.app->xsm->TimeUnit, &realtime0_user, 0., 1e20, ".1f"); bp.new_line ();

		if (file_dim & FILE_DIM_VIDEO){
		}

		gtk_widget_show (dialog);

                int response = GTK_RESPONSE_NONE;
                g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (GnomeAppService::on_dialog_response_to_user_data), &response);
        
                // FIX-ME GTK4 ??
                // wait here on response
                while (response == GTK_RESPONSE_NONE)
                        while(g_main_context_pending (NULL)) g_main_context_iteration (NULL, FALSE);

		xrm.Put ("file_max_index_value", max_index_value);
		xrm.Put ("file_offset_index_value", offset_index_value);
		xrm.Put ("file_step_index_value", step_index_value);
		xrm.Put ("file_start_value", start_value);
		xrm.Put ("file_step_value", step_value);

		xrm.Put ("file_max_index_time", max_index_time);
		xrm.Put ("file_offset_index_time", offset_index_time);
		xrm.Put ("file_step_index_time", step_index_time);
		xrm.Put ("file_start_time", start_time);
		xrm.Put ("file_step_time", step_time);

		xrm.Put ("file_realttime0_user", realtime0_user);
		xrm.Put ("file_temp_offset_user", Temp_Offset);
	}
}

// cleanup-Function, remove all "custom" menu entrys here!
static void uksoft2001_im_export_cleanup(void)
{
#if 0
	gchar **path  = g_strsplit (uksoft2001_im_export_pi.menupath, ",", 2);
	gchar **entry = g_strsplit (uksoft2001_im_export_pi.menuentry, ",", 2);

	gchar *tmp = g_strconcat (path[0], entry[0], NULL);
	gnome_app_remove_menus (GNOME_APP (uksoft2001_im_export_pi.app->getApp()), tmp, 1);
	g_free (tmp);

# if 0
	tmp = g_strconcat (path[1], entry[1], NULL);
	gnome_app_remove_menus (GNOME_APP (uksoft2001_im_export_pi.app->getApp()), tmp, 1);
	g_free (tmp);
# endif

	g_strfreev (path);
	g_strfreev (entry);
#endif
	PI_DEBUG (DBG_L2, "Plugin Cleanup done.");
}


// make a new derivate of the base class "Dataio"
class Uksoft2001_ImExportFile : public Dataio{
public:
	Uksoft2001_ImExportFile(Scan *s, const char *n); 
	virtual ~Uksoft2001_ImExportFile();
	virtual FIO_STATUS Read(xsm::open_mode mode=xsm::open_mode::replace);
	virtual FIO_STATUS Write();
private:
	FIO_STATUS import_data(const char *fname, int index_value=0, int index_time=0); 
	GString *FileList;
};

Uksoft2001_ImExportFile::Uksoft2001_ImExportFile(Scan *s, const char *n) : Dataio(s,n){
	FileList=NULL;
}

Uksoft2001_ImExportFile::~Uksoft2001_ImExportFile(){
	if (FileList){
		g_string_free(FileList, TRUE); 
		FileList=NULL;
	}
}

FIO_STATUS Uksoft2001_ImExportFile::Read(xsm::open_mode mode){
	FIO_STATUS ret;
	gchar *fname=NULL;

	PI_DEBUG (DBG_L2, "reading");

	fname = (gchar*)name;

	// name should have at least 4 chars: ".ext"
	if (fname == NULL || strlen(fname) < 4)
		return status=FIO_NOT_RESPONSIBLE_FOR_THAT_FILE;

	if (strncasecmp (fname+strlen(fname)-4,".dat", 4) && strncasecmp (fname+strlen(fname)-4,".dav", 4))
		return status=FIO_NOT_RESPONSIBLE_FOR_THAT_FILE;

	realtime0=0.;
	file_dim=0;
	if (strchr (fname, '%')){
		file_dim |= FILE_DIM_V;

		gchar *tmp = g_strdup(fname);
		* (strchr (tmp, '%')) = 'X';
		if (strchr (tmp, '%'))
			file_dim |= FILE_DIM_T;

		int index_time=0;
		ret=FIO_OK;
		uksoft2001_im_export_configure ();
		main_get_gapp()->progress_info_new ("UKSOFT 2001 Multi CCD Data Import", 2);
		main_get_gapp()->progress_info_set_bar_fraction (0., 1);
		main_get_gapp()->progress_info_set_bar_fraction (0., 2);
		main_get_gapp()->progress_info_set_bar_text (fname, 1);
		do {
			int index_value=0;
			main_get_gapp()->progress_info_set_bar_fraction ((gdouble)index_time/(gdouble)max_index_time, 1);
			do {
				gchar *fname_expand=NULL;
				ifstream f;
				if (file_dim == 1){
					fname_expand = g_strdup_printf (fname, index_value*step_index_value+offset_index_value);
					max_index_time = 1;
				} else
					fname_expand = g_strdup_printf (fname, 
									index_time*step_index_time+offset_index_time,
									index_value*step_index_value+offset_index_value);
				main_get_gapp()->progress_info_set_bar_fraction ((gdouble)(index_value+1)/(gdouble)max_index_value, 2);
				main_get_gapp()->progress_info_set_bar_text (fname_expand, 2);
				f.open(fname_expand, ios::in);
				if(!f.good()){
					cout << "UKSOFT::: ERROR while processing file >" << fname_expand << "< -- Multi File Import Aborted." << endl;
					PI_DEBUG (DBG_L2, "Error at file open. File not good/readable.");
					main_get_gapp()->progress_info_close ();
					return status=FIO_OPEN_ERR;
				}
				f.close();
				
				// Check all known File Types:
				ret = import_data (fname_expand, index_value, index_time);
				g_free (fname_expand);
				++index_value;
				
			} while (ret == FIO_OK && index_value < max_index_value);

//			cout << "UKSOFT::: appending in time " << index_time << endl;
			scan->append_current_to_time_elements (index_time, start_time + step_time*(index_time));
			scan->mem2d->remove_layer_information ();
			++index_time;

		} while (ret == FIO_OK && index_time < max_index_time);
		main_get_gapp()->progress_info_close ();
		scan->retrieve_time_element (0);
		scan->SetVM(SCAN_V_DIRECT);
		return ret;

	} else {
		// check for file exists and is OK !
		// else open File Dlg
		ifstream f;
		f.open(fname, ios::in);
		if(!f.good()){
			PI_DEBUG (DBG_L2, "Error at file open. File not good/readable.");
			return status=FIO_OPEN_ERR;
		}
		f.close();
		scan->SetVM(SCAN_V_DIRECT);
		
		// Check all known File Types:
		if ((ret=import_data (fname)) !=  FIO_NOT_RESPONSIBLE_FOR_THAT_FILE)
			return ret;
		
	}
	return  status=FIO_NOT_RESPONSIBLE_FOR_THAT_FILE;
}

FIO_STATUS Uksoft2001_ImExportFile::import_data(const char *fname, int index_value, int index_time){
	int image_number=0, image_index=0; 
	int skip=0, video=0;
	ifstream f;
	UKSOFT2001_FileHeader uks_fileheader;
	UKSOFT2001_ImageHeader_lsv5 uks_imageheader_lsv5;
	UKSOFT2001_ImageHeader_gev5 uks_imageheader_gev5;
	UKSOFT2001_ImageHeader_gev8 uks_imageheader_gev8;
	gchar *error_msg = NULL;

	// specific LEEM2000 data taken from header
	double ImageTime    = 0.; // ImageTime [???]
	double StartVoltage = 0.; // #Module #38 [V]
	double Temperatur   = 0.; // #Module #39 [C]
	double Pressure11   = 0.; // #Varian #106 [Torr]
	double FieldOfView  = 10.; // #FOV #110 [um]
	int FOV_assumed=0;
	double IllumDeflX   = 0.; // #2 Illumination Deflect. X [mA]
	double IllumDeflY   = 0.; // #3 Illumination Deflect. Y [mA]
	
	f.open(fname, ios::in);
	if(!f.good())
		return FIO_OPEN_ERR;

	// Checking resposibility for this file as good as possible, use
	// extension(s) (most simple), magic numbers, etc.

//	cout << "UKSOFT::: importing from >" << fname << "< [" << index_value << ", " << index_time << "]" << endl;
	PI_DEBUG (DBG_L2, "importing from >" << fname << "< [" << index_value << ", " << index_time << "]");

//	cout << "UKSOFT::: reading header" << endl;
	// now start importing -----------------------------------------

	f.read((char*)&uks_fileheader, sizeof(uks_fileheader)); // read header

// file type sanity check
	if(! strncmp (uks_fileheader.id, "[Parameter]", 11)){ // check GME type, skip, do not complain!
		f.close ();
		return FIO_NOT_RESPONSIBLE_FOR_THAT_FILE;
	}
	if(! strncmp (uks_fileheader.id, "[Paramco32]", 11)){ // check GME type, skip, do not complain!
		f.close ();
		return FIO_NOT_RESPONSIBLE_FOR_THAT_FILE;
	}
	if( strncmp (uks_fileheader.id, "UKSOFT2001", 10)){ // check version and type
		uks_fileheader.id[19]=0; // for safety
		error_msg = g_strdup_printf (N_("[%s] is not a UKSOFT2001 file: incorrect signature [%s]"), fname, uks_fileheader.id);

		GtkWidget *dialog = gtk_message_dialog_new (NULL,
							    GTK_DIALOG_DESTROY_WITH_PARENT,
							    GTK_MESSAGE_INFO,
							    GTK_BUTTONS_OK,
							    "%s", error_msg);
		cout << error_msg << endl;

                gtk_widget_show (dialog);

                int response = GTK_RESPONSE_NONE;
                g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (GnomeAppService::on_dialog_response_to_user_data), &response);
        
                // FIX-ME GTK4 ??
                // wait here on response
                while (response == GTK_RESPONSE_NONE)
                        while(g_main_context_pending (NULL)) g_main_context_iteration (NULL, FALSE);

		g_free (error_msg);
		f.close ();
		return FIO_NOT_RESPONSIBLE_FOR_THAT_FILE;
	}

	if (WORDS_BIGENDIAN){
		uks_fileheader.size    = swap_u16(uks_fileheader.size);
		uks_fileheader.version = swap_u16(uks_fileheader.version);
		uks_fileheader.BitsPerPixel = swap_u16(uks_fileheader.BitsPerPixel);
		uks_fileheader.starttime   = swap_u64(uks_fileheader.starttime);
		uks_fileheader.ImageWidth  = swap_u16(uks_fileheader.ImageWidth);
		uks_fileheader.ImageHeight = swap_u16(uks_fileheader.ImageHeight);
		uks_fileheader.NrImages    = swap_u16(uks_fileheader.NrImages);
		uks_fileheader.spareShort  = swap_u16(uks_fileheader.spareShort);
	}

	if (!strncasecmp (fname+strlen(fname)-4,".dav", 4)){
		file_dim |= FILE_DIM_T;
		video=1;
		uksoft2001_im_export_configure ();
		max_index_value = 1;
		main_get_gapp()->progress_info_new ("UKSOFT 2001 CCD Video Import", 1);
		main_get_gapp()->progress_info_set_bar_text (fname, 1);
		uks_fileheader.NrImages = max_index_time;
		skip = step_index_time-1;
	}
 
	for (image_number = 0; image_number < uks_fileheader.NrImages && f.good(); ++image_number){

		if (video)
			main_get_gapp()->progress_info_set_bar_fraction ((gdouble)(image_number+1)/(gdouble)max_index_time, 1);

		if (uks_fileheader.version < 5){
			f.read((char*)&uks_imageheader_lsv5, sizeof(uks_imageheader_lsv5)); // read image header
			if (WORDS_BIGENDIAN){
				uks_imageheader_lsv5.size    = swap_u16(uks_imageheader_lsv5.size);
				uks_imageheader_lsv5.version = swap_u16(uks_imageheader_lsv5.version);
				uks_imageheader_lsv5.imagetime = swap_u64(uks_imageheader_lsv5.imagetime);
				uks_imageheader_lsv5.spin    = swap_u16(uks_imageheader_lsv5.spin);
			}
		} else if (uks_fileheader.version < 8) {
			f.read((char*)&uks_imageheader_gev5, sizeof(uks_imageheader_gev5)); // read image header
			if (WORDS_BIGENDIAN){
				uks_imageheader_gev5.size    = swap_u16(uks_imageheader_gev5.size);
				uks_imageheader_gev5.version = swap_u16(uks_imageheader_gev5.version);
				uks_imageheader_gev5.imagetime = swap_u64(uks_imageheader_gev5.imagetime);
			uks_imageheader_gev5.spin    = swap_u16(uks_imageheader_gev5.spin);
				uks_imageheader_gev5.LEEMdataVersion = swap_u16(uks_imageheader_gev5.LEEMdataVersion);
			}
		} else {
			f.read((char*)&uks_imageheader_gev8, sizeof(uks_imageheader_gev8)); // read image header
			if (WORDS_BIGENDIAN){
				uks_imageheader_gev8.size    = swap_u16(uks_imageheader_gev8.size);
				uks_imageheader_gev8.version = swap_u16(uks_imageheader_gev8.version);
				uks_imageheader_gev8.imagetime = swap_u64(uks_imageheader_gev8.imagetime);
				uks_imageheader_gev8.spin    = swap_u16(uks_imageheader_gev8.spin);
				uks_imageheader_gev8.LEEMdataVersion = swap_u16(uks_imageheader_gev8.LEEMdataVersion);
			}
			gint16 fhsize, recipesize, imageheadersize, markupsize, leemdatasize;
			f.seekg(20, ios::beg); f.read((char*)&fhsize, sizeof(fhsize)); if (WORDS_BIGENDIAN) fhsize = swap_u16(fhsize);
			f.seekg(46, ios::beg); f.read((char*)&recipesize, sizeof(recipesize)); if (WORDS_BIGENDIAN) recipesize = swap_u16(recipesize);
			f.seekg(104+recipesize, ios::beg); f.read((char*)&imageheadersize, sizeof(imageheadersize)); if (WORDS_BIGENDIAN) imageheadersize = swap_u16(imageheadersize);
			f.seekg(104+recipesize+22, ios::beg); f.read((char*)&markupsize, sizeof(markupsize)); if (WORDS_BIGENDIAN) markupsize = swap_u16(markupsize); 
			markupsize= 128*((markupsize/128)+1);
			f.seekg(104+recipesize+26, ios::beg); f.read((char*)&leemdatasize, sizeof(leemdatasize)); if (WORDS_BIGENDIAN) leemdatasize = swap_u16(leemdatasize);
			int TotalSizeOfHeader=fhsize+recipesize+imageheadersize+markupsize;
			if(leemdatasize>2) TotalSizeOfHeader=TotalSizeOfHeader+leemdatasize;
			f.seekg(TotalSizeOfHeader, ios::beg); // now at image data start -- FuckingBSdesign o]
			if (index_value == 0 && index_time == 0) { std::cout << "pre-check ** UKS-Image HEADER >= V8 detected, TotalSizeOfHeader=" << TotalSizeOfHeader << std::endl; }
		}

		int pflg = (index_value == 0 && index_time == 0);

#define PRINT_HDR_INFO(X) { if (pflg) { cout << X << endl; } }

		if (1){
			PRINT_HDR_INFO ("UKS-Image Number....:" << image_number);
			PRINT_HDR_INFO ("UKS-FH: ***sizeof***=" << sizeof(uks_fileheader));
			PRINT_HDR_INFO ("UKS-FH: Id          =" << uks_fileheader.id);
			PRINT_HDR_INFO ("UKS-FH: Size        =" << uks_fileheader.size);
			PRINT_HDR_INFO ("UKS-FH: Version     =" << uks_fileheader.version);
			PRINT_HDR_INFO ("UKS-FH: BitsPerPixel=" << uks_fileheader.BitsPerPixel);
			PRINT_HDR_INFO ("UKS-FH: starttime   =" << uks_fileheader.starttime);
			PRINT_HDR_INFO ("UKS-FH: ImageWidth  =" << uks_fileheader.ImageWidth);
			PRINT_HDR_INFO ("UKS-FH: ImageHeight =" << uks_fileheader.ImageHeight);
			PRINT_HDR_INFO ("UKS-FH: NrImages    =" << uks_fileheader.NrImages);
			PRINT_HDR_INFO ("UKS-FH: spareShort  =" << uks_fileheader.spareShort);
			if (uks_fileheader.version < 5){
				PRINT_HDR_INFO ("UKS-IH*: ***sizeof**=" << sizeof(uks_imageheader_lsv5));
				PRINT_HDR_INFO ("UKS-IH*: Size       =" << uks_imageheader_lsv5.size);
				PRINT_HDR_INFO ("UKS-IH*: Version    =" << uks_imageheader_lsv5.version);
				PRINT_HDR_INFO ("UKS-IH*: imagetime  =" << uks_imageheader_lsv5.imagetime);
				ImageTime = (double)uks_imageheader_lsv5.imagetime;
			} else if (uks_fileheader.version < 8){

				PRINT_HDR_INFO ("UKS-IH: ***sizeof***=" << sizeof(uks_imageheader_gev5));
				PRINT_HDR_INFO ("UKS-IH: Size        =" << uks_imageheader_gev5.size);
				PRINT_HDR_INFO ("UKS-IH: Version     =" << uks_imageheader_gev5.version);
				PRINT_HDR_INFO ("UKS-IH: imagetime   =" << uks_imageheader_gev5.imagetime);
				PRINT_HDR_INFO ("UKS-IH: spin        =" << uks_imageheader_gev5.spin);
				PRINT_HDR_INFO ("UKS-IH: LEEMdataVers=" << uks_imageheader_gev5.LEEMdataVersion);
				ImageTime = (double)(uks_imageheader_gev5.imagetime - 128137000000000000LL); // willkuerlicher offset
				UKSOFT2001_LEEMData *ld;
				gchar *ld_ptr = (gchar*)&(uks_imageheader_gev5.LEEMdata);
				gchar *ld_ptr_end = ld_ptr + 256;
				for (ld = (UKSOFT2001_LEEMData*) ld_ptr; ld_ptr < ld_ptr_end; ++ld_ptr){
					size_t l, l2;
					float* xy;
					ld = (UKSOFT2001_LEEMData*) ld_ptr;
// 					if (ld->source < 0xff){
// 						for (int hx=0; hx<16; ++hx) cout << ((int)(*((unsigned char*)(&(ld->source) + hx)))) << " "; 
// 						cout << endl;
// 						for (int hx=0; hx<16; ++hx){
// 							float ff;
// 							xy = (float*)(&(ld->source) + hx);
// 							ff = check_and_swap_float (&xy[0]);
// 							cout << ff << " "; 
// 						}
// 						cout << endl;
// 					}
					switch (ld->source){
					case 0xff: 
						break;
					case 100:
						xy = (float*) (ld->arg);
						xy[0] = check_and_swap_float (&xy[0]);
						xy[1] = check_and_swap_float (&xy[1]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Micrometer XY: " << xy[0] << ", " << xy[1]);
						ld_ptr += 2*sizeof(float);
						break;
					case 101:
						l = strlen(ld->arg)+1;
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] FOV: " << ld->arg);
						ld_ptr += l;
						break;
					case 102:
						xy = (float*) (ld->arg);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Varian Gauge #1: " << xy[0]);
						ld_ptr += 1*sizeof(float);
						break;
					case 103:
						xy = (float*) (ld->arg);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Varian Gauge #2: " << xy[0]);
						ld_ptr += 1*sizeof(float);
						break;
					case 104:
						xy = (float*) (ld->arg);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Camera Exposure Time [ms]: " << xy[0]);
						ld_ptr += 1*sizeof(float);
						break;
					case 105:
						l = strlen(ld->arg)+1;
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Title: " << ld->arg);
						ld_ptr += l;
						break;
					case 106:
						l = strlen(ld->arg)+1;
						l2 = strlen(ld->arg + l)+1;
						xy = (float*) (ld->arg + l + l2);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Varian#1 Gauge#1: " << ld->arg << "[" << (ld->arg + l) << "]: " << xy[0]);
						Pressure11 = xy[0]; // #Varian #106 [Torr]
						ld_ptr += l + l2 + sizeof(float);
						break;
					case 107:
						l = strlen(ld->arg)+1;
						l2 = strlen(ld->arg + l)+1;
						xy = (float*) (ld->arg + l + l2);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Varian#1 Gauge#2: " << ld->arg << "[" << (ld->arg + l) << "]: " << xy[0]);
						ld_ptr += l + l2 + sizeof(float);
						break;
					case 108:
						l = strlen(ld->arg)+1;
						l2 = strlen(ld->arg + l)+1;
						xy = (float*) (ld->arg + l + l2);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Varian#2 Gauge#1: " << ld->arg << "[" << (ld->arg + l) << "]: " << xy[0]);
						ld_ptr += l + l2 + sizeof(float);
						break;
					case 109:
						l = strlen(ld->arg)+1;
						l2 = strlen(ld->arg + l)+1;
						xy = (float*) (ld->arg + l + l2);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Varian#2 Gauge#2: " << ld->arg << "[" << (ld->arg + l) << "]: " << xy[0]);
						ld_ptr += l + l2 + sizeof(float);
						break;
					case 110:
						l = strlen(ld->arg)+1;
						xy = (float*) (ld->arg + l);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] FOV, Camera to FOV cal. factor: " << ld->arg << ", " << xy[0]);
						FieldOfView = atof (ld->arg); // #FOV #110 [um]
						if (FieldOfView < 0.1){ // some files are messed up w FOV=0, assume 10um.
							FieldOfView = 10.;
							FOV_assumed = 1;
						}
						ld_ptr += l + sizeof(float);
						break;
					case 111:
						xy = (float*) (ld->arg);
						xy[0] = check_and_swap_float (&xy[0]);
						xy[1] = check_and_swap_float (&xy[1]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Phi, Theta: " << xy[0] << ", " << xy[1]);
						ld_ptr += 2*sizeof(float);
						break;
					default: 
						if(ld->source < 100){
							l = strlen(ld->arg)+1;
							xy = (float*) (ld->arg + l);
							xy[0] = check_and_swap_float (&xy[0]);
							PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] LEEM2000 module#"<< (int)(ld->source) << " '" << ld->arg << "': " << xy[0]);

							if (ld->source == 2)
								IllumDeflX = xy[0]; // #Module #2 [mA]
							if (ld->source == 3)
								IllumDeflY = xy[0]; // #Module #3 [mA]

							if (ld->source == 38)
								StartVoltage = xy[0]; // #Module #38 [V]

							if (ld->source == 39)
								Temperatur   = xy[0] + Temp_Offset; // #Module #39 [C] + User Temp. Offset

							ld_ptr += l + sizeof(float);
						} else
							PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] ??? (undocumented by 20070131) ");
						break;
					}
				}
			} else { // >= V8

				PRINT_HDR_INFO ("UKS-IH: ***sizeof***=" << sizeof(uks_imageheader_gev8));
				PRINT_HDR_INFO ("UKS-IH: Size        =" << uks_imageheader_gev8.size);
				PRINT_HDR_INFO ("UKS-IH: Version     =" << uks_imageheader_gev8.version);
				PRINT_HDR_INFO ("UKS-IH: imagetime   =" << uks_imageheader_gev8.imagetime);
				PRINT_HDR_INFO ("UKS-IH: spin        =" << uks_imageheader_gev8.spin);
				PRINT_HDR_INFO ("UKS-IH: LEEMdataVers=" << uks_imageheader_gev8.LEEMdataVersion);
				ImageTime = (double)(uks_imageheader_gev8.imagetime - 128137000000000000LL); // willkuerlicher offset
				UKSOFT2001_LEEMData *ld;
				gchar *ld_ptr = (gchar*)&(uks_imageheader_gev8.LEEMdata);
				gchar *ld_ptr_end = ld_ptr + 256;
				for (ld = (UKSOFT2001_LEEMData*) ld_ptr; ld_ptr < ld_ptr_end; ++ld_ptr){
					size_t l, l2;
					float* xy;
					ld = (UKSOFT2001_LEEMData*) ld_ptr;
// 					if (ld->source < 0xff){
// 						for (int hx=0; hx<16; ++hx) cout << ((int)(*((unsigned char*)(&(ld->source) + hx)))) << " "; 
// 						cout << endl;
// 						for (int hx=0; hx<16; ++hx){
// 							float ff;
// 							xy = (float*)(&(ld->source) + hx);
// 							ff = check_and_swap_float (&xy[0]);
// 							cout << ff << " "; 
// 						}
// 						cout << endl;
// 					}
					switch (ld->source){
					case 0xff: 
						break;
					case 100:
						xy = (float*) (ld->arg);
						xy[0] = check_and_swap_float (&xy[0]);
						xy[1] = check_and_swap_float (&xy[1]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Micrometer XY: " << xy[0] << ", " << xy[1]);
						ld_ptr += 2*sizeof(float);
						break;
					case 101:
						l = strlen(ld->arg)+1;
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] FOV: " << ld->arg);
						ld_ptr += l;
						break;
					case 102:
						xy = (float*) (ld->arg);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Varian Gauge #1: " << xy[0]);
						ld_ptr += 1*sizeof(float);
						break;
					case 103:
						xy = (float*) (ld->arg);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Varian Gauge #2: " << xy[0]);
						ld_ptr += 1*sizeof(float);
						break;
					case 104:
						xy = (float*) (ld->arg);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Camera Exposure Time [ms]: " << xy[0]);
						ld_ptr += 1*sizeof(float);
						break;
					case 105:
						l = strlen(ld->arg)+1;
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Title: " << ld->arg);
						ld_ptr += l;
						break;
					case 106:
						l = strlen(ld->arg)+1;
						l2 = strlen(ld->arg + l)+1;
						xy = (float*) (ld->arg + l + l2);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Varian#1 Gauge#1: " << ld->arg << "[" << (ld->arg + l) << "]: " << xy[0]);
						Pressure11 = xy[0]; // #Varian #106 [Torr]
						ld_ptr += l + l2 + sizeof(float);
						break;
					case 107:
						l = strlen(ld->arg)+1;
						l2 = strlen(ld->arg + l)+1;
						xy = (float*) (ld->arg + l + l2);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Varian#1 Gauge#2: " << ld->arg << "[" << (ld->arg + l) << "]: " << xy[0]);
						ld_ptr += l + l2 + sizeof(float);
						break;
					case 108:
						l = strlen(ld->arg)+1;
						l2 = strlen(ld->arg + l)+1;
						xy = (float*) (ld->arg + l + l2);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Varian#2 Gauge#1: " << ld->arg << "[" << (ld->arg + l) << "]: " << xy[0]);
						ld_ptr += l + l2 + sizeof(float);
						break;
					case 109:
						l = strlen(ld->arg)+1;
						l2 = strlen(ld->arg + l)+1;
						xy = (float*) (ld->arg + l + l2);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Varian#2 Gauge#2: " << ld->arg << "[" << (ld->arg + l) << "]: " << xy[0]);
						ld_ptr += l + l2 + sizeof(float);
						break;
					case 110:
						l = strlen(ld->arg)+1;
						xy = (float*) (ld->arg + l);
						xy[0] = check_and_swap_float (&xy[0]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] FOV, Camera to FOV cal. factor: " << ld->arg << ", " << xy[0]);
						FieldOfView = atof (ld->arg); // #FOV #110 [um]
						if (FieldOfView < 0.1){ // some files are messed up w FOV=0, assume 10um.
							FieldOfView = 10.;
							FOV_assumed = 1;
						}
						ld_ptr += l + sizeof(float);
						break;
					case 111:
						xy = (float*) (ld->arg);
						xy[0] = check_and_swap_float (&xy[0]);
						xy[1] = check_and_swap_float (&xy[1]);
						PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] Phi, Theta: " << xy[0] << ", " << xy[1]);
						ld_ptr += 2*sizeof(float);
						break;
					default: 
						if(ld->source < 100){
							l = strlen(ld->arg)+1;
							xy = (float*) (ld->arg + l);
							xy[0] = check_and_swap_float (&xy[0]);
							PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] LEEM2000 module#"<< (int)(ld->source) << " '" << ld->arg << "': " << xy[0]);

							if (ld->source == 2)
								IllumDeflX = xy[0]; // #Module #2 [mA]
							if (ld->source == 3)
								IllumDeflY = xy[0]; // #Module #3 [mA]

							if (ld->source == 38)
								StartVoltage = xy[0]; // #Module #38 [V]

							if (ld->source == 39)
								Temperatur   = xy[0] + Temp_Offset; // #Module #39 [C] + User Temp. Offset

							ld_ptr += l + sizeof(float);
						} else
							PRINT_HDR_INFO ("UKS-IH: LEEMdata[" << (int)(ld->source) << "] ??? (undocumented by 20070131) ");
						break;
					}
				}
			}
		}

		if (index_value == 0 && index_time == 0){
			// reset old scan fully to defaults
			SCAN_DATA scan_template;
//		        scan->data.CpUnits (scan_template);
			scan->data.GetScan_Param (scan_template);
			scan->data.GetUser_Info (scan_template);
			scan->data.GetDisplay_Param (scan_template);

			// update as much as we get...
			time_t t; // Scan - Startzeit eintragen 
			time(&t);
			gchar *tmp = g_strconcat ((ctime(&t)), " (Imported)", NULL); scan->data.ui.SetDateOfScan (tmp); g_free (tmp);
			scan->data.ui.SetName (name);
			scan->data.ui.SetOriginalName (name);
			scan->data.ui.SetType ("UKSOFT");
			scan->data.ui.SetUser ("nobody");
			if (FileList){
				g_string_free(FileList, TRUE); 
				FileList=NULL;
			}
			FileList = g_string_new ("Imported by GXSM from UKSOFT2001.\n");

			// Fill Scan Parameter
			scan->data.s.ntimes = max_index_time;
			scan->data.s.nvalues = max_index_value;

			XsmRescourceManager xrm("UKSOFT2001_IM_EXPORT");
			// assume this size 528 x 528 or 544x520 for 2x2 binning
			scan->data.s.nx = uks_fileheader.ImageWidth;
			scan->data.s.ny = uks_fileheader.ImageHeight;
			scan->data.s.dx = FieldOfView*1e4 / (scan->data.s.nx - 1);
			scan->data.s.dy = scan->data.s.dx; // Aspect 1:1 from Channelplate
			scan->data.s.dz = 1.;
			scan->data.s.rx = scan->data.s.nx*scan->data.s.dx;
			scan->data.s.ry = scan->data.s.ny*scan->data.s.dy;
			scan->data.s.rz = 4096.0;
			scan->data.s.x0 = 0;
			scan->data.s.y0 = 0;
			scan->data.s.alpha = 0.;
			scan->data.display.bright = 0.;
			scan->data.display.vrange_z = 4096.;
			scan->data.display.voffset_z = 0.;

			scan->data.s.GateTime   = 1.;
			scan->data.display.z_high         = 4096.;
			scan->data.display.z_low          = 0.;
  
			scan->mem2d->Resize (scan->data.s.nx, scan->data.s.ny, max_index_value, ZD_SHORT);
			scan->data.orgmode = SCAN_ORG_CENTER;
			scan->mem2d->data->MkXLookup (-scan->data.s.rx/2., scan->data.s.rx/2.);
			scan->mem2d->data->MkYLookup (scan->data.s.ry/2., -scan->data.s.ry/2.);
			scan->mem2d->data->MkVLookup (start_value, start_value+(max_index_value-1)*step_value);

			g_string_append_printf (FileList, "Temp. Offset User: %6.1f C\n", Temp_Offset);
		}

		if (video){
			if (offset_index_time > 0){
				--offset_index_time;
				f.seekg(uks_fileheader.ImageWidth*uks_fileheader.ImageHeight*2, ios::cur);
				continue;
			}
			if (skip > 1){
				--skip;
				f.seekg(uks_fileheader.ImageWidth*uks_fileheader.ImageHeight*2, ios::cur);
				continue;
			} else 
				skip = step_index_time-1;
		}

		g_string_append_printf (FileList, "%s: %18.0f us, %5.1f V, IlDfxy: %5.2f mA, %5.2f mA, %6.1f C, %4g Torr, %g um\n", fname, ImageTime, StartVoltage, IllumDeflX, IllumDeflY, Temperatur, Pressure11, FieldOfView);
		scan->mem2d->SetLayer(index_value);
                scan->mem2d->data->SetVLookup (index_value, start_value+index_value*(step_value>0. ? step_value: 1.));

		scan->data.ui.SetComment (FileList->str);

		scan->mem2d->DataRead(f, -1); // bot to top

//		cout << "UKSOFT::: importing LEEMData to mem2d layer[" << index_value << "]" << endl;
		int y,d,h,m;
		ImageTime /= 1e4; // in 100ns to ms
		if (realtime0 == 0.) 
			realtime0 = ImageTime;
		double s = ImageTime/1e3;
		y = (int)(s/(365.24219 * 24.*3600.)); s -= (double)y * 365.24219 * 24. * 3600.;
		d = (int)(s/(24.*3600.)); s -= (double)d * 24. * 3600.;
		h = (int)(s/3600.); s -= (double)h * 3600.;
		m = (int)(s/60.); s -= (double)m * 60.;
		scan->mem2d->add_layer_information (new LayerInformation ("t",(ImageTime-realtime0)/1e3, "%.2f s"));
		scan->mem2d->add_layer_information (new LayerInformation ("Energy", StartVoltage, "%5.1f V"));
		scan->mem2d->add_layer_information (new LayerInformation ("Temp.", Temperatur, "%6.1f \302\260C"));
		scan->mem2d->add_layer_information (new LayerInformation ("Pressure", Pressure11, "%3.1e torr"));
		if (FOV_assumed)
			scan->mem2d->add_layer_information (new LayerInformation ("FOV (nan) set 10um", FieldOfView, "%g \302\265m"));
		else
			scan->mem2d->add_layer_information (new LayerInformation ("FOV", FieldOfView, "%g \302\265m"));

#if 0 // not this (you can enable if you want it), but so long, it's only waste of space
		gchar *dhms = g_strdup_printf ("Time: %d %4d %02d:%02d:%06.3f", 1601 + y, 1+d, h,m,s);
		scan->mem2d->add_layer_information (new LayerInformation (dhms, ImageTime, "%18.0f ms"));
		g_free (dhms);
#endif

		scan->mem2d->add_layer_information (new LayerInformation ("t-user",(ImageTime-realtime0_user)/1e3, "%.2f s"));
		scan->mem2d->add_layer_information (new LayerInformation ("IllumDeflX", IllumDeflX, "%5.2f mA"));
		scan->mem2d->add_layer_information (new LayerInformation ("IllumDeflY", IllumDeflY, "%5.2f mA"));

		scan->mem2d->SetLayer(0);

		if (uks_fileheader.NrImages > 1){
			scan->append_current_to_time_elements (index_time, start_time + step_time*(index_time));
			scan->mem2d->remove_layer_information ();
			++index_time;
		} else break;
	}

	f.close ();

	if (video){
		main_get_gapp()->progress_info_close ();
		scan->retrieve_time_element (0);
	}

	scan->data.s.ntimes = scan->number_of_time_elements ();

  	return status=FIO_OK; 
}

FIO_STATUS Uksoft2001_ImExportFile::Write(){
	// start exporting -------------------------------------------
	return status=FIO_OK; 
}

// Plugin's Notify Cb's, registered to be called on file load/save to check file
// return via filepointer, it is set to Zero or passed as Zero if file has been processed!
// That's all fine, you should just change the Text Stings below...


static void uksoft2001_im_export_filecheck_load_callback (gpointer data ){
	gchar **fn = (gchar**)data;
	if (*fn){
		PI_DEBUG (DBG_L2, "checking for uksoft2001 file type >" << *fn << "<" );

		Scan *dst = main_get_gapp()->xsm->GetActiveScan();
		if(!dst){ 
			main_get_gapp()->xsm->ActivateFreeChannel();
			dst = main_get_gapp()->xsm->GetActiveScan();
		}
		Uksoft2001_ImExportFile fileobj (dst, *fn);

		FIO_STATUS ret = fileobj.Read(); 
		if (ret != FIO_OK){ 
			// I'am responsible! (But failed)
			if (ret != FIO_NOT_RESPONSIBLE_FOR_THAT_FILE)
				*fn=NULL;
			// no more data: remove allocated and unused scan now, force!
//			main_get_gapp()->xsm->SetMode(-1, ID_CH_M_OFF, TRUE); 
			PI_DEBUG (DBG_L2, "Read Error " << ((int)ret) );
		}else{
			// got it!
			*fn=NULL;

			// Now update gxsm main window data fields
			main_get_gapp()->xsm->ActiveScan->GetDataSet(main_get_gapp()->xsm->data);
			main_get_gapp()->spm_update_all();
			dst->draw();
		}
	}else{
		PI_DEBUG (DBG_L2, "Skipping" << *fn << "<" );
	}
}

static void uksoft2001_im_export_filecheck_save_callback (gpointer data ){
	gchar **fn = (gchar**)data;
	if (*fn){
		Scan *src;
		PI_DEBUG (DBG_L2, "Saving/(checking) >" << *fn << "<" );

		Uksoft2001_ImExportFile fileobj (src = main_get_gapp()->xsm->GetActiveScan(), *fn);

		FIO_STATUS ret;
		ret = fileobj.Write(); 

		if(ret != FIO_OK){
			// I'am responsible! (But failed)
			if (ret != FIO_NOT_RESPONSIBLE_FOR_THAT_FILE)
				*fn=NULL;
			PI_DEBUG (DBG_L2, "Write Error " << ((int)ret) );
		}else{
			// write done!
			*fn=NULL;
		}
	}else{
		PI_DEBUG (DBG_L2, "Skipping >" << *fn << "<" );
	}
}

// Menu callback functions -- usually no need to edit

static void uksoft2001_im_export_import_callback (GSimpleAction *simple, GVariant *parameter, gpointer user_data){
	gchar **help = g_strsplit (uksoft2001_im_export_pi.help, ",", 2);
	gchar *dlgid = g_strconcat (uksoft2001_im_export_pi.name, "-import", NULL);

        GtkFileFilter *f0 = gtk_file_filter_new ();
        gtk_file_filter_set_name (f0, "All");
        gtk_file_filter_add_pattern (f0, "*");

        GtkFileFilter *f3 = gtk_file_filter_new ();
        gtk_file_filter_set_name (f3, "LEEM");
        gtk_file_filter_add_pattern (f3, "*.dat");
        gtk_file_filter_add_pattern (f3, "*.dav");

        GtkFileFilter *f1 = gtk_file_filter_new ();
        gtk_file_filter_set_name (f1, "LEEM Images");
        gtk_file_filter_add_pattern (f1, "*.dat");
        gtk_file_filter_add_pattern (f1, "*.DAT");

        GtkFileFilter *f2 = gtk_file_filter_new ();
        gtk_file_filter_set_name (f2, "LEEM Movies");
        gtk_file_filter_add_pattern (f2, "*.dav");
        gtk_file_filter_add_pattern (f2, "*.DAV");

        GtkFileFilter *filter[] = { f3, f2, f1, f0, NULL };
        
        gchar *fn = main_get_gapp()->file_dialog_load (help[0], NULL, file_mask, filter);
	g_strfreev (help); 
	g_free (dlgid);
	if (fn){
                uksoft2001_im_export_filecheck_load_callback (&fn );
                g_free (fn);
	}
}

static void uksoft2001_im_export_export_callback (GSimpleAction *simple, GVariant *parameter, gpointer user_data){
	gchar **help = g_strsplit (uksoft2001_im_export_pi.help, ",", 2);
	gchar *dlgid = g_strconcat (uksoft2001_im_export_pi.name, "-export", NULL);
	gchar *fn = main_get_gapp()->file_dialog_save (help[1], NULL, file_mask, NULL);
	g_strfreev (help); 
	g_free (dlgid);
       	if (fn){
                uksoft2001_im_export_filecheck_save_callback (&fn );
                g_free (fn);
	}
}
