<?php
if ( ! class_exists('PMXI_Render')){

	class PMXI_Render{

		public function __construct(){

		}

		public static function xml_find_repeating(DOMElement $el, $path = '/')
		{
			$path .= $el->nodeName;
			if ( ! $el->parentNode instanceof DOMDocument) {
				$path .= '[1]';
			}
			$children = array();
			foreach ($el->childNodes as $child) {
				if ($child instanceof DOMElement) {
					if ( ! empty($children[$child->nodeName])) {
						return $path . '/' . $child->nodeName;
					} else {
						$children[$child->nodeName] = true;
					}
				}
			}
			// reaching this point means we didn't find anything among current element children, so recursively ask children to find something in them
			foreach ($el->childNodes as $child) {
				if ($child instanceof DOMElement) {
					$result = slef::xml_find_repeating($child, $path . '/');
					if ($result) {
						return $result;
					}
				}
			}
			// reaching this point means we didn't find anything, so return element itself if the function was called for it
			if ('/' . $el->nodeName == $path) {
				return $path;
			}
			
			return NULL;		
		}	

		public static function render_csv_element(DOMElement $el, $shorten = false, $path = '/', $ind = 1, $lvl = 0)
		{
			$path .= $el->nodeName;		
			if ( ! $el->parentNode instanceof DOMDocument and $ind > 0) {
				$path .= "[$ind]";
			}		
			
			echo '<div class="xml-element csv_element lvl-' . esc_attr($lvl) . ' lvl-mod4-' . ($lvl % 4) . '" title="' . esc_attr($path) . '">';
			if ($el->hasChildNodes()) {
				$is_render_collapsed = $ind > 1;			
				if ($lvl) echo '<div class="csv-tag opening"><span class="csv-tag-name">' . esc_html($el->nodeName) . '</span>'; echo '</div>';
				if (1 == $el->childNodes->length and $el->childNodes->item(0) instanceof DOMText) {
					$child = $el->childNodes->item(0);
					if (!empty($child->wholeText)){
						self::render_csv_text(trim($child->wholeText), $shorten, $is_render_collapsed);
					}
					elseif (is_callable(array($child, 'nodeValue'), true) && isset($child->nodeValue)){
						self::render_csv_text(trim($child->nodeValue), $shorten, $is_render_collapsed);
					}
				} else {
					echo '<div class="csv-content' . ($is_render_collapsed ? ' collapsed' : '') . '">';
					$indexes = array();										
					foreach ($el->childNodes as $child) {
						if ($child instanceof DOMElement) {
							empty($indexes[$child->nodeName]) and $indexes[$child->nodeName] = 0; $indexes[$child->nodeName]++;
							self::render_csv_element($child, $shorten, $path . '/', $indexes[$child->nodeName], $lvl + 1); 
						} elseif ($child instanceof DOMText) {												
							self::render_csv_text(trim($child->wholeText), $shorten); 
						} elseif ($child instanceof DOMComment) {
							if (preg_match('%\[pmxi_more:(\d+)\]%', $child->nodeValue, $mtch)) {
								$no = intval($mtch[1]);
								echo '<div class="xml-more">[ &dArr; ' . sprintf(__('<strong>%s</strong> %s more', 'wp_all_import_plugin'), $no, _n('element', 'elements', $no, 'wp_all_import_plugin')) . ' &dArr; ]</div>';
							}
						}
					}
					echo '</div>';
				}
				//echo '<div class="xml-tag closing"><span class="xml-tag-name">' . $el->nodeName . '</span></div>';
			} else {
				echo '<div class="xml-tag opening empty"><span class="xml-tag-name">' . wp_kses_post($el->nodeName) . '</span>'; self::render_xml_attributes($el); echo '</div>';
			}
			echo '</div>';
		}

		protected static function render_csv_text($text, $shorten = false, $is_render_collapsed = false)
		{
			if (empty($text) and 0 !== (int)$text) {
				return; // do not display empty text nodes
			}
			if (preg_match('%\[more:(\d+)\]%', $text, $mtch)) {
				$no = intval($mtch[1]);
				echo '<div class="xml-more">[ &dArr; ' . sprintf(__('<strong>%s</strong> %s more', 'wp_all_import_plugin'), $no, _n('element', 'elements', $no, 'wp_all_import_plugin')) . ' &dArr; ]</div>';
				return;
			}
			$more = '';
			if ($shorten and preg_match('%^(.*?\s+){20}(?=\S)%', $text, $mtch)) {
				$text = $mtch[0];
				$more = '<span class="xml-more">[' . __('more', 'wp_all_import_plugin') . ']</span>';
			}
			$is_short = strlen($text) <= 40;
			$newtext = htmlspecialchars($text); 
			//$newtext = preg_replace('%(?<!\s)\b(?!\s|\W[\w\s])|\w{20}%', '$0&#8203;', $newtext); // put explicit breaks for xml content to wrap
			echo '<div class="xml-content textonly' . ($is_short ? ' short' : '') . ($is_render_collapsed ? ' collapsed' : '') . ' '. (is_numeric($text) ? 'is_numeric' : '') .'">' . wp_kses_post($newtext . $more) . '</div>';
		}
		public static $option_paths = array();
		public static function render_xml_elements_for_filtring(DOMElement $el, $originPath ='', $lvl = 0){
			$path = $originPath;
			if ("" != $path){ 
				if ($lvl > 1) $path .= "->" . $el->nodeName; else $path = $el->nodeName; 
				if (empty(self::$option_paths[$path])) 
					self::$option_paths[$path] = 1;
				else
					self::$option_paths[$path]++;
				echo '<option value="'. esc_attr($path) .'['. esc_attr(self::$option_paths[$path]) .']">' . esc_html($path) . '['. esc_html(self::$option_paths[$path]) .']</option>';
			}
			else $path = $el->nodeName;		
					
			foreach ($el->attributes as $attr) {
				if (empty($originPath)){
					echo '<option value="@' . esc_attr($attr->nodeName).'">@' . esc_html($attr->nodeName) . '</option>';
				}
				else{
					echo '<option value="'. esc_attr($path) .'['. esc_attr(self::$option_paths[$path]) .']'. '/@' . esc_attr($attr->nodeName).'">'. esc_html($path) .'['. esc_html(self::$option_paths[$path]) .']'. '@' . esc_html($attr->nodeName) . '</option>';
				}
			}
			if ($el->hasChildNodes()) {
				foreach ($el->childNodes as $child) {
					if ($child instanceof DOMElement) 
						self::render_xml_elements_for_filtring($child, $path, $lvl + 1);
				}
			}		
		}

		public static function render_xml_element(DOMElement $el, $shorten = false, $path = '/', $ind = 1, $lvl = 0)
		{
			$render_whole_tree = apply_filters('wp_all_import_is_render_whole_xml_tree', true);

			$path .= $el->nodeName;	
			$alternativePath = $path;	
			if ( ! $el->parentNode instanceof DOMDocument and $ind > 0) {
				$path .= "[$ind]";
			}		
			
			echo '<div class="xml-element lvl-' . esc_attr($lvl) . ' lvl-mod4-' . esc_attr($lvl % 4) . '" title="' . esc_attr($path) . '">';
			//if ($el->hasAttributes()){
				echo '<div class="xml-element-xpaths">'; self::render_element_xpaths($el, $alternativePath, $ind, $lvl); echo '</div>';
			//}
			if ($el->hasChildNodes()) {
				$is_render_collapsed = $ind > 1;
				if ($el->childNodes->length > 1 or ! $el->childNodes->item(0) instanceof DOMText or strlen(trim($el->childNodes->item(0)->wholeText)) > 40) {
					echo '<div class="xml-expander">' . ($is_render_collapsed ? '+' : '-') . '</div>';
				}
				echo '<div class="xml-tag opening">&lt;<span class="xml-tag-name">' . esc_html($el->nodeName) . '</span>'; self::render_xml_attributes($el, $path . '/'); echo '&gt;</div>';
				if (1 == $el->childNodes->length and $el->childNodes->item(0) instanceof DOMText) {
					$item = $el->childNodes->item(0);
					if (!empty($item->wholeText)){
						self::render_xml_text(trim($item->wholeText), $shorten, $is_render_collapsed);
					}
					else{
						self::render_xml_text(trim($item->nodeValue), $shorten, $is_render_collapsed);
					}
				} else {
					echo '<div class="xml-content' . ($is_render_collapsed ? ' collapsed' : '') . '">';
					$indexes = array();
					foreach ($el->childNodes as $eli => $child) {
						if ($child instanceof DOMElement) {
							empty($indexes[$child->nodeName]) and $indexes[$child->nodeName] = 0; $indexes[$child->nodeName]++;
							if ( $render_whole_tree || $indexes[$child->nodeName] === 1){
								self::render_xml_element($child, $shorten, $path . '/', $indexes[$child->nodeName], $lvl + 1);
							}
						} elseif ($child instanceof DOMCdataSection) {
							self::render_xml_text(trim($child->wholeText), $shorten, false, true); 
						} elseif ($child instanceof DOMText) {							
							if ( $el->childNodes->item($eli - 1) and ($el->childNodes->item($eli - 1) instanceof DOMCdataSection) ){

							}
							elseif( $el->childNodes->item($eli + 1) and ($el->childNodes->item($eli + 1) instanceof DOMCdataSection) ){

							}
							else{								
								self::render_xml_text(trim($child->wholeText), $shorten); 
							}
						} elseif ($child instanceof DOMComment) {
							if (preg_match('%\[pmxi_more:(\d+)\]%', $child->nodeValue, $mtch)) {
								$no = intval($mtch[1]);
								echo '<div class="xml-more">[ &dArr; ' . sprintf(__('<strong>%s</strong> %s more', 'wp_all_import_plugin'), $no, _n('element', 'elements', $no, 'wp_all_import_plugin')) . ' &dArr; ]</div>';
							}
						}
					}
					echo '</div>';
				}
				echo '<div class="xml-tag closing">&lt;/<span class="xml-tag-name">' . esc_html($el->nodeName) . '</span>&gt;</div>';
			} else {
				echo '<div class="xml-tag opening empty">&lt;<span class="xml-tag-name">' . esc_html($el->nodeName) . '</span>'; self::render_xml_attributes($el); echo '/&gt;</div>';
			}
			echo '</div>';
		}

		protected static function render_xml_text($text, $shorten = false, $is_render_collapsed = false, $is_cdata = false)
		{
			if (empty($text) and 0 !== (int)$text) {
				return; // do not display empty text nodes
			}
			if (preg_match('%\[more:(\d+)\]%', $text, $mtch)) {
				$no = intval($mtch[1]);
				echo '<div class="xml-more">[ &dArr; ' . sprintf(__('<strong>%s</strong> %s more', 'wp_all_import_plugin'), $no, _n('element', 'elements', $no, 'wp_all_import_plugin')) . ' &dArr; ]</div>';
				return;
			}
			$more = '';
			if ($shorten and preg_match('%^(.*?\s+){20}(?=\S)%', $text, $mtch)) {
				$text = $mtch[0];
				$more = '<span class="xml-more">[' . __('more', 'wp_all_import_plugin') . ']</span>';
			}			
			$is_short = strlen($text) <= 40;			
			$text = htmlspecialchars($text);
			if ($is_cdata){
				$text = "<span class='wpallimport-cdata'>" . htmlspecialchars("<![CDATA[") . "</span> " . $text . " <span class='wpallimport-cdata'>" . htmlspecialchars("]]>") . "</span>";
			}			
			//$text = preg_replace('%(?<!\s)\b(?!\s|\W[\w\s])|\w{20}%', '$0&#8203;', $text); // put explicit breaks for xml content to wrap
			echo '<div class="xml-content textonly' . ($is_short ? ' short' : '') . ($is_render_collapsed ? ' collapsed' : '') . '">' . esc_html($text . $more) . '</div>';
		}

		public static function get_xml_path(DOMElement $el, DOMXPath $xpath)
		{
			for($p = '', $doc = $el; $doc and ! $doc instanceof DOMDocument; $doc = $doc->parentNode) {
				if (($ind = $xpath->query('preceding-sibling::' . $doc->nodeName, $doc)->length)) {
					$p = '[' . ++$ind . ']' . $p;
				} elseif ( ! $doc->parentNode instanceof DOMDocument) {
					$p = '[' . ($ind = 1) . ']' . $p;
				}
				$p = '/' . $doc->nodeName . $p;
			}
			return $p;
		}

		protected static function render_xml_attributes(DOMElement $el, $path = '/')
		{
			foreach ($el->attributes as $attr) {
				echo ' <span class="xml-attr" title="' . esc_attr($path) . '@' . esc_attr($attr->nodeName) . '"><span class="xml-attr-name">' . esc_html($attr->nodeName) . '</span>=<span class="xml-attr-value">"' . esc_attr($attr->value) . '"</span></span>';
			}
		}	

		protected static function render_element_xpaths(DOMElement $el, $path = '/', $ind = 1, $lvl = 0){						
			?>
			<ul id="menu-<?php echo str_replace('/', '-', esc_attr($path)); ?>" class="ui-helper-hidden">
				<?php foreach ($el->attributes as $attr) : if ( empty($attr->value) ) continue; ?>
			    <li data-command="action1" title="<?php echo esc_attr($path . '[@'. $attr->nodeName .' = "' . $attr->value . '"]'); ?>">
			    	<a href="#"><?php echo wp_kses_post($path . '[@'. $attr->nodeName .' = "' . $attr->value) . '"]'; ?></a>
			    </li>
			    <li data-command="action2" title="<?php echo esc_attr($path . '[@'. $attr->nodeName .'[contains(.,"' . $attr->value . '")]]'); ?>">
			    	<a href="#"><?php echo wp_kses_post($path . '[@'. $attr->nodeName .'[contains(.,"' . $attr->value) . '")]]'; ?></a>
			    </li>
				<?php endforeach; ?>
				<?php 
				$altNode = null;
				$altNodeText = null;
				$parentNode = $el->parentNode;
				$grandNode = $parentNode->parentNode;
				
				if ( ! $grandNode instanceof DOMDocument and $grandNode instanceof DOMElement ){		
					
					$equalsElements = 0;
					foreach ($grandNode->childNodes as $child) {
						if ($child instanceof DOMElement) {
							if ($child->nodeName == $parentNode->nodeName){
								$equalsElements++;
								if ($equalsElements > 1)
									break;
							}
						}
					}													

					if ($equalsElements > 1){
						if ($parentNode->hasChildNodes()) {
							foreach ($parentNode->childNodes as $i => $child) {
								if ($child instanceof DOMElement) {
									if ($child->nodeName != $el->nodeName){
										$altNode = $child;
										if ($child->hasChildNodes()){
											foreach ($child->childNodes as $i => $txtChild) {
												if ($txtChild instanceof DOMText) {
													$altNodeText = $txtChild;										
													break;
												}
											}
										}										
										break;
									}
								}
							}
						}
						
						if ( ! empty($altNode) and !empty($altNodeText) ){

							$pathArgs = explode('/', $path);
							array_pop($pathArgs);						
							array_pop($pathArgs);		
							$vpath = esc_attr(implode('/', $pathArgs) . '/' . $parentNode->nodeName . '[contains('. $altNode->nodeName .',"' . esc_attr($altNodeText->wholeText) . '")]/' . $el->nodeName);				
							?>
							<li data-command="action3" title="<?php echo esc_attr($vpath); ?>">
						    	<a href="#"><?php echo esc_html($vpath); ?></a>
						    </li>						
						    <?php

						}
					}					
				}				
				?>								
			</ul>
			<?php			
		}
	}
}