// UI.Configuration.cs created with MonoDevelop
// User: klose at 19:06 08.01.2009
// CVS release: $Id: UI.Configuration.cs,v 1.47 2011-04-19 12:36:58 klose Exp $
//
//    QuickStep: Acquire, view and identify spectra 
//    Copyright (C) 2009  Thomas Klose, Hiperscan GmbH Dresden, Germany
//
//    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 3 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, see <http://www.gnu.org/licenses/>.
//

using System;
using System.IO;
using System.Collections.Generic;
using System.Globalization;
using System.Configuration;
using System.Text.RegularExpressions;
using System.Text;
using System.Drawing;
using System.Reflection;
using System.Xml;
using Gtk;

using Hiperscan.Common;
using Hiperscan.Spectroscopy;
using Hiperscan.SGS;
using Hiperscan.Extensions;
using Hiperscan.GUI.Figure;
using Hiperscan.Unix;
using System.ComponentModel;
using Hiperscan.FileIO;


namespace Hiperscan.GUI
{

	public partial class UserInterface
	{
		public static string ConfigDirPath 
		{
			get 
			{
				return FileIOHelper.QuickStepConfigPath.Folder (UserInterface.ConfigurationProfileDirNameExtension);
			}
		}

		public static string ConfigurationProfileDirNameExtension = FileIOHelper.QuickStepConfigPath.DEFAULT_PROFILE_NAME;
		public const string USER_CONFIG_FILE_NAME = FileIOHelper.QuickStepConfigPath.DEFAULT_CONFIG_FILE_NAME;
		
		public static readonly int MaxXConstraintsCount = 5;
		
		internal void SaveSettings()
		{
			int width, height;
			this.parent.GetSize(out width, out height);
			Settings.Current.MainWindowWidth  = width;
			Settings.Current.MainWindowHeight = height;
			if (this.parent.GdkWindow != null)
				Settings.Current.MainWindowMaximized = (this.parent.GdkWindow.State == Gdk.WindowState.Maximized);
			Settings.Current.SpectrometerPanedPosition = this.spectrometer_paned.Position;
			Settings.Current.DataSourcePanedPosition   = this.data_source_paned.Position;
			
			List<string> reopen_paths = new List<string>();
			foreach (Spectrum spectrum in this.CurrentSpectra.Values)
			{
				if (spectrum.FileInfo != null)
					reopen_paths.Add(spectrum.FileInfo.FullName);
			}
			Settings.Current.ReopenPaths = reopen_paths;
			
			Console.WriteLine("Save settings...");
			Settings.Save();
			
			AccelMap.Save(Path.Combine(UserInterface.ConfigDirPath, "accelerators"));
		}
		
		internal void LoadSettings()
		{
			AccelMap.Load(Path.Combine(UserInterface.ConfigDirPath, "accelerators"));
		}

		internal class GUISettings : ConfigurationSection
		{
			
			private class PathList
			{
				
				public static string Combine(List<string> paths)
				{
					StringBuilder result = new StringBuilder();

					foreach (string path in paths)
					{
						result.AppendFormat("{0}{1}", path, System.IO.Path.PathSeparator);
					}

					if (result.Length == 0)
						return result.ToString();
					
					result.Remove(result.Length-1, 1);
					
					if (result.Length == 0)
						return result.ToString();

					if (result[0] == System.IO.Path.PathSeparator)
						result.Remove(0, 1);
					
					return result.ToString();
				}
				
				public static List<string> Split(string paths)
				{
					if (paths == null)
						return new List<string>();
					
					Regex regex = new Regex(System.IO.Path.PathSeparator.ToString());
					return new List<string>(regex.Split(paths));
				}
			}
			

			public GUISettings() {}

			
			[ConfigurationProperty("SectionExists")]
			public bool SectionExists
			{
				get { return (bool)this["SectionExists"]; }
				set { this["SectionExists"] = value;      }
			}

			[ConfigurationProperty("AutoConnect")]
			public bool AutoConnect
			{
				get { return (bool)this["AutoConnect"]; }
				set { this["AutoConnect"] = value;      }
			}

			[ConfigurationProperty("AutoSelect")]
			public bool AutoSelect
			{
				get { return (bool)this["AutoSelect"]; }
				set { this["AutoSelect"] = value;      }
			}

			[ConfigurationProperty("StandardToolbarVisible")]
			public bool StandardToolbarVisible
			{
				get
				{ 
					if (!(bool)this["SectionExists"])
						return true;
					else
						return (bool)this["StandardToolbarVisible"]; 
				}
				set { this["StandardToolbarVisible"] = value; }
			}

			[ConfigurationProperty("FigureToolbarVisible")]
			public bool FigureToolbarVisible
			{
				get
				{
					if (!(bool)this["SectionExists"])
						return true;
					else
						return (bool)this["FigureToolbarVisible"];
				}
				set { this["FigureToolbarVisible"] = value; }
			}

			[ConfigurationProperty("ExtensionsToolbarVisible")]
			public bool ExtensionsToolbarVisible
			{
				get
				{
					if (!(bool)this["SectionExists"])
						return true;
					else
						return (bool)this["ExtensionsToolbarVisible"];
				}
				set { this["ExtensionsToolbarVisible"] = value; }
			}

			[ConfigurationProperty("DataSourcesVisible")]
			public bool DataSourcesVisible
			{
				get 
				{
					if (!(bool)this["SectionExists"])
						return true;
					else
						return (bool)this["DataSourcesVisible"];
				}
				set { this["DataSourcesVisible"] = value; }
			}

			[ConfigurationProperty("PropertyEditorVisible")]
			public bool PropertyEditorVisible
			{
				get { return (bool)this["PropertyEditorVisible"]; }
				set { this["PropertyEditorVisible"] = value;      }
			}

			[ConfigurationProperty("PlotBrowserVisible")]
			public bool PlotBrowserVisible
			{
				get { return (bool)this["PlotBrowserVisible"]; }
				set { this["PlotBrowserVisible"] = value;      }
			}

			[ConfigurationProperty("SaveFilePath")]
			public string SaveFilePath
			{
				get { return (string)this["SaveFilePath"]; }
				set { this["SaveFilePath"] = value;        }
			}

			[ConfigurationProperty("ContainerSaveFilePath")]
			public string ContainerSaveFilePath
			{
				get { return (string)this["ContainerSaveFilePath"]; }
				set { this["ContainerSaveFilePath"] = value;        }
			}

			[ConfigurationProperty("ExportFilePath")]
			public string ExportFilePath
			{
				get { return (string)this["ExportFilePath"]; }
				set { this["ExportFilePath"] = value;        }
			}

			[ConfigurationProperty("SaveFrequencyFilePath")]
			public string SaveFrequencyFilePath
			{
				get { return (string)this["SaveFrequencyFilePath"]; }
				set { this["SaveFrequencyFilePath"] = value;        }
			}

			[ConfigurationProperty("SaveAddDataFilePath")]
			public string SaveAddDataFilePath
			{
				get { return (string)this["SaveAddDataFilePath"]; }
				set { this["SaveAddDataFilePath"] = value;        }
			}

			[ConfigurationProperty("OpenFilePath")]
			public string OpenFilePath
			{
				get { return (string)this["OpenFilePath"]; }
				set { this["OpenFilePath"] = value;        }
			}

			[ConfigurationProperty("OpenBgFilePath")]
			public string OpenBgFilePath
			{
				get { return (string)this["OpenBgFilePath"]; }
				set { this["OpenBgFilePath"] = value;        }
			}

			[ConfigurationProperty("OpenDirectoryPath")]
			public string OpenDirectoryPath
			{
				get { return (string)this["OpenDirectoryPath"]; }
				set { this["OpenDirectoryPath"] = value;        }
			}

			[ConfigurationProperty("AutoSaveSingleDirectory")]
			public string AutoSaveSingleDirectory
			{
				get { return (string)this["AutoSaveSingleDirectory"]; }
				set { this["AutoSaveSingleDirectory"] = value;        }
			}

			[ConfigurationProperty("AutoSaveStreamDirectory")]
			public string AutoSaveStreamDirectory
			{
				get { return (string)this["AutoSaveStreamDirectory"]; }
				set { this["AutoSaveStreamDirectory"] = value;        }
			}

			[ConfigurationProperty("WriteToEEPROM")]
			public bool WriteToEEPROM
			{
				get { return (bool)this["WriteToEEPROM"]; }
				set { this["WriteToEEPROM"] = value;      }
			}
			
			[ConfigurationProperty("DataBrowserPaths")]
			private string __DataBrowserPaths
			{
				get { return (string)this["DataBrowserPaths"]; }
				set { this["DataBrowserPaths"] = value;        }
			}
			
			public List<string> DataBrowserPaths
			{
				get { return PathList.Split(this.__DataBrowserPaths);    }
				set { this.__DataBrowserPaths = PathList.Combine(value); }
			}
			
			[ConfigurationProperty("ReopenPaths")]
			private string __ReopenPaths
			{
				get { return (string)this["ReopenPaths"]; }
				set { this["ReopenPaths"] = value;        }
			}
			
			public List<string> ReopenPaths
			{
				get { return PathList.Split(this.__ReopenPaths);    }
				set { this.__ReopenPaths = PathList.Combine(value); }
			}
			
			[ConfigurationProperty("DeactivatedPluginGuids")]
			private string __DeactivatedPluginGuids
			{
				get { return (string)this["DeactivatedPluginGuids"]; }
				set { this["DeactivatedPluginGuids"] = value;        }
			}
			
			public List<string> DeactivatedPluginGuids
			{
				get { return PathList.Split(this.__DeactivatedPluginGuids);    }
				set { this.__DeactivatedPluginGuids = PathList.Combine(value); }
			}

			[ConfigurationProperty("ActivatedPluginGuids")]
			private string __ActivatedPluginGuids
			{
				get { return (string)this["ActivatedPluginGuids"]; }
				set { this["ActivatedPluginGuids"] = value;        }
			}
			
			public List<string> ActivatedPluginGuids
			{
				get { return PathList.Split(this.__ActivatedPluginGuids);    }
				set { this.__ActivatedPluginGuids = PathList.Combine(value); }
			}

			[ConfigurationProperty("StandardOutputCulture")]
			public OutputCulture StandardOutputCulture
			{
				get 
				{ 
					if (!(bool)this["SectionExists"])
						return OutputCulture.System;

					return (OutputCulture)this["StandardOutputCulture"];
				}
				set 
				{
					this["StandardOutputCulture"] = value;               
				}
			}

//			[ConfigurationProperty("SingleFileMask")]
//			public string SingleFileMask
//			{
//				get
//				{
//					if ((string)this["SingleFileMask"] == "")
//						return "'single'_yyyy-MM-dd_HH-mm-ss_'%serial%'";
//					else
//						return (string)this["SingleFileMask"];
//				}
//				set { this["SingleFileMask"] = value; }
//			}
//
//			[ConfigurationProperty("StreamFileMask")]
//			public string StreamFileMask
//			{
//				get
//				{
//					if ((string)this["StreamFileMask"] == "")
//						return "'stream_%number%'_yyyy-MM-dd_HH-mm-ss_'%serial%'";
//					else
//						return (string)this["StreamFileMask"];
//				}
//				set { this["StreamFileMask"] = value;        }
//			}
			
			[ConfigurationProperty("SingleFileMask")]
			public string SingleFileMask
			{
				get
				{
					if ((string)this["SingleFileMask"] == "")
						return "single_%time%_%serial%";
					else
						return (string)this["SingleFileMask"];
				}
				set { this["SingleFileMask"] = value; }
			}

			[ConfigurationProperty("StreamFileMask")]
			public string StreamFileMask
			{
				get
				{
					if ((string)this["StreamFileMask"] == "")
						return "stream_%number%_%time%_%serial%";
					else
						return (string)this["StreamFileMask"];
				}
				set { this["StreamFileMask"] = value;        }
			}
			
			[ConfigurationProperty("ShowPreviewInPlot")]
			public bool ShowPreviewInPlot
			{
				get { return (bool)this["ShowPreviewInPlot"]; }
				set { this["ShowPreviewInPlot"] = value;      }
			}

			[ConfigurationProperty("AlwaysShowLegend")]
			public bool AlwaysShowLegend
			{
				get { return (bool)this["AlwaysShowLegend"]; }
				set { this["AlwaysShowLegend"] = value;      }
			}

			[ConfigurationProperty("SNVLowerBoundary")]
			public double SNVLowerBoundary
			{
				get 
				{
					if ((double)this["SNVLowerBoundary"] == 0.0)
						return 1050f;
					return (double)this["SNVLowerBoundary"]; 
				}
				set { this["SNVLowerBoundary"] = value;      }
			}

			[ConfigurationProperty("SNVUpperBoundary")]
			public double SNVUpperBoundary
			{
				get 
				{
					if ((double)this["SNVUpperBoundary"] == 0.0)
						return 1850f;
					return (double)this["SNVUpperBoundary"]; 
				}
				set { this["SNVUpperBoundary"] = value;      }
			}

			[ConfigurationProperty("MainWindowWidth")]
			public int MainWindowWidth
			{
				get { return (int)this["MainWindowWidth"]; }
				set { this["MainWindowWidth"] = value;      }
			}
			
			[ConfigurationProperty("MainWindowHeight")]
			public int MainWindowHeight
			{
				get { return (int)this["MainWindowHeight"]; }
				set { this["MainWindowHeight"] = value;      }
			}
			
			[ConfigurationProperty("MainWindowMaximized")]
			public bool MainWindowMaximized
			{
				get { return (bool)this["MainWindowMaximized"]; }
				set { this["MainWindowMaximized"] = value;      }
			}
			
			[ConfigurationProperty("SpectrometerPanedPosition")]
			public int SpectrometerPanedPosition
			{
				get 
				{ 
					if (!(bool)this["SectionExists"])
						return 300;
					else
						return (int)this["SpectrometerPanedPosition"];
				}
				set { this["SpectrometerPanedPosition"] = value;      }
			}			

			[ConfigurationProperty("DataSourcePanedPosition")]
			public int DataSourcePanedPosition
			{
				get { return (int)this["DataSourcePanedPosition"]; }
				set { this["DataSourcePanedPosition"] = value;      }
			}			

			[ConfigurationProperty("DontShowEditShortcutMessageAgain")]
			public bool DontShowEditShortcutMessageAgain
			{
				get { return (bool)this["DontShowEditShortcutMessageAgain"]; }
				set { this["DontShowEditShortcutMessageAgain"] = value;      }
			}
			
			[ConfigurationProperty("RemoteUSBSharePort")]
			public uint RemoteUSBSharePort
			{
				get { return (uint)this["RemoteUSBSharePort"]; }
				set { this["RemoteUSBSharePort"] = value;      }
			}
			
			[ConfigurationProperty("RemoteUSBServer")]
			public string RemoteUSBServer
			{
				get { return (string)this["RemoteUSBServer"]; }
				set { this["RemoteUSBServer"] = value;      }
			}

			[ConfigurationProperty("RemoteUSBServerPort")]
			public uint RemoteUSBServerPort
			{
				get { return (uint)this["RemoteUSBServerPort"]; }
				set { this["RemoteUSBServerPort"] = value;      }
			}
			
			[ConfigurationProperty("AnnotationTextDefaultFont")]
			public string AnnotationTextDefaultFont
			{
				get { return (string)this["AnnotationTextDefaultFont"]; }
				set { this["AnnotationTextDefaultFont"] = value;      }
			}
			
			[ConfigurationProperty("AnnotationTextDefaultColor")]
			public Color AnnotationTextDefaultColor
			{
				get
				{ 
					if (this["AnnotationTextDefaultColor"] == null)
						return Color.Black;
					return (Color)this["AnnotationTextDefaultColor"]; 
				}
				set { this["AnnotationTextDefaultColor"] = value; }
			}
			
			[ConfigurationProperty("AnnotationLineWidth")]
			public float AnnotationLineWidth
			{
				get
				{ 
					if ((float)this["AnnotationLineWidth"] <= 0f)
						return 1f;
					return (float)this["AnnotationLineWidth"]; 
				}
				set { this["AnnotationLineWidth"] = value; }
			}
			
			[ConfigurationProperty("AnnotationLineStyle")]
			public LineStyle AnnotationLineStyle
			{
				get { return (LineStyle)this["AnnotationLineStyle"]; }
				set { this["AnnotationLineStyle"] = value; }
			}
			
			[ConfigurationProperty("AnnotationLineColor")]
			public Color AnnotationLineColor
			{
				get
				{ 
					if (this["AnnotationTextDefaultColor"] == null)
						return Color.Black;
					return (Color)this["AnnotationLineColor"]; 
				}
				set { this["AnnotationLineColor"] = value; }
			}
			
			[ConfigurationProperty("AnnotationArrowLineWidth")]
			public float AnnotationArrowLineWidth
			{
				get
				{ 
					if ((float)this["AnnotationArrowLineWidth"] <= 0f)
						return 2f;
					return (float)this["AnnotationArrowLineWidth"]; 
				}
				set { this["AnnotationArrowLineWidth"] = value; }
			}
			
			[ConfigurationProperty("AnnotationArrowLineStyle")]
			public LineStyle AnnotationArrowLineStyle
			{
				get { return (LineStyle)this["AnnotationArrowLineStyle"]; }
				set { this["AnnotationArrowLineStyle"] = value; }
			}
			
			[ConfigurationProperty("AnnotationArrowColor")]
			public Color AnnotationArrowColor
			{
				get
				{ 
					if (this["AnnotationTextDefaultColor"] == null)
						return Color.Black;
					return (Color)this["AnnotationArrowColor"]; 
				}
				set { this["AnnotationArrowColor"] = value; }
			}
			
			[ConfigurationProperty("AnnotationArrowCapStyle")]
			public CapStyle AnnotationArrowCapStyle
			{
				get { return (CapStyle)this["AnnotationArrowCapStyle"]; }
				set { this["AnnotationArrowCapStyle"] = value; }
			}

			// deprecated!
			[ConfigurationProperty("ThemeName")]
			public string ThemeName
			{
				get 
				{
					if (!Settings.saving)
						throw new Exception("ConfigurationProperty \"ThemeName\" is deprecated. Use \"GtkTheme\"."); 
					return string.Empty;
				}
				set 
				{
					if (!Settings.saving)
						throw new Exception("ConfigurationProperty \"ThemeName\" is deprecated. Use \"GtkTheme\"."); 
				}
			}
			
			[ConfigurationProperty("GtkTheme")]
			public string GtkTheme
			{
				get { return (string)this["GtkTheme"]; }
				set { this["GtkTheme"] = value; }
			}

			[ConfigurationProperty("DontShowDiscardPropertiesDialogAgain")]
			public bool DontShowDiscardPropertiesDialogAgain
			{
				get { return (bool)this["DontShowDiscardPropertiesDialogAgain"]; }
				set { this["DontShowDiscardPropertiesDialogAgain"] = value; }
			}
			
			[ConfigurationProperty("AxisType")]
			public AxisType AxisType
			{
				get { return (AxisType)this["AxisType"]; }
				set { this["AxisType"] = value; }
			}
			
			[ConfigurationProperty("XConstraints")]
			private string _XConstraints
			{
				get { return (string)this["XConstraints"];  }
				set { this["XConstraints"] = value; }
			}
			
			public List<string> XConstraints
			{
				get 
				{ 
					if (string.IsNullOrEmpty(_XConstraints))
					    return new List<string>();
					string[] constraints = _XConstraints.Split(new char[] {':'}, StringSplitOptions.RemoveEmptyEntries);
					return new List<string>(constraints); 
				}
				set
				{
					if (value.Count > MaxXConstraintsCount)
						value.RemoveRange(0, value.Count-MaxXConstraintsCount);
					_XConstraints = string.Join(":", value.ToArray()); 
				}
			}
		}
		
		internal sealed class Settings
		{
			private static Configuration config;
			private static bool is_valid = true;
			private static bool is_initialized = false;
			public static volatile bool saving = false;

			private static readonly string DefaultSectionName = "QuickStep1.0Settings";

			public static void Init()
			{
				// sync config from Hiperscan's WebDAV server
				try
				{
					if (MainClass.IsRelease == false)
						WebDavConfig.Read();
				}
				catch { }

				Settings.Init(Settings.DefaultSectionName, new GUISettings());
				Settings.is_initialized = true;
			}

			private static void MoveConfigDataToRoamingFolder()
			{
				try
				{
					bool copy_files = true;

                    Console.WriteLine("MoveConfigDataToRoamingFolder ...");

					if (FileIOHelper.QuickStepConfigPath.FolderChanged (UserInterface.ConfigurationProfileDirNameExtension) == false)
						copy_files = false;

					string destination_dir = FileIOHelper.QuickStepConfigPath.Folder (UserInterface.ConfigurationProfileDirNameExtension);
					if (File.Exists (Path.Combine(destination_dir, FileIOHelper.QuickStepConfigPath.DEFAULT_CONFIG_FILE_NAME)) == true)
						copy_files = false;

                    Console.WriteLine("MoveConfigDataToRoamingFolder -> destination exists: {0}",
                                      File.Exists(Path.Combine(destination_dir, FileIOHelper.QuickStepConfigPath.DEFAULT_CONFIG_FILE_NAME)));

					string source_dir = FileIOHelper.QuickStepConfigPath.OldFolder (UserInterface.ConfigurationProfileDirNameExtension);
					if (File.Exists (Path.Combine (source_dir, FileIOHelper.QuickStepConfigPath.DEFAULT_CONFIG_FILE_NAME)) == false)
						copy_files = false;

                    Console.WriteLine("MoveConfigDataToRoamingFolder -> source exists: {0}",
                                      File.Exists(Path.Combine(source_dir, FileIOHelper.QuickStepConfigPath.DEFAULT_CONFIG_FILE_NAME)));

					if (File.Exists (Path.Combine (source_dir, FileIOHelper.QuickStepConfigPath.CONVERT_COOKIE)) == true)
						copy_files = false;

                    Console.WriteLine("MoveConfigDataToRoamingFolder -> cookie exists: {0}",
                                      File.Exists(Path.Combine(source_dir, FileIOHelper.QuickStepConfigPath.CONVERT_COOKIE)));


                    Console.WriteLine("MoveConfigDataToRoamingFolder -> cookie exists: {0}", copy_files);

					if (copy_files == true)
						Settings.CopyConfigData (source_dir, destination_dir);	
						
                    if (Directory.Exists(source_dir) == true &&
                     File.Exists(Path.Combine(source_dir, FileIOHelper.QuickStepConfigPath.CONVERT_COOKIE)) == false)
                    {
                        File.Create(Path.Combine(source_dir, FileIOHelper.QuickStepConfigPath.CONVERT_COOKIE));  
                        Console.WriteLine("MoveConfigDataToRoamingFolder -> cookie created");
                    }

                    Console.WriteLine("MoveConfigDataToRoamingFolder success ...");
                       	
				}
				catch(Exception ex)
				{
                    Console.WriteLine("MoveConfigDataToRoamingFolder failed {0}", ex.ToString());
				}
			}

			private static void CopyConfigData(string source_folder, string destination_folder)
			{
                Regex regex = new Regex(@".*log.*_\d\.txt$");

				foreach (string source_file in Directory.GetFiles(source_folder))
				{
                    if (regex.Match(Path.GetFileName(source_file)).Success == true)
                        continue; 

                    string destination_file = Path.Combine (destination_folder, Path.GetFileName(source_file));
                    Console.WriteLine("CopyConfigData copy file: {0} -> {1}", source_file, destination_file);
					File.Copy (source_file, destination_file, true);
				}

				foreach (string sub_dir in Directory.GetDirectories(source_folder))
				{
                    if (Path.GetFileName(sub_dir) == "de_DE" || Path.GetFileName(sub_dir) == "en_GB")
                        continue;
                    
					string sub_destination_dir = Path.Combine (destination_folder, Path.GetFileName (sub_dir));

					if (Directory.Exists(sub_destination_dir) == false)
                        Directory.CreateDirectory(sub_destination_dir);
						
                    Console.WriteLine("CopyConfigData rcursion with folder {0}", sub_destination_dir);

					Settings.CopyConfigData (sub_dir, sub_destination_dir);
				}
			}

			private static void CreateEmptyConfig (string file)
			{
				using (StreamWriter sw = new StreamWriter (file, false, Encoding.UTF8)) {
					sw.WriteLine ("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
					sw.WriteLine ("<configuration />");
				}
			}

			public static void Init (string section_name, ConfigurationSection new_section)
			{
				if (Settings.config == null) {
					string file = Path.Combine (UserInterface.ConfigDirPath, UserInterface.USER_CONFIG_FILE_NAME);

					Settings.MoveConfigDataToRoamingFolder ();

					int max_tries = 5;
					for (int i = 1; i <= max_tries; i++) {
						try {
							if (File.Exists (file) == false)
								Settings.CreateEmptyConfig (file);
							File.Copy (file, file + ".config", true);
							Settings.config = ConfigurationManager.OpenExeConfiguration (file);
							break;
						} catch (Exception ex) {
							if (i == max_tries)
								throw ex;

							System.Threading.Thread.Sleep (150);
						}
					}
				}

				// If the section does not exist in the configuration
				if (Settings.config.Sections [section_name] == null) {
					Settings.config.Sections.Add (section_name, new_section);
					new_section = Settings.config.GetSection (section_name);
				}
			}


			public static void RequestConfigOverride (Exception ex)
			{
				Settings.is_valid = false;
				string file = Path.Combine (UserInterface.ConfigDirPath, UserInterface.USER_CONFIG_FILE_NAME);

				Console.WriteLine ("Cannot read configuration:");
				Console.WriteLine (ex);
				OverwriteConfigDialog dialog = new OverwriteConfigDialog (null, file);
				ResponseType response = (ResponseType)dialog.Run ();
				dialog.Destroy ();

				if (response == ResponseType.No)
					throw new EmergencyStopException ();

				try {
					File.Delete (file);
				} catch (Exception exx) {
					new InfoMessage (null, Catalog.GetString ("Cannot overwrite configuration file:") +
							" " + exx.Message);
					throw new EmergencyStopException ();
				}
				new InfoMessage (null, Catalog.GetString ("Please restart the application."));
				throw new EmergencyStopException ();
			}

			public static void Save()
			{
				saving = true;

				if (!Settings.IsValid)
				{
					saving = false;
					return;
				}
				
				Settings.Current.SectionExists = true;
				string file = Path.Combine(UserInterface.ConfigDirPath, UserInterface.USER_CONFIG_FILE_NAME);

				try
				{
					Settings.__WriteConfigFile();
					
					try
					{
						if (MainClass.IsRelease == false)
							WebDavConfig.Write();
					}
					catch { }
				}
				catch (Exception ex)
				{
					Console.WriteLine("Error while saving settings: " + ex.ToString());
					Console.WriteLine("Trying again in 1 second...");
					System.Threading.Thread.Sleep(1000);
					try
					{
						Settings.__WriteConfigFile();
						
						try
						{
							if (MainClass.IsRelease == false)
								WebDavConfig.Write();
						}
						catch { }
					}
					catch (Exception exx)
					{
						Console.WriteLine("Failed again: " + exx.Message);
						Console.WriteLine("Giving up.");
						UserInterface.UI.ShowInfoMessage(null,
						                                 Catalog.GetString("An error occured while writing configuration file: {0}\n\nSetting will not be saved."),
						                                 exx.Message);
					}
				}
				saving = false;
			}
			
			//TODO
			//Settings.config.SaveAs(file, ConfigurationSaveMode.Full) does not still work under mono 5.0
			private static void __WriteConfigFile()
			{
				string file = Path.Combine(UserInterface.ConfigDirPath, UserInterface.USER_CONFIG_FILE_NAME);

				string pattern = @"([a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12})|(QuickStep1.0Settings)";
				Regex regex = new Regex(pattern);
		
				XmlDocument document = new XmlDocument();
				document.LoadXml("<configuration><configSections></configSections></configuration>");
				XmlNode config_section = document.GetElementsByTagName("configSections")[0];
				XmlNode configuration = document.GetElementsByTagName("configuration")[0];
				
				foreach(string section_name in Settings.config.Sections.Keys)
				{
					try
					{	
						if (regex.Match(section_name).Success == true)
						{
							ConfigurationSection section = Settings.config.GetSection(section_name);

							XmlAttribute name = document.CreateAttribute("name");
							name.InnerText = section_name;
							XmlAttribute type = document.CreateAttribute("type");
							type.InnerText = section.GetType().AssemblyQualifiedName;
							XmlAttribute require_permission = document.CreateAttribute("requirePermission");
							require_permission.InnerText = "false";
							
							XmlElement element = document.CreateElement("section");
							element.Attributes.Append(name);
							element.Attributes.Append(type);
							element.Attributes.Append(require_permission);
							
							config_section.AppendChild(element);
						}
					}
					catch(Exception ex)
					{
						Console.WriteLine(ex.ToString());
					}
				}
				
				foreach(string section_name in Settings.config.Sections.Keys)
				{
					try
					{	
						if (regex.Match(section_name).Success == true)
						{
							try
							{
								ConfigurationSection section = Settings.config.GetSection(section_name);

								XmlElement element = document.CreateElement(section_name);
								configuration.AppendChild(element);
							
								UserInterface.Settings.__WriteConfigProperties(element, document, section);
							}
							catch(Exception ex)
							{
								Console.WriteLine("Configuration error: " + ex.Message);
							}
						}
					}
					catch (Exception) {}
				}
				
				using (StreamWriter sw = new StreamWriter(file, false, Encoding.UTF8))
				{
					document.Save(sw);
				}				
				//Settings.config.SaveAs(file, ConfigurationSaveMode.Full);
			}
			
			private static void  __WriteConfigProperties(XmlElement element, XmlDocument doc, object section)
			{ 
				foreach(PropertyInfo property in section.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
				{	
					if (property.GetCustomAttributes(typeof(ConfigurationPropertyAttribute), false).Length == 0)
						continue;

					ConfigurationPropertyAttribute config_attribute = (ConfigurationPropertyAttribute) property.GetCustomAttributes(typeof(ConfigurationPropertyAttribute),false)[0];

					if ((property.GetValue(section, null) as ConfigurationElement) != null)
					{
						XmlElement sub_element = doc.CreateElement(property.Name);
						element.AppendChild(sub_element);
						__WriteConfigProperties(sub_element, doc, property.GetValue(section, null));
					}	
					else
					{
						
						XmlAttribute attribute = doc.CreateAttribute(config_attribute.Name);
						TypeConverter converter = TypeDescriptor.GetConverter(property.GetValue(section, null));
						
						attribute.InnerText = converter.ConvertToInvariantString(property.GetValue(section, null));
						element.Attributes.Append(attribute);
					}
				}
			}
			
	
			public static ConfigurationSection Section(string section_name)
			{
				return Settings.config.GetSection(section_name);
			}
			
			public static GUISettings Current
			{
				get { return Settings.config.GetSection(Settings.DefaultSectionName) as GUISettings; }
			}
			
			public static bool IsValid
			{
				get { return Settings.is_valid;  }
			}

			public static bool IsInitialized
			{
				get { return Settings.is_initialized; }
			}
		}
		
		public class Config
		{

			public enum PropertyType
			{
				Spectrometer,
				Directory,
				Spectrum
			}
			
			public enum ApplicationMode
			{
				Normal,
				Exhibition
			}
			
			public static readonly Color PreviewColor = Color.Aqua;
			public static readonly Color StreamColor  = Color.Red;
		}
		
		public void InitConfigurationSection(string section_name, ConfigurationSection section)
		{
			try
			{
				Settings.Init(section_name, section);
			}
			catch (Exception ex)
			{
				Settings.RequestConfigOverride(ex);
			}
		}
		
		public ConfigurationSection GetConfigurationSection(string section_name)
		{
			return Settings.Section(section_name);
		}
		
		public void SaveConfiguration()
		{
			Settings.Save();
		}


		static private volatile bool __setting_plot_type = false;
		
		public PlotTypeInfo PlotType
		{
			get { return this.plot_info_list.Current.PlotType;  }
			set 
			{ 
				if (__setting_plot_type)
					return;
				
				__setting_plot_type = true;
				bool call_again = false;

				try
				{
					this.plot_info_list.Current.PlotType = value;
					Console.WriteLine("Set plot type to: " + value.Name);
					this.ScrolledPlot.Plot.XLabel = value.XLabel;
					this.ScrolledPlot.Plot.YLabel = value.YLabel;
					this.ScrolledPlot.Plot.PlotTypeId = value.GetPlotTypeId();
					this.UpdateXConstraintsEntry();
					call_again = !value.QueryInformation();
					
					if (value is UndefinedPlotTypeInfo)
					{
						if (this.plot_type_combo.Active != -1)
							this.plot_type_combo.Active = -1;
					}
					else
					{
						this.__SetPlotTypeCombo(value.Name, true);
					}
				}
				catch {}
				finally
				{
					__setting_plot_type = false; 
					if (call_again)
						this.PlotType = this.plot_info_list.Current.PlotType;
				}
			}
		}

		public void __SetPlotTypeCombo(string name, bool update_plot)
		{
			bool sav_state = __update_on_plot_type_combo_change;
			__update_on_plot_type_combo_change = update_plot;

			this.plot_type_combo.Model.Foreach(delegate(TreeModel model, TreePath path, TreeIter iter) {
				if (((PlotTypeInfo)model.GetValue(iter, 1)).Name != name)
					return false;
				this.plot_type_combo.SetActiveIter(iter);
				return true;
			});

			__update_on_plot_type_combo_change = sav_state;
		}
		
//		public Config.PlotType PlotType_
//		{
//			get
//			{
//				return this.plot_type_;
//			}
//			set
//			{
//				if (__setting_plot_type)
//					return;
//				
//				__setting_plot_type = true;
//				
//				bool call_again = false;
//				
//				try
//				{
//					switch (value)
//					{
//						
//					case Config.PlotType.Intensity:
//						this.ScrolledPlot.Plot.XLabel = Catalog.GetString("Wavelength / nm");
//						this.ScrolledPlot.Plot.YLabel = Catalog.GetString("Intensity");
//						this.lower_plot_limit = -2f;
//						this.upper_plot_limit =  5f;
//						this.standard_ymin = -0.1f;
//						this.standard_ymax =  2.6f;
//						this.intensity_item.Active = true;
//						break;
//						
//					case Config.PlotType.Absorbance:
//						this.ScrolledPlot.Plot.XLabel = Catalog.GetString("Wavelength / nm");
//						this.ScrolledPlot.Plot.YLabel = Catalog.GetString("Absorbance");
//						this.lower_plot_limit = -5f;
//						this.upper_plot_limit =  8f;
//						this.standard_ymin = -0.5f;
//						this.standard_ymax =  4.1f;
//						this.absorbance_item.Active = true;
//						break;
//						
//					case Config.PlotType.AbsorbanceSNV:
//						this.ScrolledPlot.Plot.XLabel = Catalog.GetString("Wavelength / nm");
//						this.ScrolledPlot.Plot.YLabel = Catalog.GetString("SNV(Absorbance)");
//						this.lower_plot_limit = -5f;
//						this.upper_plot_limit =  8f;
//						this.standard_ymin = -0.5f;
//						this.standard_ymax =  4.1f;
//						SNVBoundariesDialog dialog = new SNVBoundariesDialog(this.ScrolledPlot.Plot.GlobalXMin,
//						                                                     this.ScrolledPlot.Plot.GlobalXMax);
//						SNVInfo new_snv_info = dialog.Query();
//						if (!new_snv_info.valid)
//						{
//							call_again = true; 
//							return;
//						}
//						this.snv_info = new_snv_info;
//						this.snv_item.Active = true;
//						break;
//						
//					case Config.PlotType.AbsorbanceFFT:
//						this.ScrolledPlot.Plot.XLabel = Catalog.GetString("Spatial frequency / 1/nm");
//						this.ScrolledPlot.Plot.YLabel = Catalog.GetString("FFT(SNV(Absorbance))");
//						this.lower_plot_limit = -1f;
//						this.upper_plot_limit =  8f;
//						this.standard_ymin = -0.5f;
//						this.standard_ymax =  4.1f;
//						dialog = new SNVBoundariesDialog(this.ScrolledPlot.Plot.GlobalXMin,
//						                                 this.ScrolledPlot.Plot.GlobalXMax);
//						new_snv_info = dialog.Query();
//						if (!new_snv_info.valid)
//						{
//							call_again = true;
//							return;
//						}
//						this.snv_info = new_snv_info;
//						this.fft_item.Active = true;
//						break;
//						
//					case Config.PlotType.IntensityFFTAbs:
//						this.ScrolledPlot.Plot.XLabel = Catalog.GetString("Spatial frequency / 1/nm");
//						this.ScrolledPlot.Plot.YLabel = Catalog.GetString("Abs(FFT(RawIntensity))");
//						this.lower_plot_limit = -1f;
//						this.upper_plot_limit =  8f;
//						this.standard_ymin = -0.5f;
//						this.standard_ymax =  4.1f;
//						this.fft_raw_abs_item.Active = true;
//						break;
//
//					case Config.PlotType.IntensityFFTArg:
//						this.ScrolledPlot.Plot.XLabel = Catalog.GetString("Spatial frequency / 1/nm");
//						this.ScrolledPlot.Plot.YLabel = Catalog.GetString("Arg(FFT(RawIntensity))");
//						this.lower_plot_limit = -2f;
//						this.upper_plot_limit =  2f;
//						this.standard_ymin = -0.5f;
//						this.standard_ymax =  4.1f;
//						this.fft_raw_arg_item.Active = true;
//						break;
//
//					case Config.PlotType.Background:
//						this.ScrolledPlot.Plot.XLabel = Catalog.GetString("Wavelength / nm");
//						this.ScrolledPlot.Plot.YLabel = Catalog.GetString("Background intensity");
//						this.lower_plot_limit = -2f;
//						this.upper_plot_limit =  5f;
//						this.standard_ymin = -0.1f;
//						this.standard_ymax =  2.6f;
//						this.background_item.Active = true;
//						break;
//						
//					case Config.PlotType.Correction:
//						this.ScrolledPlot.Plot.XLabel = Catalog.GetString("Wavelength / nm");
//						this.ScrolledPlot.Plot.YLabel = Catalog.GetString("Correction fit");
//						this.lower_plot_limit = -10f;
//						this.upper_plot_limit =  10f;
//						this.standard_ymin = -0.1f;
//						this.standard_ymax =  2.6f;
//						this.correction_item.Active = true;
//						break;
//						
//					case Config.PlotType.None:
//						this.ScrolledPlot.Plot.XLabel = Catalog.GetString("Wavelength / nm");
//						this.ScrolledPlot.Plot.YLabel = Catalog.GetString("Intensity");
//						this.intensity_item.Active = true;
//						break;
//					}
//					
//					this.plot_type_ = value;
//					this.plot_type_combo.Active = (int)value;
//				}
//				catch {}
//				finally
//				{
//					__setting_plot_type = false; 
//					if (call_again)
//						this.PlotType_ = this.plot_type_;
//				}
//			}
//		}
		
		public OutputCulture StandardOutputCulture
		{
			get
			{
				return Settings.Current.StandardOutputCulture;
			}
			set
			{
//				this.default_output_culture_combo.Active = (int)value;
			
				switch (value)
				{

				case OutputCulture.English:
					this.english_item.Active = true;
					break;
					
				case OutputCulture.German:
					this.german_item.Active = true;
					break;
					
				case OutputCulture.System:
					this.system_item.Active = true;
					break;
					
				}

				if (this.device_list == null)
					return;
				
				foreach (Device dev in this.device_list.Values)
				{
					AutoSaveConfig config = (AutoSaveConfig)dev.CurrentConfig.UserData;

					if (config == null)
						continue;
					
					config.SingleDir.OutputCulture = value;
					config.StreamDir.OutputCulture = value;
				}
				
				Settings.Current.StandardOutputCulture = value;
			}
		}
		
		public CultureInfo OutputCultureInfo()
		{
			return this.OutputCultureInfo(this.StandardOutputCulture);
		}
		
		public CultureInfo OutputCultureInfo(OutputCulture output_culture)
		{
			switch (output_culture)
			{
				
			case OutputCulture.English:
				return new CultureInfo("en-US");
				
			case OutputCulture.German:
				return new CultureInfo("de-DE");
				
			case OutputCulture.System:
				return CultureInfo.CurrentCulture;
				
			default:
				return CultureInfo.CurrentCulture;
			}
		}

		public bool StandardToolbarVisible
		{
			get { return this.standard_toolbar_item.Active;  }
			set	
			{ 
				if (this.standard_toolbar_item.Active != value)
					this.standard_toolbar_item.Active = value;
				else
					this.standard_toolbar_item.EmitToggled();
			}
		}

		public bool FigureToolbarVisible
		{
			get { return this.figure_toolbar_item.Active;  }
			set
			{ 
				if (this.figure_toolbar_item.Active != value)
					this.figure_toolbar_item.Active = value;
				else
					this.figure_toolbar_item.EmitToggled();
			}
		}

		public bool ExtensionsToolbarVisible
		{
			get { return this.extensions_toolbar_item.Active;  }
			set
			{ 
				if (this.extensions_toolbar_item.Active != value)
					this.extensions_toolbar_item.Active = value;
				else
					this.extensions_toolbar_item.EmitToggled();
			}
		}

		public bool DataSourcesVisible
		{
			get { return this.data_sources_button.Active;  }
			set	
			{ 
				if (this.data_sources_button.Active != value)
					this.data_sources_button.Active = value; 
				else
					this.OnDataSourcesButtonToggled(this.data_sources_button, null);
			}
		}

		public bool PropertyEditorVisible
		{
			get { return this.property_editor_button.Active;  }
			set	
			{ 
				if (this.property_editor_button.Active != value)
					this.property_editor_button.Active = value; 
				else
					this.OnPropertyEditorButtonToggled(this.property_editor_button, null);
			}
		}
		
		public bool PlotBrowserVisible
		{
			get { return this.plot_browser_button.Active;  }
			set 
			{ 
				if (this.plot_browser_button.Active != value)
					this.plot_browser_button.Active = value; 
				else
					this.OnPlotBrowserButtonToggled(this.plot_browser_button, null);
			}
		}
		
		public Config.PropertyType PropertyType
		{
			get { return (Config.PropertyType)this.property_notebook.CurrentPage; }
			set	{ this.property_notebook.CurrentPage = (int)value;                }
		}
		
		public bool ExhibitionMode
		{
			get { return MainClass.ApplicationMode == UserInterface.Config.ApplicationMode.Exhibition; }
		}
		
		public bool TouchScreenMode
		{
			get { return MainClass.TouchScreen; }
		}
		
		public bool IsRelease
		{
			get { return MainClass.IsRelease; }
		}
	}
}
