<commit_before>﻿using FujiyNotepad.UI.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace FujiyNotepad.UI
{
    /// <summary>
    /// Interaction logic for FujiyTextBox.xaml
    /// </summary>
    public partial class FujiyTextBox : UserControl
    {
        MemoryMappedFile mFile;
        long fileSize;
        string filePath;
        long viewPortSize = 1024 * 1024 * 1024;//TODO precisa ser dinamico
        StringBuilder sb = new StringBuilder();
        long maximumStartOffset;
        TextSearcher searcher;
        public LineIndexer LineIndexer { get; set; }
        long lastOffset;

        public FujiyTextBox()
        {
            InitializeComponent();
            TxtContent.Margin = new Thickness(0, 0, ContentScrollBar.Width, 0);
        }

        public void OpenFile(string filePath)
        {
            if (mFile != null)
            {
                mFile.Dispose();//TODO pensar em uma forma melhor de clean, talvez remover todo o User Control
            }

            this.filePath = filePath;
            fileSize = new FileInfo(filePath).Length;

            maximumStartOffset = GetMaximumStartOffset();//TODO precisa atualizar sempre que fizer resize

            mFile = MemoryMappedFile.CreateFromFile(filePath, FileMode.Open, null, 0, MemoryMappedFileAccess.Read);

            searcher = new TextSearcher(mFile, fileSize);
            LineIndexer = new LineIndexer(searcher);

            GoToOffset(0);
        }

        public void GoToLineNumber(int lineNumber)
        {
            if (LineIndexer.GetNumberOfLinesIndexed() > lineNumber)
            {
                long offset = LineIndexer.GetOffsetFromLineNumber(lineNumber);

                UpdateScrollBarFromOffset(offset);

                GoToOffset(offset);
            }
            else
            {
                if (LineIndexer.IsCompleted)
                {
                    //TODO mensagem
                }
                else
                {
                    //TODO mensagem
                }

            }
        }

        private void UpdateScrollBarFromOffset(long offset)
        {
            double newScrollValue = offset * ContentScrollBar.Maximum / fileSize;
            ContentScrollBar.Value = newScrollValue;
        }

        private void ScrollBar_Scroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e)
        {
            //TODO evitar que seja chamado varias vezes em menos de 100ms
            long startOffset = (long)(fileSize * e.NewValue / ContentScrollBar.Maximum);

            GoToOffset(startOffset);
        }

        private void GoToOffset(long startOffset)
        {
            startOffset = Math.Min(startOffset, maximumStartOffset);

            startOffset = searcher.SearchNewLineBefore(startOffset);
            lastOffset = startOffset;
            long length = GetLengthToFillViewport(startOffset);

            Debug.Assert(length > 0);

            using (var stream = mFile.CreateViewStream(startOffset, length, MemoryMappedFileAccess.Read))
            using (var streamReader = new StreamReader(stream))
            {
                sb.Clear();
                int linesInVewport = CountVisibleLines();
                for (int i = 0; i < linesInVewport && streamReader.EndOfStream == false; i++)
                {
                    if (i == linesInVewport - 1)
                    {
                        sb.Append(streamReader.ReadLine());
                    }
                    else
                    {
                        sb.AppendLine(streamReader.ReadLine());
                    }
                }

                TxtContent.Text = sb.ToString();
            }
        }

        private long GetLengthToFillViewport(long startOffset)
        {
            int linesInVewport = CountVisibleLines();
            var nextLineOffset = searcher.SearchInFile(startOffset, '\n', new Progress<int>()).Take(linesInVewport).LastOrDefault();
            if (nextLineOffset != default(long))
            {
                return nextLineOffset;
            }
            return fileSize - startOffset;
        }

        private long GetMaximumStartOffset()
        {
            using (var fs = File.OpenRead(filePath))
            {
                fs.Seek(0, SeekOrigin.End);
                int newLines = 0;
                int visibleLines = CountVisibleLines();

                while (newLines < visibleLines && fs.Position > 0)//TODO testar arquivo pequeno<commit_msg>Length fix<commit_after>﻿using FujiyNotepad.UI.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace FujiyNotepad.UI
{
    /// <summary>
    /// Interaction logic for FujiyTextBox.xaml
    /// </summary>
    public partial class FujiyTextBox : UserControl
    {
        MemoryMappedFile mFile;
        long fileSize;
        string filePath;
        long viewPortSize = 1024 * 1024 * 1024;//TODO precisa ser dinamico
        StringBuilder sb = new StringBuilder();
        long maximumStartOffset;
        TextSearcher searcher;
        public LineIndexer LineIndexer { get; set; }
        long lastOffset;

        public FujiyTextBox()
        {
            InitializeComponent();
            TxtContent.Margin = new Thickness(0, 0, ContentScrollBar.Width, 0);
        }

        public void OpenFile(string filePath)
        {
            if (mFile != null)
            {
                mFile.Dispose();//TODO pensar em uma forma melhor de clean, talvez remover todo o User Control
            }

            this.filePath = filePath;
            fileSize = new FileInfo(filePath).Length;

            maximumStartOffset = GetMaximumStartOffset();//TODO precisa atualizar sempre que fizer resize

            mFile = MemoryMappedFile.CreateFromFile(filePath, FileMode.Open, null, 0, MemoryMappedFileAccess.Read);

            searcher = new TextSearcher(mFile, fileSize);
            LineIndexer = new LineIndexer(searcher);

            GoToOffset(0);
        }

        public void GoToLineNumber(int lineNumber)
        {
            if (LineIndexer.GetNumberOfLinesIndexed() > lineNumber)
            {
                long offset = LineIndexer.GetOffsetFromLineNumber(lineNumber);

                UpdateScrollBarFromOffset(offset);

                GoToOffset(offset);
            }
            else
            {
                if (LineIndexer.IsCompleted)
                {
                    //TODO mensagem
                }
                else
                {
                    //TODO mensagem
                }

            }
        }

        private void UpdateScrollBarFromOffset(long offset)
        {
            double newScrollValue = offset * ContentScrollBar.Maximum / fileSize;
            ContentScrollBar.Value = newScrollValue;
        }

        private void ScrollBar_Scroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e)
        {
            //TODO evitar que seja chamado varias vezes em menos de 100ms
            long startOffset = (long)(fileSize * e.NewValue / ContentScrollBar.Maximum);

            GoToOffset(startOffset);
        }

        private void GoToOffset(long startOffset)
        {
            startOffset = Math.Min(startOffset, maximumStartOffset);

            startOffset = searcher.SearchNewLineBefore(startOffset);
            lastOffset = startOffset;
            long length = GetLengthToFillViewport(startOffset);

            Debug.Assert(length > 0);

            using (var stream = mFile.CreateViewStream(startOffset, length, MemoryMappedFileAccess.Read))
            using (var streamReader = new StreamReader(stream))
            {
                sb.Clear();
                int linesInVewport = CountVisibleLines();
                for (int i = 0; i < linesInVewport && streamReader.EndOfStream == false; i++)
                {
                    if (i == linesInVewport - 1)
                    {
                        sb.Append(streamReader.ReadLine());
                    }
                    else
                    {
                        sb.AppendLine(streamReader.ReadLine());
                    }
                }

                TxtContent.Text = sb.ToString();
            }
        }

        private long GetLengthToFillViewport(long startOffset)
        {
            int linesInVewport = CountVisibleLines();
            var nextLineOffset = searcher.SearchInFile(startOffset, '\n', new Progress<int>()).Take(linesInVewport).LastOrDefault();
            if (nextLineOffset != default(long))
            {
                return nextLineOffset - startOffset;
            }
            return fileSize - startOffset;
        }

        private long GetMaximumStartOffset()
        {
            using (var fs = File.OpenRead(filePath))
            {
                fs.Seek(0, SeekOrigin.End);
                int newLines = 0;
                int visibleLines = CountVisibleLines();

                while (newLines < visibleLines && fs.Position > 0)//TODO testar arquivo pequeno
{'fraction_non_alphanumeric': 0.0807805075320999, 'fraction_numerical': 0.005257304620361945, 'mean_word_length': 1.748541261461517, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1445891', 'n_tokens_mistral': 2631, 'n_tokens_neox': 2484, 'n_words': 569}