// DirectoryProperty.cs created with MonoDevelop
// User: klose at 13:41 16.02.2009
// CVS release: $Id: DirectoryProperty.cs,v 1.15 2010-08-11 14:10:52 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.Globalization;
using System.IO;

using Hiperscan.SGS;
using Hiperscan.Spectroscopy;
using Hiperscan.Spectroscopy.IO;
using Hiperscan.Unix;


namespace Hiperscan.QuickStep.IO
{

    public enum SpectrumFileType
    {
        CSV
    }
    
    public enum OutputCulture
    {
        English,
        German,
        System
    }
    
    public class DirectoryProperty : System.IComparable<DirectoryProperty>
    {
        private IDevice associated_device = null;

        private CultureInfo culture_info;
        private OutputCulture output_culture;

        private string single_suffix;
        private string stream_suffix;

        private SpectrumFileType single_filetype;
        private SpectrumFileType stream_filetype;


        private DirectoryProperty()
        {
            this.AutoSaveSingle  = false;
            this.AutoSaveStream  = false;
            this.OutputCulture   = UserInterface.Settings.Current.StandardOutputCulture;
            this.SingleFilemask  = UserInterface.Settings.Current.SingleFileMask;
            this.StreamFilemask  = UserInterface.Settings.Current.StreamFileMask;
            this.SingleFiletype  = SpectrumFileType.CSV;
            this.StreamFiletype  = SpectrumFileType.CSV;
            this.SpectrumComment = string.Empty;
        }
        
        public DirectoryProperty(DirectoryInfo info) : this()
        {
            this.Info = info;
        }
        
        public DirectoryProperty(string path) : this()
        {
            this.Info = new DirectoryInfo(path);
        }
        
        public DirectoryProperty(DirectoryProperty dir) : this()
        {
            this.Info = dir.Info;
            
            this.AutoSaveSingle = dir.AutoSaveSingle;
            this.AutoSaveStream = dir.AutoSaveStream;
            
            this.associated_device = dir.AssociatedDevice;
        }

        public int CompareTo(DirectoryProperty dp)
        {
            if (dp == null)
                return 1;
            
            return string.Compare(this.Info.Name, dp.Info.Name, StringComparison.InvariantCulture);
        }
        
        private string AssembleFilename(Spectrum spectrum, string filemask, string suffix)
        {
            return DirectoryProperty.AssembleFilename(this.Info.FullName, spectrum, filemask, suffix);
        }

        public static string AssembleFilename(string path, Spectrum spectrum, string filemask, string suffix)
        {
            path += System.IO.Path.DirectorySeparatorChar;
            
            // compatibility with deprecated format
            filemask = filemask.Replace("yyyy-MM-dd_HH-mm-ss", "%time%");
            
            if (string.IsNullOrEmpty(spectrum.Serial))
                filemask = filemask.Replace("%serial%",  "*");
            else
                filemask = filemask.Replace("%serial%",  spectrum.Serial);
            
            if (spectrum.Number < 0)
                filemask = filemask.Replace("%number%",  "*");
            else
                filemask = filemask.Replace("%number%",  spectrum.Number.ToString("d4"));
            
            if (spectrum.AverageCount < 0)
                filemask = filemask.Replace("%average%", "*");
            else
                filemask = filemask.Replace("%average%", spectrum.AverageCount.ToString());
                
            filemask = filemask.Replace("'", string.Empty);
            filemask = filemask.Insert(0, "'");
            filemask += "'";
            
            if (filemask.Contains("%time%"))
            {
                filemask = filemask.Replace("%time%", "'yyyy-MM-dd_HH-mm-ss'");
            }
            
            if (filemask.Contains("%"))
                throw new ArgumentException(Catalog.GetString("Invalid % expression."));
            
            return path + spectrum.Timestamp.ToString(filemask) + suffix;
        }
        
        public void DisconnectSingleDevice()
        {
            Console.WriteLine($"Disconnect device {this.associated_device} from single dir {this.Info.Name}");
            try
            {
                this.associated_device.NewSingle -= this.OnNewSingle;
            }
#pragma warning disable RECS0022
            catch { }
#pragma warning restore RECS0022
        }

        public void DisconnectStreamDevice()
        {
            Console.WriteLine($"Disconnect device {this.associated_device} from stream dir {this.Info.Name}");

            try
            {
                this.associated_device.NewStream -= this.OnNewStream;
            }
#pragma warning disable RECS0022
            catch { }
#pragma warning restore RECS0022
        }

        public void DisconnectDevice()
        {
            this.DisconnectSingleDevice();
            this.DisconnectStreamDevice();
        }
        
        private void OnNewSingle(IDevice device, Spectrum spectrum)
        {
            if (this.AutoSaveSingle == false || this.Active == false)
                return;

            device.SetAbsorbance(spectrum);
            device.SetWavelengthCorrection(spectrum);

            string fname = this.AssembleFilename(spectrum, 
                                                 this.SingleFilemask,
                                                 this.single_suffix);
            
            if (string.IsNullOrEmpty(this.SpectrumComment) == false)
                spectrum.Comment = this.SpectrumComment;
            
            UserInterface._SetCreator(spectrum);

            try
            {
                CSV.Write(spectrum, fname);
            }
            catch (Exception ex)
            {
                this.Active = false;
                string msg = string.Format(Catalog.GetString(@"Cannot automatically save single spectrum in directory '{0}': {1}

Disabling the auto save function."), 
                                           this.Info.FullName,
                                           ex.Message);

                Console.WriteLine(msg);
                Console.WriteLine(ex.ToString());

                UserInterface.Queues.AddToMessageQueue(ex.Message, ex);
            }
        }
        
        private void OnNewStream(IDevice device, Spectrum spectrum)
        {
            if (this.AutoSaveStream == false || this.Active == false)
                return;
            
            device.SetAbsorbance(spectrum);
            device.SetWavelengthCorrection(spectrum);
            
            string fname = this.AssembleFilename(spectrum,
                                                 this.StreamFilemask,
                                                 this.stream_suffix);
            
            if (string.IsNullOrEmpty(this.SpectrumComment) == false)
                spectrum.Comment = this.SpectrumComment;

            UserInterface._SetCreator(spectrum);

            try
            {
                spectrum.Label = string.Empty;
                CSV.Write(spectrum, fname);
            }
            catch (Exception ex)
            {
                this.Active = false;
                string msg = string.Format(Catalog.GetString(@"Cannot automatically save stream spectrum in directory '{0}': {1}

Disabling the auto save function."),
                                           this.Info.FullName, ex.Message);
                Console.WriteLine(msg);
                Console.WriteLine(ex);
                UserInterface.Queues.AddToMessageQueue(ex.Message, ex);
            }
        }

        public IDevice AssociatedDevice
        {
            get 
            { 
                return this.associated_device;
            }
            set
            { 
                if (value == this.associated_device)
                    return;
                
                this.DisconnectDevice();
                this.associated_device = value;

                if (this.associated_device != null)
                {
                    Console.WriteLine($"Connect device {this.associated_device} with dir {this.Info.Name}");
                    this.associated_device.NewSingle += this.OnNewSingle;
                    this.associated_device.NewStream += this.OnNewStream;
                }
            }
        }

        public OutputCulture OutputCulture
        {
            get 
            { 
                return this.output_culture;
            }
            set
            {
                switch (value)
                {
                    
                case OutputCulture.English:
                    this.culture_info = new CultureInfo("en-US");
                    break;
                
                case OutputCulture.German:
                    this.culture_info = new CultureInfo("de-DE");
                    break;
                    
                case OutputCulture.System:
                    this.culture_info = CultureInfo.CurrentCulture;
                    break;

                default:
                    this.culture_info = new CultureInfo("en-US");
                    break;
                }

                this.output_culture = value;
            }
        }
        public SpectrumFileType SingleFiletype
        {
            get
            {
                return this.single_filetype;
            }
            set
            {
                switch (value)
                {
                case SpectrumFileType.CSV:
                    this.single_suffix = ".csv";
                    break;

                default:
                    this.single_suffix = ".csv";
                    break;
                }

                this.single_filetype = value;
            }
        }

        public SpectrumFileType StreamFiletype
        {
            get
            {
                return this.stream_filetype;
            }
            set
            {
                switch (value)
                {
                case SpectrumFileType.CSV:
                    this.stream_suffix = ".csv";
                    break;

                default:
                    this.stream_suffix = ".csv";
                    break;
                }

                this.stream_filetype = value;
            }
        }

        public DirectoryInfo Info { get; }

        public bool Active         { get; set; } = true;
        public bool AutoSaveSingle { get; set; } = false;
        public bool AutoSaveStream { get; set; } = false;

        public string SingleFilemask  { get; set; }
        public string StreamFilemask  { get; set; }
        public string SpectrumComment { get; set; }

        public bool HasComment => string.IsNullOrEmpty(this.SpectrumComment) == false;
    }
}