text: /*global Autolinker */
  /*jshint boss:true */
  /**
   * @class Autolinker.HtmlTag
   * @extends Object
   * 
   * Represents an HTML tag, which can be used to easily build/modify HTML tags programmatically.
   * 
   * Autolinker uses this abstraction to create HTML tags, and then write them out as strings. You may also use
   * this class in your code, especially within a {@link Autolinker#replaceFn replaceFn}.
   * 
   * ## Examples
   * 
   * Example instantiation:
   * 
   *     var tag = new Autolinker.HtmlTag( {
   *         tagName : 'a',
   *         attrs   : { 'href': 'http://google.com', 'class': 'external-link' },
   *         innerHtml : 'Google'
   *     } );
   *     
   *     tag.toString();  // <a href="http://google.com" class="external-link">Google</a>
   *     
   *     // Individual accessor methods
   *     tag.getTagName();                 // 'a'
   *     tag.getAttr( 'href' );            // 'http://google.com'
   *     tag.hasClass( 'external-link' );  // true
   * 
   * 
   * Using mutator methods (which may be used in combination with instantiation config properties):
   * 
   *     var tag = new Autolinker.HtmlTag();
   *     tag.setTagName( 'a' );
   *     tag.setAttr( 'href', 'http://google.com' );
   *     tag.addClass( 'external-link' );
   *     tag.setInnerHtml( 'Google' );
   *     
   *     tag.getTagName();                 // 'a'
   *     tag.getAttr( 'href' );            // 'http://google.com'
   *     tag.hasClass( 'external-link' );  // true
   *     
   *     tag.toString();  // <a href="http://google.com" class="external-link">Google</a>
   *     
   * 
   * ## Example use within a {@link Autolinker#replaceFn replaceFn}
   * 
   *     var html = Autolinker.link( "Test google.com", {
   *         replaceFn : function( autolinker, match ) {
   *             var tag = autolinker.getTagBuilder().build( match );  // returns an {@link Autolinker.HtmlTag} instance, configured with the Match's href and anchor text
   *             tag.setAttr( 'rel', 'nofollow' );
   *             
   *             return tag;
   *         }
   *     } );
   *     
   *     // generated html:
   *     //   Test <a href="http://google.com" target="_blank" rel="nofollow">google.com</a>
   *     
   *     
   * ## Example use with a new tag for the replacement
   * 
   *     var html = Autolinker.link( "Test google.com", {
   *         replaceFn : function( autolinker, match ) {
   *             var tag = new Autolinker.HtmlTag( {
   *                 tagName : 'button',
   *                 attrs   : { 'title': 'Load URL: ' + match.getAnchorHref() },
   *                 innerHtml : 'Load URL: ' + match.getAnchorText()
   *             } );
   *             
   *             return tag;
   *         }
   *     } );
   *     
   *     // generated html:
   *     //   Test <button title="Load URL: http://google.com">Load URL: google.com</button>
   */
  Autolinker.HtmlTag = Autolinker.Util.extend( Object, {
  	
  	/**
  	 * @cfg {String} tagName
  	 * 
  	 * The tag name. Ex: 'a', 'button', etc.
  	 * 
  	 * Not required at instantiation time, but should be set using {@link #setTagName} before {@link #toString}
  	 * is executed.
  	 */
  	
  	/**
  	 * @cfg {Object.<String, String>} attrs
  	 * 
  	 * An key/value Object (map) of attributes to create the tag with. The keys are the attribute names, and the
  	 * values are the attribute values.
  	 */
  	
  	/**
  	 * @cfg {String} innerHtml
  	 * 
  	 * The inner HTML for the tag. 
  	 * 
  	 * Note the camel case name on `innerHtml`. Acronyms are camelCased in this utility (such as not to run into the acronym 
  	 * naming inconsistency that the DOM developers created with `XMLHttpRequest`). You may alternatively use {@link #innerHTML}
  	 * if you prefer, but this one is recommended.
  	 */
  	
  	/**
  	 * @cfg {String} innerHTML
  	 * 
  	 * Alias of {@link #innerHtml}, accepted for consistency with the browser DOM api, but prefer the camelCased version
  	 * for acronym names.
  	 */
  	
  	
  	/**
  	 * @protected
  	 * @property {RegExp} whitespaceRegex
  	 * 
  	 * Regular expression used to match whitespace in a string of CSS classes.
  	 */
  	whitespaceRegex : /\s+/,
  	
  	
  	/**
  	 * @constructor
  	 * @param {Object} [cfg] The configuration properties for this class, in an Object (map)
  	 */
  	constructor : function( cfg ) {
  		Autolinker.Util.assign( this, cfg );
  		
  		this.innerHtml = this.innerHtml || this.innerHTML;  // accept either the camelCased form or the fully capitalized acronym
  	},
  	
  	
  	/**
  	 * Sets the tag name that will be used to generate the tag with.
  	 * 
  	 * @param {String} tagName
  	 * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
  	 */
  	setTagName : function( tagName ) {
  		this.tagName = tagName;
  		return this;
  	},
  	
  	
  	/**
  	 * Retrieves the tag name.
  	 * 
  	 * @return {String}
  	 */
  	getTagName : function() {
  		return this.tagName || "";
  	},
  	
  	
  	/**
  	 * Sets an attribute on the HtmlTag.
  	 * 
  	 * @param {String} attrName The attribute name to set.
  	 * @param {String} attrValue The attribute value to set.
  	 * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
  	 */
  	setAttr : function( attrName, attrValue ) {
  		var tagAttrs = this.getAttrs();
  		tagAttrs[ attrName ] = attrValue;
  		
  		return this;
  	},
  	
  	
  	/**
  	 * Retrieves an attribute from the HtmlTag. If the attribute does not exist, returns `undefined`.
  	 * 
  	 * @param {String} name The attribute name to retrieve.
  	 * @return {String} The attribute's value, or `undefined` if it does not exist on the HtmlTag.
  	 */
  	getAttr : function( attrName ) {
  		return this.getAttrs()[ attrName ];
  	},
  	
  	
  	/**
  	 * Sets one or more attributes on the HtmlTag.
  	 * 
  	 * @param {Object.<String, String>} attrs A key/value Object (map) of the attributes to set.
  	 * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
  	 */
  	setAttrs : function( attrs ) {
  		var tagAttrs = this.getAttrs();
  		Autolinker.Util.assign( tagAttrs, attrs );
  		
  		return this;
  	},
  	
  	
  	/**
  	 * Retrieves the attributes Object (map) for the HtmlTag.
  	 * 
  	 * @return {Object.<String, String>} A key/value object of the attributes for the HtmlTag.
  	 */
  	getAttrs : function() {
  		return this.attrs || ( this.attrs = {} );
  	},
  	
  	
  	/**
  	 * Sets the provided `cssClass`, overwriting any current CSS classes on the HtmlTag.
  	 * 
  	 * @param {String} cssClass One or more space-separated CSS classes to set (overwrite).
  	 * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
  	 */
  	setClass : function( cssClass ) {
  		return this.setAttr( 'class', cssClass );
  	},
  	
  	
  	/**
  	 * Convenience method to add one or more CSS classes to the HtmlTag. Will not add duplicate CSS classes.
  	 * 
  	 * @param {String} cssClass One or more space-separated CSS classes to add.
  	 * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
  	 */
  	addClass : function( cssClass ) {
  		var classAttr = this.getClass(),
  		    whitespaceRegex = this.whitespaceRegex,
  		    indexOf = Autolinker.Util.indexOf,  // to support IE8 and below
  		    classes = ( !classAttr ) ? [] : classAttr.split( whitespaceRegex ),
  		    newClasses = cssClass.split( whitespaceRegex ),
  		    newClass;
  		
  		while( newClass = newClasses.shift() ) {
  			if( indexOf( classes, newClass ) === -1 ) {
  				classes.push( newClass );
  			}
  		}
  		
  		this.getAttrs()[ 'class' ] = classes.join( " " );
  		return this;
  	},
  	
  	
  	/**
  	 * Convenience method to remove one or more CSS classes from the HtmlTag.
  	 * 
  	 * @param {String} cssClass One or more space-separated CSS classes to remove.
  	 * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
  	 */
  	removeClass : function( cssClass ) {
  		var classAttr = this.getClass(),
  		    whitespaceRegex = this.whitespaceRegex,
  		    indexOf = Autolinker.Util.indexOf,  // to support IE8 and below
  		    classes = ( !classAttr ) ? [] : classAttr.split( whitespaceRegex ),
  		    removeClasses = cssClass.split( whitespaceRegex ),
  		    removeClass;
  		
  		while( classes.length && ( removeClass = removeClasses.shift() ) ) {
  			var idx = indexOf( classes, removeClass );
  			if( idx !== -1 ) {
  				classes.splice( idx, 1 );
  			}
  		}
  		
  		this.getAttrs()[ 'class' ] = classes.join( " " );
  		return this;
  	},
  	
  	
  	/**
  	 * Convenience method to retrieve the CSS class(es) for the HtmlTag, which will each be separated by spaces when
  	 * there are multiple.
  	 * 
  	 * @return {String}
  	 */
  	getClass : function() {
  		return this.getAttrs()[ 'class' ] || "";
  	},
  	
  	
  	/**
  	 * Convenience method to check if the tag has a CSS class or not.
  	 * 
  	 * @param {String} cssClass The CSS class to check for.
  	 * @return {Boolean} `true` if the HtmlTag has the CSS class, `false` otherwise.
  	 */
  	hasClass : function( cssClass ) {
  		return ( ' ' + this.getClass() + ' ' ).indexOf( ' ' + cssClass + ' ' ) !== -1;
  	},
  	
  	
  	/**
  	 * Sets the inner HTML for the tag.
  	 * 
  	 * @param {String} html The inner HTML to set.
  	 * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained.
  	 */
  	setInnerHtml : function( html ) {
  		this.innerHtml = html;
  		
  		return this;
  	},
  	
  	
  	/**
  	 * Retrieves the inner HTML for the tag.
  	 * 
  	 * @return {String}
  	 */
  	getInnerHtml : function() {
  		return this.innerHtml || "";
  	},
  	
  	
  	/**
  	 * Override of superclass method used to generate the HTML string for the tag.
  	 * 
  	 * @return {String}
  	 */
  	toString : function() {
  		var tagName = this.getTagName(),
  		    attrsStr = this.buildAttrsStr();
  		
  		attrsStr = ( attrsStr ) ? ' ' + attrsStr : '';  // prepend a space if there are actually attributes
  		
  		return [ '<', tagName, attrsStr, '>', this.getInnerHtml(), '</', tagName, '>' ].join( "" );
  	},
  	
  	
  	/**
  	 * Support method for {@link #toString}, returns the string space-separated key="value" pairs, used to populate 
  	 * the stringified HtmlTag.
  	 * 
  	 * @protected
  	 * @return {String} Example return: `attr1="value1" attr2="value2"`
  	 */
  	buildAttrsStr : function() {
  		if( !this.attrs ) return "";  // no `attrs` Object (map) has been set, return empty string
  		
  		var attrs = this.getAttrs(),
  		    attrsArr = [];
  		
  		for( var prop in attrs ) {
  			if( attrs.hasOwnProperty( prop ) ) {
  				attrsArr.push( prop + '="' + attrs[ prop ] + '"' );
  			}
  		}
  		return attrsArr.join( " " );
  	}
  	
  } );
  