//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// UserRTX.NET satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Collections.Generic;

#if !WASM
namespace user_rtx { using u = user_rtx;
#else
namespace user_rtx.wasm { using u = user_rtx.wasm;
#endif

partial class XmlConfigurationBase {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/// <exception cref="FileNotFoundException" />
/// <exception cref="EXmlConfiguration" />
protected void LoadDocument( string filePath ) =>
   LoadDocumentX( filePath, null );

/// <exception cref="EXmlConfiguration" />
protected void LoadDocumentFromText( string xml ) =>
   LoadDocumentWithReader( new StringReader( xml ) );

/// <exception cref="EXmlConfiguration" />
protected void LoadDocumentWithReader( TextReader input ) =>
   LoadDocumentX( null, input );

//--------------------------------------------------------------------------------------------------

protected void UnloadDocument()
{
   _document = null;
   _currentElement = null;
   _namespaceManager = null;
   _filePath = _fileFullPath = null;
}

//==================================================================================================

/// <exception cref="InvalidOperationException" />
/// <exception cref="EXmlConfiguration" />
protected void SaveDocument()
{
   if ( FilePath == null )
      throw new InvalidOperationException(u.local.T(
         RC._File_path_has_not_been_set_for_document_saving_of_XML_configuration,
         "Файловый маршрут не был установлен для сохранения документа XML-конфигурации." ));
   SaveDocument( FileFullPath );
}

/// <exception cref="InvalidOperationException" />
/// <exception cref="EXmlConfiguration" />
protected void SaveDocument( string filePath ) =>
   SaveDocument( filePath, false );

/// <exception cref="InvalidOperationException" />
/// <exception cref="EXmlConfiguration" />
protected void SaveDocument( string filePath, bool setFilePath )
{
   VerifyDocumentLoaded();
   string fileFullPath;
   try {
      fileFullPath = Path.GetFullPath( filePath );
      ValidateDocument();
      Document.Save( fileFullPath );
   }
   catch ( Exception e ) {
      throw new EXmlConfiguration( e.Message );
   }
   if ( setFilePath ) {
      _filePath = filePath;
      _fileFullPath = fileFullPath;
   }
}

//==================================================================================================

/// <exception cref="InvalidOperationException" />
/// <exception cref="EXmlConfiguration" />
protected void SetFilePath( string filePath )
{
   VerifyDocumentLoaded();
   string
      fileFullPath;
   try {
      fileFullPath = Path.GetFullPath( filePath );
   }
   catch ( Exception e ) {
      throw new EXmlConfiguration(ComposeErrorMessageWithFile(
         e.Message, filePath ));
   }
   _filePath = filePath;
   _fileFullPath = fileFullPath;
}

//--------------------------------------------------------------------------------------------------

protected void ResetFilePath()
{
   _filePath = _fileFullPath = null;
}

//==================================================================================================

/// <exception cref="ArgumentException" />
/// <exception cref="FileNotFoundException" />
/// <exception cref="EXmlConfiguration" />
void LoadDocumentX( [u.rel_opt] string? filePath, [u.rel_opt] TextReader? input )
{
   if ( u.ops.AllNulls( input, filePath ) )
      throw e_argument.New(
         "One of following arguments must not be null: “{0}”,“{1}”.",
         nameof(filePath), nameof(input) );

   if ( !u.ops.HasNull( input, filePath ) )
      throw e_argument.New(
         "One of following arguments must be null: “{0}”,“{1}”.",
         nameof(filePath), nameof(input) );

   UnloadDocument();

   var schemaSet = new XmlSchemaSet();
   var readerSettings = new XmlReaderSettings();

   schemaSet.Add( Schema );

   readerSettings.ValidationType = ValidationType.Schema;
   readerSettings.Schemas = schemaSet;

   var document = new XmlDocument();
   XmlNamespaceManager namespaceManager;

   string? fileFullPath = null;

   try {
      if ( filePath != null )
         fileFullPath = Path.GetFullPath( filePath );
      using ( var reader = input!=null ?
         XmlReader.Create( input, readerSettings ) :
         XmlReader.Create( fileFullPath.NN(), readerSettings ) )
         document.Load( reader );

      XmlElement? rootElement = document.DocumentElement ??
         throw new EXmlConfiguration(u.local.T(
            RC._XML_document_does_dot_have_expected_root_element,
            "XML-документ не содержит ожидаемого корневого элемента." ));
      if ( rootElement.NamespaceURI != Schema.TargetNamespace )
         throw e_xml_configuration.New(u.local.T(
            RC._Element_of_XML_document_must_belong_to_following_namespace_0,
            "Элемент XML-документа должен принадлежать следующему пространству имён: “{0}”." ),
            Schema.TargetNamespace );

      namespaceManager = new XmlNamespaceManager( document.NameTable );
      namespaceManager.AddNamespace( "x", Schema.TargetNamespace );
   }
   catch ( Exception e ) {
      if ( e is FileNotFoundException )
         throw;
      throw new EXmlConfiguration(ComposeErrorMessageWithFile(
         fileFullPath ?? filePath, e.Message ));
   }

   if ( filePath != null ) {
      _filePath = filePath;
      _fileFullPath = fileFullPath;
   }
   _currentElement = document.DocumentElement;
   _namespaceManager = namespaceManager;
   _document = document;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // XmlConfigurationBase

} // user_rtx (.wasm)
