/// <summary>
 /// Returns the most suitable HtmlOption, based on the tag representation
 /// </summary>
 /// <param name="tagRepresentation">The tag representation.</param>
 public HtmlOption GetOptionFromRepresentation(string tagRepresentation)
 {
     if (string.IsNullOrEmpty(tagRepresentation)) throw new ArgumentNullException("tagRepresentation");
     tagRepresentation = tagRepresentation.Trim('<','>');
     string tagName = tagRepresentation.Contains(' ') ? tagRepresentation.Substring(0, tagRepresentation.IndexOf(' ')) : tagRepresentation;
     if (tagName != OpenTag) return null; //we can get options only from open tags. If it's not open or something else, return null.
     HtmlAttribute[] attributes = HtmlAttribute.GetAttributes(tagRepresentation);
     if (attributes == null || attributes.Length == 0) //no attributes
     {
         return Options.FirstOrDefault(o => (o as HtmlOption).ContentHtmlAttribute == null && (o as HtmlOption).OptionHtmlAttribute == null) as HtmlOption; //return the option with no attributes
     }
     List<HtmlOption> validOptions = new List<HtmlOption>();
     foreach (HtmlOption opt in Options.Where(o => ((o as HtmlOption).ContentHtmlAttribute == null || attributes.Contains((o as HtmlOption).ContentHtmlAttribute)) &&
         ((o as HtmlOption).OptionHtmlAttribute == null || attributes.Contains((o as HtmlOption).OptionHtmlAttribute)))) //all the options which contain the used attributes. But we still don't know about specific attribute values.
     {
         if (opt.ContentHtmlAttribute == null && opt.OptionHtmlAttribute == null) continue; //ignore the no attribute option, because it has been checked before
         if (opt.ContentHtmlAttribute != null && string.IsNullOrEmpty(HtmlAttribute.GetAttributeValue(tagRepresentation, opt.ContentHtmlAttribute))) continue; //we have attribute in the option, but can't get its value from the representation
         if (opt.OptionHtmlAttribute != null && string.IsNullOrEmpty(HtmlAttribute.GetAttributeValue(tagRepresentation, opt.OptionHtmlAttribute))) continue;
         validOptions.Add(opt);
     }
     //now we have only valid options, according to the tag representation.
     //Here are the priorities:
     //1. Both attributes and both of them include the full attribute value
     //2. Both attributes and one of them includes the full attribute value
     //3. Both attributes and both include part of the attribute value
     //4. One attribute and includes the full attribute value
     //5. One attribute and includes a part of the attribute value.
     //In some cases this can make a problem if we have more attributes, but in the case I will use this library,
     //it will work fine. This is also up to settings, which sometimes can be pretty stupid if such a thing happens.
     HtmlOption[] priorityList = new HtmlOption[4]; //four elements. The lowest index is the highest priority. This is done to avoid multiple searching through the whole collection, when many options.
     foreach (HtmlOption opt in validOptions)
     {
         if (opt.ContentHtmlAttribute != null && opt.OptionHtmlAttribute != null)
         {
             if (!opt.ContentHtmlAttribute.HasValue && !opt.OptionHtmlAttribute.HasValue) return opt;
             if (!opt.ContentHtmlAttribute.HasValue || !opt.OptionHtmlAttribute.HasValue) //one has value and one is full
             {
                 priorityList[0] = opt;
             }
             //both have values
             priorityList[1] = opt;
         }
         //one attribute
         if (opt.ContentHtmlAttribute != null && !opt.ContentHtmlAttribute.HasValue || opt.OptionHtmlAttribute != null && !opt.OptionHtmlAttribute.HasValue)
         {
             //one full.
             priorityList[2] = opt;
         }
         //one attribute from value.
         priorityList[3] = opt;
     }
     //return the one with the highest priority
     int i = 0;
     while (i < priorityList.Length)
     {
         if (priorityList[i] != null) return priorityList[i];
         i++;
     }
     return null; //if nothing is found.
 }
 /// <summary>
 /// Gets the value of the option of the tag. Also, if the tag content is encoded in some of its attributes,
 /// adds the content as a child.
 /// </summary>
 /// <param name="tag">The tag.</param>
 /// <param name="tagRepresentation">The representation of the tag.</param>
 protected override void GetTagOptionFromRepresentation(Tag tag, string tagRepresentation)
 {
     TagOption = (tag as HtmlTag).GetOptionFromRepresentation(tagRepresentation); //get the option that best describes the tag
     if (TagOption == null) return; //this is when it's a closing tag...
     if (TagOption.OptionHtmlAttribute != null)
     {
         Option = HtmlAttribute.GetAttributeValue(tagRepresentation, TagOption.OptionHtmlAttribute);
     }
     if (TagOption.ContentHtmlAttribute != null)
     {
         AddChild(new TextSyntaxNode(HtmlAttribute.GetAttributeValue(tagRepresentation, TagOption.ContentHtmlAttribute)));
     }
 }
 /// <summary>
 /// Converts the tag to BBCode according to the html option and
 /// the option and content strings
 /// </summary>
 /// <param name="option">The option. Represented as [size={option}] in bbcode</param>
 /// <param name="content">The content. Represented as [b]{content}[/b] in bbcode</param>
 /// <param name="tagOption">The tag option that has to be used to convert the tag.</param>        
 public string ToBBCodeString(string option, string content, HtmlOption tagOption)
 {
     if (tagOption == null) throw new ArgumentNullException("tagOption");
     if (tagOption.OptionHtmlAttribute != null && string.IsNullOrEmpty(option)) throw new ArgumentNullException("tagOption"); //have option but the value is null or empty
     if (!Options.Contains(tagOption)) throw new HtmlParsingException("Option not found in the current html tag representation!");
     return "[" + tagOption.OpenTag + (tagOption.OptionHtmlAttribute != null ? "=" + option : "") + "]" + content + (string.IsNullOrEmpty(tagOption.CloseTag) ? "" : "[" + tagOption.CloseTag + "]");
 }