/**
 * SphericalLib.DatReader
 * 
 * SphericalLib is a .NET library to deal with geometry on the unit sphere.
 * It is intented to be used for complex survey footprint descriptions in
 * standalone applications as well as in web services and perhaps Yukon.
 * 
 * Written by Tamas Budavari (budavari@pha.jhu.edu)
 * See bottom of file for revision history
 * 
 * Current revision:
 *   ID:          $Id: DatReader.cs,v 1.1.1.1 2006/11/14 02:56:39 gupchup Exp $
 *   Revision:    $Revision: 1.1.1.1 $
 *   Date:        $Date: 2006/11/14 02:56:39 $
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Spherical;

namespace Spherical.IO
{
    /// <summary>
    /// This class implements methods to read objects of SphericalLib
    /// from binary files, see also BinWriter.
    /// </summary>
    [CLSCompliant(true)]
    public class DatReader
    {
        private TextReader reader;

        /// <summary>
        /// Create reader from filename
        /// </summary>
        /// <param name="path"></param>
        public DatReader(string path)
        {
            FileStream input = new FileStream(path, FileMode.Open);
            reader = new StreamReader(input);
        }

        /// <summary>
        /// Create reader from stream
        /// </summary>
        /// <param name="input"></param>
        public DatReader(TextReader input)
        {
            reader = input;
        }


        /// <summary>
        /// Close reader
        /// </summary>
        public void Close()
        {
            reader.Close();
        }

        private string OneSpace(string line)
        {
            // only spaces after this (hopefully)
            string proc = line.Trim().Replace("\r\n", " ").Replace('\n', ' ').Replace('\t', ' ');

            // replace duplicate spaces with a single one
            string trim = "";
            while (trim != proc)
            {
                trim = proc;
                proc = trim.Replace("  ", " ");
            }
            return trim;
        }

        /// <summary>
        /// Read next set of points
        /// </summary>
        /// <param name="list">points list</param>
        /// <param name="mid">internal point</param>
        /// <returns>ID of polygon</returns>
        public int NextPointList(List<Cartesian> list, double min_arcsec, out Cartesian mid)
        {
            Cartesian curr, last;
            double lon, lat;
            // 1st line has id and middle point (i think)
            string line = reader.ReadLine();
            string[] tok = OneSpace(line).Split();
            //Console.Out.WriteLine("# of tokens: {0}", tok.Length);
            int id = int.Parse(tok[0]);
            lon = double.Parse(tok[1]);
            lat = double.Parse(tok[2]);
            mid = new Cartesian(lon+180, lat);

            double angle, total_angle;
            total_angle = 0;
            // rest has only angles
            last = Cartesian.NaN;
            while (!(line = reader.ReadLine()).StartsWith("END"))
            {
                tok = OneSpace(line).Split();
                lon = double.Parse(tok[0]);
                lat = double.Parse(tok[1]);
                curr = new Cartesian(lon+180, lat);
                if (last != Cartesian.NaN && (curr == last || curr.Cross(last,false).Norm < double.Epsilon))
                {
                    //Console.Error.WriteLine("DatReader.NextPointList(): Warning: duplicated point");
                }
                else if (curr.AngleInArcmin(last) < min_arcsec/60)
                {
                    //Console.Error.WriteLine("DatReader.NextPointList(): point too close to previous - ignored!");
                }
                else
                {
                    Cartesian vc = curr.Sub(mid.Scaled(mid.Dot(curr)));
                    Cartesian vl = last.Sub(mid.Scaled(mid.Dot(last)));
                    angle = Math.Asin(vc.Cross(vl, false).Norm) * Const.Radian2Degree;
                    //Console.Error.WriteLine(angle);
                    if (!double.IsNaN(angle))
                        total_angle += angle;
                    list.Add(curr);
                    last = curr;
                }
            }
            //Console.Error.WriteLine("Total angle: {0}", total_angle);
            if (total_angle < 1)
                list.Reverse();
            list.RemoveAt(0);
            return id;
        }

        /// <summary>
        /// Revision from CVS
        /// </summary>
        public static string Revision
        {
            get { return "$Revision: 1.1.1.1 $"; }
        }

    }
}

#region Revision History
/* Revision History

        $Log: DatReader.cs,v $
        Revision 1.1.1.1  2006/11/14 02:56:39  gupchup
        no message

        Revision 1.4  2006/05/17 13:44:11  budavari
        lon-lat bug fixed

        Revision 1.3  2006/04/19 16:52:13  budavari
        EVerything is now CLS compliant

        Revision 1.2  2006/03/31 15:28:03  budavari
        Exlclude one of duplate points

        Revision 1.1  2006/03/09 20:31:12  budavari
        Added DatReader class - not ready yet

*/
#endregion