/// <summary>
 /// Determines the encoding of a file
 /// </summary>
 /// <returns></returns>
 public static Encoding GetEncoding(this FileInfo source)
 {
     using (var stream = File.Open(source.FullName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite))
     {
         using (var reader = new StreamReaderExtended(stream, true))
         {
             var something = reader.Peek();
             return reader.CurrentEncoding;
         }
     }
 }
        public IEnumerable<FileSegment> LoadSegments()
        {
            using (var stream = File.Open(_info.FullName, FileMode.Open, FileAccess.Read,FileShare.Delete | FileShare.ReadWrite))
            {
                var fileLength = stream.Length;

                stream.Seek(0, SeekOrigin.Begin);
                using (var reader = new StreamReaderExtended(stream, true))
                {
                    if (reader.EndOfStream ||  fileLength == 0)
                    {
                        yield return new FileSegment(0, 0, 0, FileSegmentType.Tail);
                        yield break;
                    }

                    if (fileLength < _initialTail)
                    {
                        yield return new FileSegment(0, 0, fileLength, FileSegmentType.Tail);
                        yield break;
                    }

                    var headStartsAt = reader.FindNextEndOfLinePosition(fileLength - _initialTail);
                    long currentEnfOfPage = 0;
                    long previousEndOfPage = 0;

                    int index = 0;
                    do
                    {
                        var approximateEndOfPage = currentEnfOfPage + _segmentSize;
                        if (approximateEndOfPage >= headStartsAt)
                        {
                            yield return new FileSegment(index, previousEndOfPage, headStartsAt, FileSegmentType.Head);
                            break;
                        }
                        currentEnfOfPage = reader.FindNextEndOfLinePosition(approximateEndOfPage);
                        yield return new FileSegment(index, previousEndOfPage, currentEnfOfPage, FileSegmentType.Head);

                        index++;
                        previousEndOfPage = currentEnfOfPage;

                    } while (true);


                    index ++;
                    yield return new FileSegment(index, headStartsAt, fileLength, FileSegmentType.Tail);
                }
            }
        }
        private IEnumerable<Line> ReadLinesByIndex(ScrollRequest scroll)
        {

            var page = GetPage(scroll);

            var relativeIndex = CalculateRelativeIndex(page.Start);
            if (relativeIndex == null) yield break;

            var offset = relativeIndex.LinesOffset;

            using (var stream = File.Open(Info.FullName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite))
            {
                using (var reader = new StreamReaderExtended(stream, Encoding, false))
                {
                    //go to starting point
                    stream.Seek(relativeIndex.Start, SeekOrigin.Begin);
                    if (offset > 0)
                    {
                        //skip number of lines offset
                        for (int i = 0; i < offset; i++)
                            reader.ReadLine();
                    }

                    //if estimate move to the next start of line
                    if (relativeIndex.IsEstimate && relativeIndex.Start != 0)
                        reader.ReadLine();

                    foreach (var i in Enumerable.Range(page.Start, page.Size))
                    {
                        var startPosition = reader.AbsolutePosition();
                        var line = reader.ReadLine();
                        var endPosition = reader.AbsolutePosition();
                        var info = new LineInfo(i + 1, i, startPosition, endPosition);

                        var ontail = startPosition >= TailInfo.TailStartsAt && DateTime.Now.Subtract(TailInfo.LastTail).TotalSeconds < 1
                            ? DateTime.Now
                            : (DateTime?)null;

                        yield return new Line(info, line, ontail);
                    }
                }
            }
        }
        private FileSegmentSearchResult Search(long start, long end)
        {
            long lastPosition = 0;
            using (var stream = File.Open(Info.FullName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite))
            {

                if (stream.Length < start)
                {
                    start = 0;
                    end = stream.Length;
                }
                long[] lines;
                using (var reader = new StreamReaderExtended(stream, true))
                {
                    stream.Seek(start, SeekOrigin.Begin);
                    if (reader.EndOfStream)
                        return new FileSegmentSearchResult(start,end);

                    lines = reader.SearchLines(_predicate, i => i, (line, position) =>
                    {
                        lastPosition = position;//this is end of line po
                        return end != -1 && lastPosition > end;

                    }).ToArray();
                }
                return new FileSegmentSearchResult(start, lastPosition, lines);
            }
        }
        private IEnumerable<Line> ReadLinesByPosition(ScrollRequest scroll)
        {

            //TODO: Calculate initial index of first item.

   
            //scroll from specified position

            using (var stream = File.Open(Info.FullName, FileMode.Open, FileAccess.Read,FileShare.Delete | FileShare.ReadWrite))
            {
                int taken = 0;
                using (var reader = new StreamReaderExtended(stream, Encoding, false))
                {

                    var startPosition = scroll.Position;
                    var first = (int)CalculateIndexByPositon(startPosition);
                    reader.BaseStream.Seek(startPosition, SeekOrigin.Begin);

                    do
                    {

                        var line = reader.ReadLine();
                        if (line==null) yield break;

                        var endPosition = reader.AbsolutePosition();

                        var info = new LineInfo(first + taken + 1, first + taken, startPosition, endPosition);
                        var ontail = endPosition >= TailInfo.TailStartsAt && DateTime.Now.Subtract(TailInfo.LastTail).TotalSeconds < 1
                            ? DateTime.Now
                            : (DateTime?)null;

                        yield return new Line(info, line, ontail);

                        startPosition = endPosition;
                        taken++;

                    } while (taken < scroll.PageSize);
                }
            }
        }
        /// <summary>
        /// Finds the delimiter by looking for the first line in the file and comparing chars
        /// </summary>
        /// <param name="source">The source.</param>
        /// <returns></returns>
        public static int FindDelimiter(this FileInfo source)
        {
            using (var stream = File.Open(source.FullName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite))
            {
                using (var reader = new StreamReaderExtended(stream, Encoding.Default, true))
                {
                    if (reader.EndOfStream)
                        return -1;
                    do
                    {
                        var ch = (char)reader.Read();

                        // Note the following common line feed chars: 
                        // \n - UNIX   \r\n - DOS   \r - Mac 
                        switch (ch)
                        {
                            case '\r':
                                var next = (char)reader.Peek();
                                //with \n is WINDOWS delimiter. Otherwise mac
                                return next == '\n' ? 2 : 1;
                            case '\n':
                                return 1;
                        }
                    } while (!reader.EndOfStream);
                    return -1;
                }
            }
        }
        public static IEnumerable<Line> ReadLinesByPosition(this FileInfo source, long[] positions, Func<int, bool> isEndOfTail = null)
        {
            using (var stream = File.Open(source.FullName, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.ReadWrite))
            {
                using (var reader = new StreamReaderExtended(stream, Encoding.Default, true))
                {
                    foreach (var position in positions)
                    {
                        if (reader.AbsolutePosition() != position)
                        {
                            reader.DiscardBufferedData();
                            stream.Seek(position, SeekOrigin.Begin);

                        }
                        var line = reader.ReadLine();
                        yield return new Line((int)position, line,null);
                    }
                }
            }
        }