// Created with MonoDevelop
//
//    Copyright (C) 2009 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.Collections.Generic;
using System.Globalization;
using System.IO;

using Hiperscan.Unix;


namespace Hiperscan.Spectroscopy.IO
{
    public static partial class CSV
    {

        public static DataSet ReadDataSet(string fname)
        {
            using (Stream stream = new FileStream(fname, FileMode.Open))
            {
                return CSV.ReadDataSet(stream);
            }
        }

        public static DataSet ReadDataSet(Stream stream)
        {
            CultureInfo culture = CultureInfo.InvariantCulture;

            using (StreamReader reader = new StreamReader(stream))
            {
                List<double> x = new List<double>();
                List<double> y = new List<double>();

                while (reader.EndOfStream == false)
                {
                    string line = reader.ReadLine();
                    string[] s = line.Split(culture.TextInfo.ListSeparator.ToCharArray());
                    x.Add(double.Parse(s[0], culture));
                    y.Add(double.Parse(s[1], culture));
                }

                return new DataSet(x, y);
            }
        }

        public static void Write(DataSet ds, string fname)
        {
            CSV.Write(ds, null, fname);
        }

        public static void Write(DataSet ds, string header, string fname)
        {
            CultureInfo culture = CultureInfo.InvariantCulture;

            if (Path.GetExtension(fname).ToLower() != ".csv")
                fname = Path.ChangeExtension(fname, ".csv");

            using (var stream = new FileIO.FileStreamWriter(fname))
            {

                if (string.IsNullOrEmpty(header) == false)
                    stream.WriteLine(header.TrimEnd(new char[] { '\n' }));

                for (int ix = 0; ix < ds.Count; ++ix)
                {
                    stream.WriteLine(ds.X[ix].ToString(culture) + culture.TextInfo.ListSeparator + ds.Y[ix].ToString(culture));
                }
            }
        }

        public static void Write(List<string> headers, List<DataSet> data_sets, double delta_x, string fname)
        {
            if (Path.GetExtension(fname).ToLower() != ".csv")
                fname = Path.ChangeExtension(fname, ".csv");

            using (var stream = new FileIO.FileStreamWriter(fname))
                CSV.Write(headers, data_sets, delta_x, stream);
        }

        public static void Write(List<string> headers, List<DataSet> data_sets, double delta_x, StreamWriter stream)
        {
            CultureInfo culture = CultureInfo.InvariantCulture;

            if (data_sets == null || data_sets.Count < 1)
                throw new Exception(Catalog.GetString("Cannot write empty or invalid data sets."));

            double xmin = double.MinValue, xmax = double.MaxValue;
            foreach (DataSet ds in data_sets)
            {
                double min = ds.XMin();
                if (min > xmin)
                    xmin = min;

                double max = ds.XMax();
                if (max < xmax)
                    xmax = max;
            }

            if (xmin.Equals(double.MinValue) || xmax.Equals(double.MaxValue))
                throw new Exception(Catalog.GetString("Cannot write empty or invalid data sets."));

            // find gaps
            List<Tuple<double,double>> gaps = new List<Tuple<double,double>>();
            foreach (int gap_ix in data_sets[0].Gaps)
            {
                Tuple<double,double> gap = new Tuple<double,double>(data_sets[0].X[gap_ix-1], data_sets[0].X[gap_ix]);
                gaps.Add(gap);
            }

            List<double> xi = new List<double>();
            if (data_sets[0].IsContinuous)
            {
                double x0 = System.Math.Ceiling(xmin);
                for (int ix = 0; x0 + ((double)ix * delta_x) <= xmax; ++ix)
                {
                    double x = x0 + (double)ix * delta_x;

                    bool is_gap = false;
                    foreach (Tuple<double,double> gap in gaps)
                    {
                        if (x > gap.Item1 && x < gap.Item2)
                            is_gap = true;
                    }

                    if (is_gap)
                        continue;

                    xi.Add(x);
                }
            }
            else
            {
                xi = new List<double>(data_sets[0].X);
            }

            List<DataSet> idata_sets = new List<DataSet>();
            foreach (DataSet ds in data_sets)
            {
                idata_sets.Add(ds.Interpolate(xi, InterpolationType.NaturalCubic));
            }

            if (headers != null)
            {
                for (int ix = 0; ix < headers.Count; ++ix)
                {
                    stream.Write(headers[ix]);
                    if (ix < headers.Count - 1)
                        stream.Write(culture.TextInfo.ListSeparator);
                    else
                        stream.WriteLine();
                }
            }

            for (int ix = 0; ix < idata_sets[0].Count; ++ix)
            {
                stream.Write(idata_sets[0].X[ix].ToString(culture) + culture.TextInfo.ListSeparator);

                for (int jx = 0; jx < idata_sets.Count; ++jx)
                {
                    stream.Write(idata_sets[jx].Y[ix].ToString(culture));
                    if (jx < idata_sets.Count - 1)
                        stream.Write(culture.TextInfo.ListSeparator);
                    else
                        stream.WriteLine();
                }
            }
        }
    }
}
