using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace Rokojori
{  
  public class XMLElementNode:XMLNode
  {
    public XMLElementNode( XMLDocument document, string nodeName, string nameSpace = null ):base( document, XMLNode.NodeType.Element )
    {
      _nodeName = nodeName;
      _nameSpace = nameSpace;
    }

    string _nodeName;
    public string nodeName => _nodeName;

    string _nameSpace;
    public string nameSpace => _nameSpace;

    List<XMLNode> _children = new List<XMLNode>();
    public int numChildren => _children.Count;

    public string fullNodeName 
    {
      get 
      {
        if ( _nameSpace == null )
        {
          return _nodeName;
        }

        return _nameSpace + ":" + _nodeName;
      }
    }

    public XMLNode GetChildAt( int index )
    {
      return _children[ index ];
    }

    public override string ToString()
    {
      return GetInfo();
    }

    public override string GetInfo()
    {
      if ( _attributes.Count > 0 )
      {
        var atts = "";

        for ( int i = 0; i < _attributes.Count; i++ )
        {
          if ( i != 0 )
          {
            atts += " ";
          }

          var value = _attributes[ i ].nodeValue;

          var attValue = _attributes[ i ].fullName;

          if ( value != null )
          {
            attValue += "=\"" + XMLSerializer.Escape( value ) + "\"";
          } 

          atts += attValue;
        }

        return "<" + fullNodeName + " " + atts + " >";

      }

      return "<" + fullNodeName + ">";
    }

    public bool HasOnlyTextNodes()
    {
      for ( int i = 0; i < _children.Count; i++ )
      {
        if ( _children[ i ].nodeType != NodeType.Text )
        {
          return false;
        }
      }

      return _children.Count > 0;
    }

    public void RemoveChild( XMLNode node )
    {
      var childIndex = _children.IndexOf( node );

      if ( childIndex == -1 )
      {
        return;
      }

      node._SetParent( null );
      _children.RemoveAt( childIndex );
    }

    public void AppendChild( XMLNode node )
    {
      if ( node.parentNode == this )
      {
        return;
      }

      if ( node.parentNode != null )
      {
        var element = node.parentNode as XMLElementNode;
        element.RemoveChild( node );
      }      
    
      _children.Add( node );
    
      node._SetParent( this );

    }

    public XMLTextNode AddText( string text )
    {
      var textNode = document.CreateText( text );
      AppendChild( textNode );

      return textNode;
    }

    public XMLElementNode AddHTMLScript( string script )
    {
      return AddElement( HTMLElementName.script, script );
    }

    public XMLElementNode AddHTMLStyle( string style )
    {
      return AddElement( HTMLElementName.style, style );
    }

    public XMLElementNode AddElement( XMLElementNodeName name, string text = null )
    {
      var en = document.Create( name, text );
      AppendChild( en );
      return en;
    }

    public void SetAttribute( string name, string value, string nameSpace = null )
    {
      var att = new XMLAttributeNode( document, this, name, value, nameSpace );
      _attributes.Add( att );
    }

    
    List<XMLAttributeNode> _attributes = new List<XMLAttributeNode>();

    public int numAttributes => _attributes.Count;

    public void RemoveAttributeAt( int index )
    {
      _attributes.RemoveAt( index );
    }

    public void RemoveAttribute( XMLAttributeNode attributeNode )
    {
      var index = _attributes.IndexOf( attributeNode );

      if ( index == -1 )
      {
        return;
      }

      RemoveAttributeAt( index );
    }

    public XMLAttributeNode GetAttributeAt( int index )
    {
      return _attributes[ index ];
    }

    public XMLAttributeNode GetAttribute( string name, string nameSpace = null )
    {
      return _attributes.Find( a => a.name == name && a.nameSpace == nameSpace );
    }  

    public XMLElementNode querySelector( XMLElementSelector selector )
    { 
      return XMLQuery.SelectElement( this, selector );
    }

    public XMLElementNode querySelector( string selector )
    {
      return querySelector( XMLElementSelectors.From( selector ) );
    }

    public List<XMLElementNode> querySelectorAll( XMLElementSelector selector )
    { 
      return XMLQuery.SelectAllElements( this, selector );
    }

    public List<XMLElementNode> querySelectorAll( string selector )
    {
      return querySelectorAll( XMLElementSelectors.From( selector ) );
    }
  
  }
}