//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// CommonHelpers 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;

namespace CommonHelpers {

//**************************************************************************************************
partial class HXmlConfigurationBase {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/// <exception cref="ArgumentNullException" />
protected string GetElementPath(XmlElement element)
{
   HArgChecking.VerifyNotNull( element );
   VerifyDocumentLoaded();
   var sb = new StringBuilder();
   for (XmlNode node=element; node!=null; node=node.ParentNode)
      sb.Insert( 0, "/" + node.Name );
   var path = sb.ToString();
   return path.StartsWith( "/#document/" ) ?
      path.Remove( 0, 10 ) : path;
}

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

/// <exception cref="InvalidOperationException" />
protected XmlNode GetCurrentElement()
{
   VerifyDocumentLoaded(); return _CurrentElement_;
}

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

/// <exception cref="InvalidOperationException" />
protected string NormalizeElementPath(string elementPath)
{
   HArgChecking.VerifyNotNull( elementPath );
   VerifyDocumentLoaded();
   return elementPath.StartsWith( "/" ) ? elementPath :
      string.Format( "/{0}/{1}", Document.DocumentElement.Name, elementPath );
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="InvalidOperationException" />
protected bool HasAttribute(string name)
{
   return AttributeValueOrNull( name ) != null;
}

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

/// <exception cref="ArgumentNullException" />
[HOptionalResult]
protected string AttributeValueOrNull(string name)
{
   HArgChecking.VerifyNotNull( name );
   XmlAttribute attribute = CurrentElement.Attributes[ name ];
   return attribute!=null ? attribute.Value : null;
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="InvalidOperationException" />
protected string SetAttributeValue(string name,[HOptional] string value)
{
   HArgChecking.VerifyNotNull( name );
   CurrentElement.SetAttribute( name, value );
   return value;
}

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
/// <exception cref="InvalidOperationException" />
protected string SetAttributeValueAddRemove(string name,[HOptional] string value)
{
   HArgChecking.VerifyNotNull( name );
   if ( value != null )
      if ( HasAttribute( name ) )
         SetAttributeValue( name, value );
      else
      {
         var newAttribute = Document.CreateAttribute( name );
         newAttribute.Value = value;
         CurrentElement.Attributes.Append( newAttribute );
         UpdateAttributeValueCollection();
      }
   else
      RemoveAttribute( name, true );
   return value;
}

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

/// <exception cref="InvalidOperationException" />
protected XmlElement SelectDocumentElement()
{
   return CurrentElement = Document.DocumentElement;
}

/// <exception cref="InvalidOperationException" />
protected XmlElement SetCurentElement([HOptional] XmlElement element)
{
   VerifyDocumentLoaded(); return SetCurentElementPrepareValueCollection( element );
}

/// <exception cref="InvalidOperationException" />
protected XmlElement ResetCurentElement()
{
   return SetCurentElement( null );
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="InvalidOperationException" />
/// <exception cref="HXmlConfigurationException" />
protected XmlElement NavigateTo(string elementPath)
{
   if ( !TryNavigateTo( elementPath ) )
      throw CreateExceptionWithFile(
         Verbose.XML_ELEMENT_PATH_IS_NOT_FOUND_0,
         NormalizeElementPath( elementPath ) );
   return CurrentElement;
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="ArgumentException" />
/// <exception cref="InvalidOperationException" />
protected bool TryNavigateTo(string elementPath)
{
   elementPath = NormalizeElementPath( elementPath );
   var sb = new StringBuilder();
   foreach (char ch in elementPath)
      if ( ch == '/' )
         sb.Append( "/x:" );
      else
         sb.Append( ch );
   XmlNode node = Document.SelectSingleNode(
      sb.ToString(), NamespaceManager );
   if ( node == null )
      return false;
   if ( !(node is XmlElement) )
      throw HArgumentExceptionCreator.Create(
         Verbose.INCORRECT_PATH_FOR_NAVIGATION_0__PATH_TO_XML_ELEMENT_WAS_EXPECTED,
         elementPath );
   CurrentElement = (XmlElement)node;
   return true;
}

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

/// <exception cref="ArgumentNullException" />
protected HXmlAttributeValueCollection GetAttributeValues(XmlNode node,bool asStrictReadOnly=true)
{
   HArgChecking.VerifyNotNull( node );
   var attrValueCollection = new HXmlAttributeValueCollection( this );
   foreach (XmlAttribute attribute in node.Attributes)
      attrValueCollection.Add( attribute.Name, attribute.Value );
   if ( asStrictReadOnly )
      attrValueCollection.MakeStrictReadonly();
   return attrValueCollection;
}

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

protected XmlNode[] GetChildElements()
{
   return GetChildElements( CurrentElement );
}

/// <exception cref="ArgumentNullException" />
protected static XmlNode[] GetChildElements(XmlNode node)
{
   HArgChecking.VerifyNotNull( node );

   var nodeList = new List<XmlNode>();

   foreach (XmlNode childNode in node.ChildNodes)
      if ( childNode.NodeType == XmlNodeType.Element )
         nodeList.Add( childNode );

   return nodeList.ToArray();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HXmlConfigurationBase
//**************************************************************************************************

} // CommonHelpers
