// Created with MonoDevelop
//
//    Copyright (C) 2018 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.Text.RegularExpressions;
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;

using Hiperscan.Unix;

namespace Hiperscan.SGS.Benchtop.FinderSetup
{

    [Serializable()]
    public class MotorParameter
    {
        public byte OTPAddress { set; get; }
        public byte Value      { set; get; }
        
        public MotorParameter()
        {
        }

        public MotorParameter(byte otp_address, byte val)
        {
            this.OTPAddress = otp_address;
            this.Value = val;
        }

        public byte[] ToArray()
        {
            return new byte[] { this.OTPAddress, this.Value };
        }
    }
    
    [Serializable()]
    public class FinderConfig
    {
        public List<MotorParameter> MotorParameters { set; get; }

        public byte Dimmer       { set; get; }
        public uint SleepTimeout { set; get; }

        public byte   TemperatureControlVersion { set; get; }
        public byte   TemperatureControlValue   { set; get; }
        public double TemperatureControlTarget  { set; get; }

        public List<byte> VersionBytes         { set; get; }
        public List<byte> VersionByteOverrides { set; get; }
        public SampleHolderType SampleHolderType { get; set; }


        public FinderConfig()
        {
        }

        public static FinderConfig Read(string fname)
        {
            try
            {
                using (Stream stream = new FileStream(fname, FileMode.Open, FileAccess.Read))
                {
                    XmlSerializer serializer = new XmlSerializer(typeof(FinderConfig));
                    FinderConfig config = (FinderConfig)serializer.Deserialize(stream);

                    if (config == null)
                        throw new Exception(Catalog.GetString("Error while deserialisation."));

                    return config;
                }
            }
            catch (FormatException)
            {
                // FIXME: The following hack is necessary for Mono ARM < Version 3.4, since there is an error in double.Parse()
                //        This code should be removed if the bugfix in Mono went upstream
                string content = FileIO.ReadFileToEndWithEncodingFromBOM(fname);

                MatchCollection matches = Regex.Matches(content, @">[0-9]+\.*[0-9]*<");

                foreach (Match match in matches)
                {
                    double value;

                    string[] s = match.ToString().Replace("<", "").Replace(">", "").Split(new char[] {'.'});
                    if (s.Length == 1)
                    {
                        value = double.Parse(s[0]) * 10.0;
                    }
                    else if (s.Length == 2 && s[1].Length == 1)
                    {
                        value = double.Parse(s[0]) * 10.0 + double.Parse(s[1]);
                    }
                    else
                    {
                        throw new NotSupportedException("Bugfixing for decimal numbers with more than one digits after decimal separator is not supported.");
                    }

                    content = content.Replace(match.ToString(), ">" + value.ToString("f0") + "<");
                }

                XmlSerializer serializer = new XmlSerializer(typeof(FinderConfig));
                FinderConfig config = (FinderConfig)serializer.Deserialize(new StringReader(content));

                config.TemperatureControlTarget /= 10.0;

                if (config == null)
                    throw new Exception(Catalog.GetString("Error while deserialisation."));

                return config;
            }
        }

        public static void Write(FinderConfig finder_config, string fname)
        {
            using (Stream stream = new FileStream(fname, FileMode.Create))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(FinderConfig));
                serializer.Serialize(stream, finder_config);
            }
        }

        public static void CreateTemplate(string fname)
        {
            FinderConfig config = new FinderConfig();

            // default config values
            config.MotorParameters = new List<MotorParameter>
            {
                new MotorParameter(3, 172),
                new MotorParameter(4, 1),
                new MotorParameter(5, 1),
                new MotorParameter(7, 12)
            };

            // disable I2C address parameter
            //this.MotorParameters.Add(new MotorParameter(2, 0));

            config.Dimmer = 107;
            config.SleepTimeout = 0;

            config.TemperatureControlVersion = 1;
            config.TemperatureControlValue   = 140;
            config.TemperatureControlTarget  = 55.5;

            config.VersionBytes         = new List<byte> {   3,   7,   4,   5 };
            config.VersionByteOverrides = new List<byte> { 255, 255, 255, 255 };

            FinderConfig.Write(config, fname);
        }
    }
}
