using System;
using System.Globalization;
using System.Text;
using Tellert.Til;

namespace view_tms
{
    class ViewTms
    {
        static int Main(string[] args)
        {
            // Ignore current culture settings for compatibility with the "C" version of VIEW_TMS.EXE
            System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");

            if (args.Length < 1)
            {
                Console.WriteLine("VIEW_TMS V1.3.3 - Copyright (c) 2014-2018 Rudy Tellert Elektronik");
                Console.WriteLine("SYNTAX: VIEW_TMS filename.tms");
                return 87;
            }

            using (Til til = new Til())
            {
                if (til.Load(args[0]))
                {
                    uint g = 0;
                    foreach (Til.Group group in til.Groups)
                    {

                        Console.WriteLine(Console.Out.NewLine + "Group " + (g + 1) + "/" + til.Groups.Length + ":");
                        Console.WriteLine("  SampleCount = " + group.SampleCount);
                        Console.WriteLine("  SampleRate = " + group.SampleRate + " s");
                        if (group.Time.DeviceSetup.IsAvailable) Console.WriteLine("  HWSetup = " + group.Time.DeviceSetup);
                        if (group.Time.Start.IsAvailable) Console.WriteLine("  Start = " + group.Time.Start);
                        if (group.Time.DeviceReadOut.IsAvailable) Console.WriteLine("  HWReadOut = " + group.Time.DeviceReadOut);

                        for (uint n = 0; n < group.Time.Sections.Length; n++)
                        {

                            ulong lastSampleIndex = (n + 1 != group.Time.Sections.Length) ?
                              group.Time.Sections[n + 1].SampleOffset : group.SampleCount;

                            if (lastSampleIndex != 0) lastSampleIndex--;
                            Console.Write("  Sample range of section" + (n + 1) + " = [" +
                              group.Time.Sections[n].SampleOffset + ";" + lastSampleIndex + "]");
                            Console.WriteLine(group.Time.Sections[n].Start.IsAvailable ?
                              (" at " + group.Time.Sections[n].Start) : "");
                        }

                        double[][] values = new double[group.Signals.Length][];
#if DEBUG
                        double[][] valuesFromRaw = new double[group.Signals.Length][];
#endif
                        uint s = 0;
                        foreach (Til.Signal signal in group.Signals)
                        {
                            Console.WriteLine(Console.Out.NewLine + "  Signal " + (s + 1) + "/" +
                                group.Signals.Length + ((s == 0) ? " (= Reference Signal):" : ":"));
                            Console.WriteLine("    Name = " + signal.Name);
                            Console.WriteLine("    Unit = " + signal.Unit);
                            Console.WriteLine("    DataType = " + GetDataTypeString(signal.Raw.DataType, group.SampleCount));
                            Console.WriteLine("    Factor = " + signal.Raw.Factor);
                            Console.WriteLine("    Offset = " + signal.Raw.Offset);
                            if (signal.Raw.Storage.FileName.Length != 0)
                            {
                                Console.WriteLine("    FileName = " + signal.Raw.Storage.FileName);
                                Console.WriteLine("    FileOffset = " + signal.Raw.Storage.Offset);
                                Console.WriteLine("    FileDataSize = " + signal.Raw.Storage.DataSize);
                                Console.WriteLine("    FileGap = " + signal.Raw.Storage.Gap);
                            }
                            Console.WriteLine("    FlagQuantized = " + (signal.Attributes.Quantized ? 1 : 0));
                            Console.WriteLine("    ViewMin = " + signal.ViewDefaults.Min);
                            Console.WriteLine("    ViewMax = " + signal.ViewDefaults.Max);

                            signal.Iterator.CopyTo(out values[s]);
#if DEBUG
                            signal.Raw.ConvertTo(out valuesFromRaw[s]);
#endif
                            s++;
                        }

                        Console.WriteLine(Console.Out.NewLine + "  Sample values:");
                        for (ulong k = 0; k < group.SampleCount; k++)
                        {
                            for (s = 0; s < group.Signals.Length; s++)
                            {
#if DEBUG
                                if (values[s][k] != valuesFromRaw[s][k]) throw new Til.Exception("Unexpected sample value mismatch!");
#endif
                                if (s == 0) Console.Write("    ");
                                Console.Write(values[s][k]);
                                Console.Write((s + 1 == group.Signals.Length) ? Console.Out.NewLine : "\t");
                            }
                        }

                        g++;
                    }
                }
            }

            return 0;
        }

        private static string GetDataTypeString(Til.DataType dataType, UInt64 sampleCount)
        {
            switch (dataType)
            {
                case Til.DataType.SampleNumber:
                    return "sample number [0;" + (sampleCount - 1) + "]; size: 0 bytes";

                case Til.DataType.LeUInt8:
                    return "unsigned char (Intel); size: 1 byte";

                case Til.DataType.LeInt8:
                    return "signed char (Intel); size: 1 byte";

                case Til.DataType.LeUInt16:
                    return "unsigned short (Intel); size: 2 bytes";

                case Til.DataType.LeInt16:
                    return "signed short (Intel); size: 2 bytes";

                case Til.DataType.LeUInt32:
                    return "unsigned long (Intel); size: 4 bytes";

                case Til.DataType.LeInt32:
                    return "signed long (Intel); size: 4 bytes";

                case Til.DataType.LeUInt64:
                    return "unsigned __int64 (Intel); size: 8 bytes";

                case Til.DataType.LeInt64:
                    return "signed __int64 (Intel); size: 8 bytes";

                case Til.DataType.LeFloat32:
                    return "float (Intel); size: 4 bytes";

                case Til.DataType.LeFloat64:
                    return "double (Intel); size: 8 bytes";

                case Til.DataType.RsvdLeFloat80:
                    return "long double (Intel); size: 10 bytes";
            }

            return "unknown";
        }
    }
}
