<commit_before>/*
 * Copyright (C)2017 <NAME> (derRaab) | blog.derraab.com | superclass.de
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

package de.superclass.haxe.util;

/**
	`SvgUtil` provides simple helper methods for svg manipulation.
**/
class SvgUtil {
	
	private static var _ids: Array<String> = [];

	/**
		Prefixes all SVG internal id values and their usages.
	**/
    public static function prefixIds( svgXmlRootNode : Xml, prefix : String ) : Void {

	    _iterateAllElements( svgXmlRootNode.elements(), prefix );
    }

	private static function _iterateAllElements( elements : Iterator<Xml> , prefix : String ) : Void {

		while( elements.hasNext() ){

			var element : Xml = elements.next();

			if ( element.nodeName.toLowerCase() == "style" ) {

				_setPrefixToStyle( element, prefix );
			}
			else {

				if( element.exists( "class" ) ) {

					_prefixAttribute( element , prefix , "class" );
				}

				if( element.exists( "id" ) ) {

					_setPrefixToId( element , prefix ) ;
				}

				if( element.exists( "xlink:href" ) ) {

					_setPrefixToUse( element , prefix ) ;
				}

				if( element.exists( "mask" ) ) {

					_setPrefixToAttribute( element , prefix , "mask" ) ;
				}

				if( element.exists( "filter" ) ) {

					_setPrefixToAttribute( element , prefix , "filter" );
				}

				if( element.exists( "fill" ) ) {

					_setPrefixToAttribute( element , prefix , "fill" );
				}

				if( element.exists( "clip-path" ) ) {

					_setPrefixToAttribute( element , prefix , "clip-path" );
				}
			}

			var childElements = element.elements();
			if( childElements != null ) {

				_iterateAllElements( childElements, prefix );
			}
		}
	}

	private static function _setPrefixToStyle( styleElement : Xml , prefix: String ) : Void {

		var cssStringXml : Xml = styleElement.firstChild();
		if ( cssStringXml == null ) {

			return;
		}

		styleElement.removeChild( cssStringXml );

		var cssString = "" + cssStringXml;

		// Extract all strings between . and {
		var eregClass : EReg = ~/(\.)(.*)(\{)/ig;

		var cssClasses : Array<String> = ERegUtil.getMatchedArray( eregClass, 2, cssString );
		for ( i in 0...cssClasses.length ) {

			var cssClass : String = cssClasses[ i ];
			cssString = StringUtil.replace( cssString, "." + cssClass + "{", "." + prefix + cssClass + "{" );
		}

		styleElement.addChild( Xml.createPCData( cssString ) );
	}

	private static function _setPrefixToId( element : Xml , prefix: String ) : Void {

		var id : String = element.get( "id" );
		var ids : Array<String> = _ids;
			ids[ ids.length ] = id;<commit_msg>Prefix only in svg defined styles<commit_after>/*
 * Copyright (C)2017 <NAME> (derRaab) | blog.derraab.com | superclass.de
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

package de.superclass.haxe.util;

/**
	`SvgUtil` provides simple helper methods for svg manipulation.
**/
import haxe.ds.StringMap;

class SvgUtil {
	
	private static var _ids: Array<String> = [];

	/**
		Prefixes all SVG internal id values and their usages.
	**/
    public static function prefixIds( svgXmlRootNode : Xml, prefix : String ) : Void {

		// Collect elements for special css treatment
		var elementsWithClass : Array<Xml> = [];
		var styleElements : Array<Xml> = [];

	    _iterateAllElements( svgXmlRootNode.elements(), prefix, elementsWithClass, styleElements );

		// Prefix only in svg defined styles
		_setPrefixToStyles( prefix, elementsWithClass, styleElements );
    }

	private static function _setPrefixToStyles( prefix : String, elementsWithClass : Array<Xml>, styleElements : Array<Xml> ) : Void {

		// Collect all defined svg specific css classes
		var cssClassMap : StringMap<String> = new StringMap<String>();
		var cssClassMapUsed : Bool = false;

		for ( i in 0...styleElements.length ) {

			var styleElement : Xml = styleElements[ i ];
			var cssClasses : Array<String> = _setPrefixToStyle( styleElement, prefix );
			if ( ArrayUtil.hasLength( cssClasses ) ) {

				for ( ii in 0...cssClasses.length ) {

					var cssClass : String = cssClasses[ ii ];
					cssClassMap.set( cssClass, cssClass );

					cssClassMapUsed = true;
				}
			}
		}

		if ( ! cssClassMapUsed ) {

			return;
		}

		// Prefix just the defined svg specific classes - others might be put in for an external reason!
		for ( i in 0...elementsWithClass.length ) {

			var element : Xml = elementsWithClass[ i ];
			var className : String = element.get( "class" );
			if ( StringUtil.hasLength( className ) ) {

				var classNameNew : String = null;

				if ( StringUtil.contains( className, " " ) ) {

					// Multiple classes
					var classNameArray : Array<String> = className.split( " " );
					for ( ii in 0...classNameArray.length ) {

						var className2 : String = classNameArray[ ii ];
						if ( cssClassMap.exists( className2 ) ) {

							classNameArray[ ii ] = prefix + className2;
						}
					}

					classNameNew = classNameArray.join( " " );
				}
				else {

					// Only one class
					if ( cssClassMap.exists( className ) ) {

						classNameNew = prefix + className;
					}
					else {

						classNameNew = className;
					}
				}

				// Refresh only if actually changed
				if ( className != classNameNew ) {

					element.set( "class", classNameNew );
				}
			}
		}
	}

	private static function _iterateAllElements( elements : Iterator<Xml> , prefix : String, elementsWithClass : Array<Xml>, styleElements : Array<Xml> ) : Void {

		while( elements.hasNext() ){

			var element : Xml = elements.next();

			if ( element.nodeName.toLowerCase() == "style" ) {

				// Collect
				styleElements.push( element );
			}
			else {

				if( element.exists( "class" ) ) {

					// Collect
					elementsWithClass.push( element );
				}

				if( element.exists( "id" ) ) {

					_setPrefixToId( element , prefix ) ;
				}

				if( element.exists( "xlink:href" ) ) {

					_setPrefixToUse( element , prefix ) ;
				}

				if( element.exists( "mask" ) ) {

					_setPrefixToAttribute( element , prefix , "mask" ) ;
				}

				if( element.exists( "filter" ) ) {

					_setPrefixToAttribute( element , prefix , "filter" );
				}

				if( element.exists( "fill" ) ) {

					_setPrefixToAttribute( element , prefix , "fill" );
				}

				if( element.exists( "clip-path" ) ) {

					_setPrefixToAttribute( element , prefix , "clip-path" );
				}
			}

			var childElements = element.elements();
			if( childElements != null ) {

				_iterateAllElements( childElements, prefix, elementsWithClass, styleElements );
			}
		}
	}

	private static function _setPrefixToStyle( styleElement : Xml , prefix: String ) : Array<String> {

		var cssStringXml : Xml = styleElement.firstChild();
		if ( cssStringXml == null ) {

			return null;
		}

		styleElement.removeChild( cssStringXml );

		var cssString = "" + cssStringXml;

		// Extract all strings between . and {
		var eregClass : EReg = ~/(\.)(.*)(\{)/ig;

		var cssClasses : Array<String> = ERegUtil.getMatchedArray( eregClass, 2, cssString );
		for ( i in 0...cssClasses.length ) {

			var cssClass : String = cssClasses[ i ];
			cssString = StringUtil.replace( cssString, "." + cssClass + "{", "." + prefix + cssClass + "{" );
		}

		styleElement.addChild( Xml.createPCData( cssString ) );

		return cssClasses;
	}

	private static function _setPrefixToId( element : Xml , prefix: String ) : Void {

		var id : String = element.get( "id" );
		var ids : Array<String> = _ids;
			ids[ ids.length ] = id;
{'fraction_non_alphanumeric': 0.11240228185083456, 'fraction_numerical': 0.0020071836044791885, 'mean_word_length': 3.1723226090788894, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6803584', 'n_tokens_mistral': 3286, 'n_tokens_neox': 2720, 'n_words': 912}