<commit_before>﻿/*----------------------------------------------------------
This Source Code Form is subject to the terms of the 
Mozilla Public License, v.2.0. If a copy of the MPL 
was not distributed with this file, You can obtain one 
at http://mozilla.org/MPL/2.0/.
----------------------------------------------------------*/

using System;
using System.IO;
using System.Text;

using ScriptEngine.Machine;
using ScriptEngine.Machine.Contexts;

namespace ScriptEngine.HostedScript.Library.Binary
{
    /// <summary>
    /// 
    /// Объект предназначен для удобной записи различных типов данных в приемник.
    /// Необходимо соблюдать следующий порядок работы с данным объектом:
    /// 
    ///  - Создать или получить приемник даных.
    ///  - Вызвать из приемника экземпляр объекта ЗаписьДанных.
    ///  - Выполнить требуемые действия с помощью объекта.
    ///  - Закрыть экземпляр объекта ЗаписьДанных.
    /// При необходимости использовать другие методы для работы с данными, требуется сначала закрыть экземпляр объекта ЗаписьДанных с помощью метода Закрыть, выполнить необходимые действия над данными, установить требуемую позицию для чтения из приемника и создать новый экземпляр ЗаписьДанных.
    /// </summary>
    [ContextClass("ЗаписьДанных", "DataWriter")]
    public class DataWriter : AutoContext<DataWriter>, IDisposable
    {

        private Encoding _workingEncoding;
        private IValue _userVisibleEncoding;
        private BinaryWriter _binaryWriter;
        private readonly bool _writeBOM;
    
        public DataWriter(string fileName, IValue textEncoding, ByteOrderEnum? byteOrder, string lineSplitter, bool append, string convertibleSplitterOfLines, bool writeBOM)
        {
            ByteOrder = byteOrder?? ByteOrderEnum.LittleEndian;
            LineSplitter = lineSplitter?? "\r\n";
            ConvertibleSplitterOfLines = convertibleSplitterOfLines;
            _writeBOM = writeBOM;
            TextEncoding = textEncoding;

            var fileSubsystem = new FileStreamsManager();
            var fileStreamContext = append ? fileSubsystem.OpenForAppend(fileName) : fileSubsystem.OpenForWrite(fileName);

            _binaryWriter = new BinaryWriter(fileStreamContext.GetUnderlyingStream(), _workingEncoding);
        
        }

        public DataWriter(IStreamWrapper streamObj, IValue textEncoding, ByteOrderEnum? byteOrder, string lineSplitter, string convertibleSplitterOfLines, bool writeBOM)
        {
            ByteOrder = byteOrder?? ByteOrderEnum.LittleEndian;
            LineSplitter = lineSplitter ?? "\r\n";
            ConvertibleSplitterOfLines = convertibleSplitterOfLines;
            _writeBOM = writeBOM;
            TextEncoding = textEncoding;

            _binaryWriter = new BinaryWriter(streamObj.GetUnderlyingStream(), _workingEncoding);
        
        }

        /// <summary>
        /// 
        /// Создает объект ЗаписьДанных для записи в указанный файл. Если файл с таким именем не существует, он будет создан. Параметр &lt;Дописать&gt; определяет, будут ли данные записаны в начало или в конец файла.
        /// После завершения работы с объектом, до закрытия потока, переданного в конструктор, объект необходимо закрыть с помощью метода Закрыть или НачатьЗакрытие. При этом используемый файл будет закрыт автоматически.
        /// </summary>
        ///
        /// <param name="fileName">
        /// Имя файла, в который будет выполнена запись. </param>
        /// <param name="textEncoding">
        /// Кодировка текста для создаваемого экземпляра ЗаписьДанных. Если не задана, то используется UTF-8.
        /// Значение по умолчанию: UTF8. Типы: КодировкаТекста (TextEncoding), Строка (String) </param>
        /// <param name="byteOrder">
        /// Порядок байтов, используемый по умолчанию для кодирования целых чисел при записи в поток.
        /// Значение по умолчанию: LittleEndian. </param>
        /// <param name="lineSplitter">
        /// Разделитель по умолчанию для строк, записываемых в поток. Если разделитель строк не задан, то используется строка ПС.
        /// Значение по умолчанию: ПС. </param>
        /// <param name="append">
        /// Определяет, будут ли данные записаны в начало или в конец файла:
        /// 
        ///  - Если Истина, то при открытии существующего файла запись будет выполнена в конец файла.
        ///  - Иначе данные будут записываться с начала файла, перезаписывая существующие данные.
        /// Если заданный файл не существует, будет создан новый файл с указанным именем и значение параметра не повлияет на поведение конструктора.
        /// Значение по умолчанию: Ложь. </param>
        /// <param name="convertibleSplitterOfLines">
        /// Определяет разделение строк в файле для конвертации в стандартный перевод строк ПС.
        /// Значение по умолчанию: ВК + ПС. </param>
        /// <param name="writeBOM">
        /// Если в начало файла или потока требуется записать метку порядка байтов (BOM) для используемой кодировки текста, то данный параметр должен иметь значение Истина.
        /// Значение по умолчанию: Ложь. </param>
        ///
        [ScriptConstructor(Name = "На основании имени файла")]
        public static DataWriter Constructor(IValue fileName, IValue textEncoding = null, ByteOrderEnum? byteOrder = null, string lineSplitter = null, bool append = false, string convertibleSplitterOfLines = null, bool writeBOM = false)
        {
            if(fileName.DataType == DataType.String)
                return new DataWriter(fileName.AsString(), textEncoding, byteOrder, lineSplitter, append, convertibleSplitterOfLines, writeBOM);
            else
                return ConstructorByStream(fileName, textEncoding, byteOrder, lineSplitter, convertibleSplitterOfLines, writeBOM);
        }

        /// <summary>
        /// 
        /// Объект создается для записи в заданный поток.
        /// После завершения работы с объектом, до закрытия потока, переданного в конструктор, объект необходимо закрыть с помощью метода Закрыть или НачатьЗакрытие.
        /// </summary>
        ///
        /// <param name="stream">
        /// Поток, в который производится запись данных. Типы: Поток (Stream), ПотокВПамяти (MemoryStream), ФайловыйПоток (FileStream) </param>
        /// <param name="textEncoding">
        /// Устанавливает кодировку текста для создаваемого экземпляра ЗаписьДанных. Если не задано, используется кодировка UTF-8.
        /// Значение по умолчанию: UTF8. Типы: КодировкаТекста (TextEncoding), Строка (String) </param>
        /// <param name="byteOrder">
        /// Порядок байтов, используемый по умолчанию для кодирования целых чисел при записи в поток.
        /// Значение по умолчанию: LittleEndian. </param>
        /// <param name="lineSplitter">
        /// Разделитель по умолчанию для строк, записываемых в поток. Если разделитель строк не задан, то используется строка ПС.
        /// Значение по умолчанию: ПС. </param>
        /// <param name="convertibleSplitterOfLines">
        /// Определяет разделение строк в файле для конвертации в стандартный перевод строк ПС.
        /// Значение по умолчанию: ВК + ПС. </param>
        /// <param name="writeBOM">
        /// Если в начало файла или потока требуется записать метку порядка байтов (BOM) для используемой кодировки текста, то данный параметр должен иметь значение Истина.
        /// Значение по умолчанию: Ложь. </param>
        ///
        [ScriptConstructor(Name = "На основании потока")]
        public static DataWriter ConstructorByStream(IValue stream, IValue textEncoding = null, ByteOrderEnum? byteOrder = null, string lineSplitter = null, string convertibleSplitterOfLines = null, bool writeBOM = false)
        {
            var streamObj = stream.AsObject() as IStreamWrapper;
            if (streamObj == null)
            {
                throw RuntimeException.InvalidArgumentType(nameof(stream));
            }

            return new DataWriter(streamObj, textEncoding, byteOrder, lineSplitter, convertibleSplitterOfLines, writeBOM);
        }
    
        /// <summary>
        /// 
        /// Кодировка текста по-умолчанию для данного экземпляра ЗаписьДанных.
        /// Кодировка может быть задана как в виде значения перечисления КодировкаТекста, так и в виде строки с указанием названия кодировки.
        /// </summary>
        /// <value>КодировкаТекста (TextEncoding), Строка (String)</value>
        [ContextProperty("КодировкаТекста", "TextEncoding")]
        public IValue TextEncoding
        {
            get { return _userVisibleEncoding; }
            set
            {
                if (value != null)
                {
                    _workingEncoding = TextEncodingEnum.GetEncoding(value, _writeBOM);
                    _userVisibleEncoding = value;
                }
                else
                {
                    _workingEncoding = new UTF8Encoding(true);
                    _userVisibleEncoding = ValueFactory.Create("utf-8");
                }
            }
        }
    
        /// <summary>
        /// 
        /// Конвертируемый разделитель строк. Этот параметр влияет на поведение метода ЗаписатьСимволы.
        /// </summary>
        /// <value>Строка (String)</value>
        [ContextProperty("КонвертируемыйРазделительСтрок", "ConvertibleSplitterOfLines")]<commit_msg>fix #861: типы параметров конструктора<commit_after>﻿/*----------------------------------------------------------
This Source Code Form is subject to the terms of the 
Mozilla Public License, v.2.0. If a copy of the MPL 
was not distributed with this file, You can obtain one 
at http://mozilla.org/MPL/2.0/.
----------------------------------------------------------*/

using System;
using System.IO;
using System.Text;

using ScriptEngine.Machine;
using ScriptEngine.Machine.Contexts;

namespace ScriptEngine.HostedScript.Library.Binary
{
    /// <summary>
    /// 
    /// Объект предназначен для удобной записи различных типов данных в приемник.
    /// Необходимо соблюдать следующий порядок работы с данным объектом:
    /// 
    ///  - Создать или получить приемник даных.
    ///  - Вызвать из приемника экземпляр объекта ЗаписьДанных.
    ///  - Выполнить требуемые действия с помощью объекта.
    ///  - Закрыть экземпляр объекта ЗаписьДанных.
    /// При необходимости использовать другие методы для работы с данными, требуется сначала закрыть экземпляр объекта ЗаписьДанных с помощью метода Закрыть, выполнить необходимые действия над данными, установить требуемую позицию для чтения из приемника и создать новый экземпляр ЗаписьДанных.
    /// </summary>
    [ContextClass("ЗаписьДанных", "DataWriter")]
    public class DataWriter : AutoContext<DataWriter>, IDisposable
    {

        private Encoding _workingEncoding;
        private IValue _userVisibleEncoding;
        private BinaryWriter _binaryWriter;
        private readonly bool _writeBOM;
    
        public DataWriter(string fileName, IValue textEncoding, ByteOrderEnum? byteOrder, string lineSplitter, bool append, string convertibleSplitterOfLines, bool writeBOM)
        {
            ByteOrder = byteOrder?? ByteOrderEnum.LittleEndian;
            LineSplitter = lineSplitter?? "\r\n";
            ConvertibleSplitterOfLines = convertibleSplitterOfLines;
            _writeBOM = writeBOM;
            TextEncoding = textEncoding;

            var fileSubsystem = new FileStreamsManager();
            var fileStreamContext = append ? fileSubsystem.OpenForAppend(fileName) : fileSubsystem.OpenForWrite(fileName);

            _binaryWriter = new BinaryWriter(fileStreamContext.GetUnderlyingStream(), _workingEncoding);
        }

        public DataWriter(IStreamWrapper streamObj, IValue textEncoding, ByteOrderEnum? byteOrder, string lineSplitter, string convertibleSplitterOfLines, bool writeBOM)
        {
            ByteOrder = byteOrder?? ByteOrderEnum.LittleEndian;
            LineSplitter = lineSplitter ?? "\r\n";
            ConvertibleSplitterOfLines = convertibleSplitterOfLines;
            _writeBOM = writeBOM;
            TextEncoding = textEncoding;

            _binaryWriter = new BinaryWriter(streamObj.GetUnderlyingStream(), _workingEncoding);
        }

        /// <summary>
        /// 
        /// Создает объект ЗаписьДанных для записи в указанный файл. Если файл с таким именем не существует, он будет создан. Параметр &lt;Дописать&gt; определяет, будут ли данные записаны в начало или в конец файла.
        /// После завершения работы с объектом, до закрытия потока, переданного в конструктор, объект необходимо закрыть с помощью метода Закрыть или НачатьЗакрытие. При этом используемый файл будет закрыт автоматически.
        /// </summary>
        ///
        /// <param name="fileName">
        /// Имя файла, в который будет выполнена запись. </param>
        /// <param name="textEncoding">
        /// Кодировка текста для создаваемого экземпляра ЗаписьДанных. Если не задана, то используется UTF-8.
        /// Значение по умолчанию: UTF8. Типы: КодировкаТекста (TextEncoding), Строка (String) </param>
        /// <param name="byteOrder">
        /// Порядок байтов, используемый по умолчанию для кодирования целых чисел при записи в поток.
        /// Значение по умолчанию: LittleEndian. </param>
        /// <param name="lineSplitter">
        /// Разделитель по умолчанию для строк, записываемых в поток. Если разделитель строк не задан, то используется строка ПС.
        /// Значение по умолчанию: ПС. </param>
        /// <param name="append">
        /// Определяет, будут ли данные записаны в начало или в конец файла:
        /// 
        ///  - Если Истина, то при открытии существующего файла запись будет выполнена в конец файла.
        ///  - Иначе данные будут записываться с начала файла, перезаписывая существующие данные.
        /// Если заданный файл не существует, будет создан новый файл с указанным именем и значение параметра не повлияет на поведение конструктора.
        /// Значение по умолчанию: Ложь. </param>
        /// <param name="convertibleSplitterOfLines">
        /// Определяет разделение строк в файле для конвертации в стандартный перевод строк ПС.
        /// Значение по умолчанию: ВК + ПС. </param>
        /// <param name="writeBOM">
        /// Если в начало файла или потока требуется записать метку порядка байтов (BOM) для используемой кодировки текста, то данный параметр должен иметь значение Истина.
        /// Значение по умолчанию: Ложь. </param>
        ///
        [ScriptConstructor]
        public static DataWriter Constructor(IValue file_stream, IValue textEncoding = null, IValue byteOrder = null, IValue lineSplitter = null, IValue param5 = null, IValue param6 = null, IValue param7 = null)
        {
            if (file_stream.DataType == DataType.String)
                return new DataWriter(file_stream.AsString(), textEncoding, 
                            ContextValuesMarshaller.ConvertParam<ByteOrderEnum?>(byteOrder,null),
                            ContextValuesMarshaller.ConvertParam<string>(lineSplitter),
                            ContextValuesMarshaller.ConvertParam<bool>(param5),
                            ContextValuesMarshaller.ConvertParam<string>(param6),
                            ContextValuesMarshaller.ConvertParam<bool>(param7));
            else
                return ConstructorByStream(file_stream, textEncoding,
                            ContextValuesMarshaller.ConvertParam<ByteOrderEnum?>(byteOrder,null),
                            ContextValuesMarshaller.ConvertParam<string>(lineSplitter),
                            ContextValuesMarshaller.ConvertParam<string>(param5),
                            ContextValuesMarshaller.ConvertParam<bool>(param6));
        }

        /// <summary>
        /// 
        /// Объект создается для записи в заданный поток.
        /// После завершения работы с объектом, до закрытия потока, переданного в конструктор, объект необходимо закрыть с помощью метода Закрыть или НачатьЗакрытие.
        /// </summary>
        ///
        /// <param name="stream">
        /// Поток, в который производится запись данных. Типы: Поток (Stream), ПотокВПамяти (MemoryStream), ФайловыйПоток (FileStream) </param>
        /// <param name="textEncoding">
        /// Устанавливает кодировку текста для создаваемого экземпляра ЗаписьДанных. Если не задано, используется кодировка UTF-8.
        /// Значение по умолчанию: UTF8. Типы: КодировкаТекста (TextEncoding), Строка (String) </param>
        /// <param name="byteOrder">
        /// Порядок байтов, используемый по умолчанию для кодирования целых чисел при записи в поток.
        /// Значение по умолчанию: LittleEndian. </param>
        /// <param name="lineSplitter">
        /// Разделитель по умолчанию для строк, записываемых в поток. Если разделитель строк не задан, то используется строка ПС.
        /// Значение по умолчанию: ПС. </param>
        /// <param name="convertibleSplitterOfLines">
        /// Определяет разделение строк в файле для конвертации в стандартный перевод строк ПС.
        /// Значение по умолчанию: ВК + ПС. </param>
        /// <param name="writeBOM">
        /// Если в начало файла или потока требуется записать метку порядка байтов (BOM) для используемой кодировки текста, то данный параметр должен иметь значение Истина.
        /// Значение по умолчанию: Ложь. </param>
        ///
        //[ScriptConstructor(Name = "На основании потока")]
        public static DataWriter ConstructorByStream(IValue stream, IValue textEncoding = null, ByteOrderEnum? byteOrder = null, string lineSplitter = null, string convertibleSplitterOfLines = null, bool writeBOM = false)
        {
            var streamObj = stream.AsObject() as IStreamWrapper;
            if (streamObj == null)
            {
                throw RuntimeException.InvalidArgumentType(nameof(stream));
            }

            return new DataWriter(streamObj, textEncoding, byteOrder, lineSplitter, convertibleSplitterOfLines, writeBOM);
        }

        /// <summary>
        /// 
        /// Кодировка текста по-умолчанию для данного экземпляра ЗаписьДанных.
        /// Кодировка может быть задана как в виде значения перечисления КодировкаТекста, так и в виде строки с указанием названия кодировки.
        /// </summary>
        /// <value>КодировкаТекста (TextEncoding), Строка (String)</value>
        [ContextProperty("КодировкаТекста", "TextEncoding")]
        public IValue TextEncoding
        {
            get { return _userVisibleEncoding; }
            set
            {
                if (value != null)
                {
                    _workingEncoding = TextEncodingEnum.GetEncoding(value, _writeBOM);
                    _userVisibleEncoding = value;
                }
                else
                {
                    _workingEncoding = new UTF8Encoding(true);
                    _userVisibleEncoding = ValueFactory.Create("utf-8");
                }
            }
        }
    
        /// <summary>
        /// 
        /// Конвертируемый разделитель строк. Этот параметр влияет на поведение метода ЗаписатьСимволы.
        /// </summary>
        /// <value>Строка (String)</value>
        [ContextProperty("КонвертируемыйРазделительСтрок", "ConvertibleSplitterOfLines")]
{'fraction_non_alphanumeric': 0.09740259740259741, 'fraction_numerical': 0.0016103896103896104, 'mean_word_length': 2.357927786499215, 'pattern_counts': {'":': 0, '<': 94, '<?xml version=': 0, '>': 94, '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': '3312771', 'n_tokens_mistral': 5978, 'n_tokens_neox': 6627, 'n_words': 1570}