Your IP : 216.73.217.53


Current Path : /home/bonneesp/www/administrator/components/com_tabulizer/assets/classes/admin/
Upload File :
Current File : /home/bonneesp/www/administrator/components/com_tabulizer/assets/classes/admin/ruleset.php

<?php
/**
 * @version		6.5.0 tabulizer $
 * @package		tabulizer
 * @copyright	Copyright © 2011 - All rights reserved.
 * @license		GNU/GPL
 * @author		Dimitrios Mourloukos
 * @author mail	info@alterora.gr
 * @website		www.tabulizer.com
 * 
 */


// no direct access
defined('_JEXEC') or die('Restricted access');

if (!defined('XML_FILE_EXT')) define('XML_FILE_EXT','.xml');

class Ruleset {

	var $rulesets = null;
	var $conflicts = null;	
	var $errors = null;	

	/**
	Rulesets
	*/

	function loadRulesets($filename = null, $limit=0, $limitstart=0, &$total_count) {
		$dir = TabulizerPath::getDirPath('rules');									
		
		$xmlfiles = array();
		if (empty($filename)) {
			# load all xml files in rules folder					
			if (is_dir($dir)) {
				if ($dh = opendir($dir)) {
					while (($file = readdir($dh)) !== false) {
						if (is_file($dir . $file)) {
							if (preg_match('/'.XML_FILE_EXT.'$/i',$file)) {
								$xmlfiles[] = $file;
							}
						}
					}	
					closedir($dh);
				}			
			}
		} else {
			# load sepcific xml file
			if (file_exists($dir . $filename)) {
				$xmlfiles[] = $filename;
			}
		}

		# keep pagination count (either for archives or rulesets)								
		$archive_count = empty($xmlfiles)?0:count($xmlfiles);				
		$ruleset_count = 0;	
		
		# traverse files			
		if (!empty($xmlfiles)) {			
			foreach ($xmlfiles as $archive_count => $xmlfile) {
				// the pagination limits can apply either to ruleset archives to ruleset within a specific archive
				// for this reason, check if the filename exists				
				if (empty($filename)) {
					if (($limit) && (($archive_count<$limitstart)||($archive_count>=($limitstart + $limit)))) continue; 
				} 				
				$contents = file_get_contents($dir . $xmlfile);
				if (empty($contents)) continue;
				
				$p = xml_parser_create();
				xml_parse_into_struct($p, $contents, $vals, $index);
				xml_parser_free($p);
				
				$ruleset = array();
				$xmlfile_noext = pathinfo($xmlfile, PATHINFO_FILENAME);									
				$archive_filename = $xmlfile;
				
				# init vars
				$archive_name = $archive_title = $archive_description = $archive_style = '';
				$archive_meta = array('compatibility'=>0);	
				
				$ruleset_name = $ruleset_title = $ruleset_description = $ruleset_style = $ruleset_suffix = '';				
				$ruleset_sample_data_caption = $ruleset_sample_data_text = $ruleset_sample_data_sep = $ruleset_sample_data_enc = '';
				$ruleset_preselected = 0;
				
				$rule_element = $rule_range = $rule_style = '';																			
				
				$used = array('rulesets' => array('names' => array(), 'titles' => array()));				
				$rulesets = array();
				$ruleset = array();
										
				foreach ($vals as $node) {
					switch ($node['tag']) {						
						case 'META':
							if (!empty($node['attributes']['VERSION'])) {
								$archive_meta['version'] = floatval(trim($node['attributes']['VERSION']));
							}
							if (!empty($node['attributes']['COMPATIBILITY'])) {
								$archive_meta['compatibility'] = floatval(trim($node['attributes']['COMPATIBILITY']));
							}
							if (!empty($node['attributes']['GENERATOR'])) {
								$archive_meta['generator'] = trim($node['attributes']['GENERATOR']);
							}
							if (!empty($node['attributes']['LAST_MODIFIED'])) {
								$archive_meta['last_modified'] = strtotime(trim($node['attributes']['LAST_MODIFIED']));
							}
							if (!empty($node['attributes']['AUTHOR_NAME'])) {
								$archive_meta['author_name'] = trim($node['attributes']['AUTHOR_NAME']);
							}
							if (!empty($node['attributes']['AUTHOR_EMAIL'])) {
								$archive_meta['author_email'] = trim($node['attributes']['AUTHOR_EMAIL']);
							}
							if (!empty($node['attributes']['AUTHOR_URL'])) {
								$archive_meta['author_url'] = trim($node['attributes']['AUTHOR_URL']);
							}												
							break;

						case 'RULES':
							if ($node['type'] == 'open') {					
								if (!empty($node['attributes']['NAME'])) $archive_name = trim($node['attributes']['NAME']);
								if (!empty($node['attributes']['TITLE'])) $archive_title = trim($node['attributes']['TITLE']);
                                if (!empty($node['attributes']['DESCRIPTION'])) $archive_description = trim($node['attributes']['DESCRIPTION']);
								if (!empty($node['attributes']['STYLE'])) $archive_style = trim($node['attributes']['STYLE']);
							} else if ($node['type'] == 'close') {
								$ruleset_archive = array('name'=>$archive_name, 'title'=>$archive_title, 'description'=>$archive_description, 'style'=>$archive_style, 'meta'=> $archive_meta, 'rulesets'=>$rulesets, 'filename'=>$archive_filename);
								$this->rulesets[$xmlfile_noext] = $ruleset_archive;
							} else if ($node['type'] == 'complete') {
								if (!empty($node['attributes']['NAME'])) $archive_name = trim($node['attributes']['NAME']);
								if (!empty($node['attributes']['TITLE'])) $archive_title = trim($node['attributes']['TITLE']);
                                if (!empty($node['attributes']['DESCRIPTION'])) $archive_description = trim($node['attributes']['DESCRIPTION']);
								if (!empty($node['attributes']['STYLE'])) $archive_style = trim($node['attributes']['STYLE']);																
								$ruleset_archive = array('name'=>$archive_name, 'title'=>$archive_title, 'description'=>$archive_description, 'style'=>$archive_style, 'meta'=> $archive_meta, 'rulesets'=>$rulesets, 'filename'=>$archive_filename);
								$this->rulesets[$xmlfile_noext] = $ruleset_archive;																
							}				
							break;
							
						case 'RULESET':
							if ($node['type'] == 'open') {					
								if (!empty($node['attributes']['NAME'])) $ruleset_name = trim($node['attributes']['NAME']);
								if (!empty($node['attributes']['TITLE'])) $ruleset_title = trim($node['attributes']['TITLE']);
								if (!empty($node['attributes']['DESCRIPTION'])) $ruleset_description = trim($node['attributes']['DESCRIPTION']);
								if (!empty($node['attributes']['STYLE'])) $ruleset_style = trim($node['attributes']['STYLE']);
								if (!empty($node['attributes']['SUFFIX'])) $ruleset_suffix = trim($node['attributes']['SUFFIX']);
								if (!empty($node['attributes']['PRESELECTED'])) $ruleset_preselected = 1;
								if (!empty($node['attributes']['SAMPLE_DATA_TEXT']) && !empty($node['attributes']['SAMPLE_DATA_SEP'])) {
									$ruleset_sample_data_caption = empty($node['attributes']['SAMPLE_DATA_CAPTION'])?'':trim(str_replace(SEPARATOR_NEWLLINE,"\n",$node['attributes']['SAMPLE_DATA_CAPTION']));
									$ruleset_sample_data_text = trim(str_replace(SEPARATOR_NEWLLINE,"\n",$node['attributes']['SAMPLE_DATA_TEXT']));
									$ruleset_sample_data_sep = trim($node['attributes']['SAMPLE_DATA_SEP']);
									$ruleset_sample_data_enc = empty($node['attributes']['SAMPLE_DATA_ENC'])?'':trim($node['attributes']['SAMPLE_DATA_ENC']);									
								}																																									
							} else if (($node['type'] == 'close')) {
								if (empty($rulesetname) || ($rulesetname == $ruleset_name)) {
									// check for duplicates names
									if (isset($used['rulesets']['names'][$ruleset_name])) {
										if (empty($this->conflicts['rulesets'])) $this->conflicts['rulesets'] = array('names' => array(), 'titles' => array());
										if (empty($this->conflicts['rulesets']['names'][$xmlfile_noext])) $this->conflicts['rulesets']['names'][$xmlfile_noext] = array();
										$this->conflicts['rulesets']['names'][$xmlfile_noext][] = array('value' => $ruleset_name, 'already_defined' => $used['rulesets']['names'][$ruleset_name]);
									} else {
										// pagination
										$pagination_ignore_ruleset = false;
										$ruleset_count++;
										if (!empty($filename)) {
											if (($limit) && (($ruleset_count<$limitstart)||($ruleset_count>=($limitstart + $limit)))) {
												$pagination_ignore_ruleset = true;
											} 
										}	
										if (!$pagination_ignore_ruleset) {
											$rulesets[$ruleset_name] = array('name'=> $ruleset_name, 'title'=>$ruleset_title, 'description'=>$ruleset_description, 'style'=>$ruleset_style, 'style_inherited'=>$archive_style, 'preselected'=>$ruleset_preselected, 'suffix'=>$ruleset_suffix, 'rules'=>$ruleset, 'filename'=>$archive_filename);
										}	
										if (!empty($ruleset_sample_data_text) && !empty($ruleset_sample_data_sep)) { $rulesets[$ruleset_name]['sample_data'] = 1; $rulesets[$ruleset_name]['sample_data_caption'] = $ruleset_sample_data_caption; $rulesets[$ruleset_name]['sample_data_text'] = $ruleset_sample_data_text; $rulesets[$ruleset_name]['sample_data_sep'] = $ruleset_sample_data_sep; $rulesets[$ruleset_name]['sample_data_enc'] = $ruleset_sample_data_enc; }
										$used['rulesets']['names'][$ruleset_name] = $xmlfile_noext;																														
									}	
									// check for duplicates titles									
									if (isset($used['rulesets']['titles'][$ruleset_title])) {							
										$resolve_duplicate_titles = true;
										if ($resolve_duplicate_titles) {
											$rulesets[$ruleset_name]['title'] = $rulesets[$ruleset_name]['title'] . ' ('.$ruleset_name.')';
										} else {																					
											if (empty($this->conflicts['rulesets'])) $this->conflicts['rulesets'] = array('names' => array(), 'titles' => array());
											if (empty($this->conflicts['rulesets']['titles'][$xmlfile_noext])) $this->conflicts['rulesets']['titles'][$xmlfile_noext] = array();
											$this->conflicts['rulesets']['titles'][$xmlfile_noext][] = array('value' => $ruleset_title, 'already_defined' => $used['rulesets']['titles'][$ruleset_title]);
										}
									} else {
										$used['rulesets']['titles'][$ruleset_title] = $xmlfile_noext;
									}
								}	
								$ruleset_name = $ruleset_title = $ruleset_description = $ruleset_style =  $ruleset_suffix = '';
								$ruleset_sample_data_caption = $ruleset_sample_data_text = $ruleset_sample_data_sep = $ruleset_sample_data_enc = '';							
								$ruleset_preselected = 0;
								$ruleset = array();
							} else if ($node['type'] == 'complete') {					
								if (!empty($node['attributes']['NAME'])) $ruleset_name = trim($node['attributes']['NAME']);
								if (!empty($node['attributes']['TITLE'])) $ruleset_title = trim($node['attributes']['TITLE']);
								if (!empty($node['attributes']['DESCRIPTION'])) $ruleset_description = trim($node['attributes']['DESCRIPTION']);
								if (!empty($node['attributes']['STYLE'])) $ruleset_style = trim($node['attributes']['STYLE']);
								if (!empty($node['attributes']['SUFFIX'])) $ruleset_suffix = trim($node['attributes']['SUFFIX']);
								if (!empty($node['attributes']['PRESELECTED'])) $ruleset_preselected = 1;																
								
								if (empty($rulesetname) || ($rulesetname == $ruleset_name)) {																																
									// check for duplicates names
									if (isset($used['rulesets']['names'][$ruleset_name])) {																			
										if (empty($this->conflicts['rulesets'])) $this->conflicts['rulesets'] = array('names' => array(), 'titles' => array());
										if (empty($this->conflicts['rulesets']['names'][$xmlfile_noext])) $this->conflicts['rulesets']['names'][$xmlfile_noext] = array();
										$this->conflicts['rulesets']['names'][$xmlfile_noext][] = array('value' => $ruleset_name, 'already_defined' => $used['rulesets']['names'][$ruleset_name]);
									} else {									
										// pagination
										$pagination_ignore_ruleset = false;
										$ruleset_count++;
										if (!empty($filename)) {
											if (($limit) && (($ruleset_count<$limitstart)||($ruleset_count>=($limitstart + $limit)))) {
												$pagination_ignore_ruleset = true;
											} 
										}	
										if (!$pagination_ignore_ruleset) {
											$rulesets[$ruleset_name] = array('name'=> $ruleset_name, 'title'=>$ruleset_title, 'description'=>$ruleset_description, 'style'=>$ruleset_style, 'style_inherited'=>$archive_style, 'preselected'=>$ruleset_preselected, 'suffix'=>$ruleset_suffix, 'rules'=>$ruleset, 'filename'=>$archive_filename);
										}																												
										if (!empty($ruleset_sample_data_text)) { $rulesets[$ruleset_name]['sample_data'] = 1; $rulesets[$ruleset_name]['sample_data_caption'] = $ruleset_sample_data_caption; $rulesets[$ruleset_name]['sample_data_text'] = $ruleset_sample_data_text; $rulesets[$ruleset_name]['sample_data_sep'] = $ruleset_sample_data_sep; $rulesets[$ruleset_name]['sample_data_enc'] = $ruleset_sample_data_enc; }
										$used['rulesets']['names'][$ruleset_name] = $xmlfile_noext;										
									}	
									// check for duplicates titles									
									if (isset($used['rulesets']['titles'][$ruleset_title])) {									
										if (empty($this->conflicts['rulesets'])) $this->conflicts['rulesets'] = array('names' => array(), 'titles' => array());
										if (empty($this->conflicts['rulesets']['titles'][$xmlfile_noext])) $this->conflicts['rulesets']['titles'][$xmlfile_noext] = array();
										$this->conflicts['rulesets']['titles'][$xmlfile_noext][] = array('value' => $ruleset_title, 'already_defined' => $used['rulesets']['titles'][$ruleset_title]);																														
									} else {
										$used['rulesets']['titles'][$ruleset_title] = $xmlfile_noext;
									}									
								}	
								$ruleset_name = $ruleset_title = $ruleset_description = $ruleset_style = $ruleset_suffix = '';
								$ruleset_sample_data_caption = $ruleset_sample_data_text = $ruleset_sample_data_sep = $ruleset_sample_data_enc = '';
								$ruleset_preselected = 0;
								$ruleset = array();
							}
							break;
							
						case 'RULE':
							if ($node['type'] == 'complete') {															
								$attributes = $node['attributes'];
								$rule_element = $rule_element_section = $rule_range = $rule_range_key = $rule_priority = $rule_style = $rule_attribute = $rule_autospan = $rule_th_tag = $rule_remove = $rule_format = $rule_replacement = $rule_calculation = $rule_split = $rule_filter = $rule_column_filter = $rule_sort = $rule_pagination = $rule_scroll = $rule_theme = $rule_responsive = $rule_graph = $rule_prepend = $rule_append = $rule_add_files = $rule_export_table = $rule_modification = '';
								if (!empty($attributes['ELEMENT'])) $rule_element = trim($attributes['ELEMENT']);
								if (!empty($attributes['ELEMENT_SECTION'])) $rule_element_section = trim($attributes['ELEMENT_SECTION']);
								// range will be processed later on, based on its compatibility number in order to decode actual values
								if (!empty($attributes['RANGE'])) $rule_range = trim($attributes['RANGE']);								
								// keep RANGE_COUNT for backward compatibility																	
								if (!empty($attributes['RANGE_COUNT'])) $rule_range_key = trim($attributes['RANGE_COUNT']);
								if (!empty($attributes['RANGE_KEY'])) $rule_range_key = trim($attributes['RANGE_KEY']);
                                if (!empty($attributes['PRIORITY'])) $rule_priority = trim($attributes['PRIORITY']);

                                if (!empty($attributes['STYLE'])) $rule_style = trim($attributes['STYLE']);
                                if (!empty($attributes['ATTRIBUTE'])) $rule_attribute = trim($attributes['ATTRIBUTE']);
								if (!empty($attributes['AUTOSPAN'])) $rule_autospan = trim($attributes['AUTOSPAN']);
                                if (!empty($attributes['TH_TAG'])) $rule_th_tag = trim($attributes['TH_TAG']);
                                if (!empty($attributes['REMOVE'])) $rule_remove = trim($attributes['REMOVE']);
								if (!empty($attributes['FORMAT'])) $rule_format = trim($attributes['FORMAT']);
								if (!empty($attributes['CALCULATION'])) $rule_calculation = trim($attributes['CALCULATION']);
                                if (!empty($attributes['MODIFICATION'])) $rule_modification = trim($attributes['MODIFICATION']);
								if (!empty($attributes['REPLACEMENT'])) $rule_replacement = trim($attributes['REPLACEMENT']);								
								if (!empty($attributes['PREPEND'])) $rule_prepend = trim($attributes['PREPEND']);
								if (!empty($attributes['APPEND'])) $rule_append = trim($attributes['APPEND']);
                                if (!empty($attributes['ADD_FILES'])) $rule_add_files = trim($attributes['ADD_FILES']);
                                if (!empty($attributes['SPLIT'])) $rule_split = trim($attributes['SPLIT']);
								if (!empty($attributes['FILTER'])) $rule_filter = trim($attributes['FILTER']);
                                if (!empty($attributes['COLUMN_FILTER'])) $rule_column_filter = trim($attributes['COLUMN_FILTER']);
								if (!empty($attributes['SORT'])) $rule_sort = trim($attributes['SORT']);
								if (!empty($attributes['PAGINATION'])) $rule_pagination = trim($attributes['PAGINATION']);
								if (!empty($attributes['SCROLL'])) $rule_scroll = trim($attributes['SCROLL']);
                                if (!empty($attributes['THEME'])) $rule_theme = trim($attributes['THEME']);
								if (!empty($attributes['RESPONSIVE'])) $rule_responsive = trim($attributes['RESPONSIVE']);																
								if (!empty($attributes['GRAPH'])) $rule_graph = trim($attributes['GRAPH']);
								if (!empty($attributes['EXPORT_TABLE'])) $rule_export_table = trim($attributes['EXPORT_TABLE']);																
								
								$ruleset[] = array('element'=>$rule_element, 'element_section'=>$rule_element_section, 'range'=>$rule_range, 'range_key'=>$rule_range_key, 'priority'=>$rule_priority, 'style'=>$rule_style, 'attribute'=>$rule_attribute, 'autospan'=>$rule_autospan, 'th_tag'=>$rule_th_tag, 'remove'=>$rule_remove, 'format'=>$rule_format, 'replacement'=>$rule_replacement, 'calculation'=>$rule_calculation, 'modification'=>$rule_modification,
													'split'=>$rule_split, 'filter'=>$rule_filter, 'column_filter'=>$rule_column_filter, 'sort'=>$rule_sort, 'pagination'=>$rule_pagination, 'scroll'=>$rule_scroll, 'theme'=>$rule_theme, 'responsive'=>$rule_responsive, 'graph'=>$rule_graph, 'prepend'=>$rule_prepend, 'append'=>$rule_append, 'add_files'=>$rule_add_files, 'export_table' => $rule_export_table);
							}
							break;
							
						case 'SAMPLE_DATA':
							if ($node['type'] == 'complete') {					
								if (!empty($node['attributes']['CAPTION'])) $ruleset_sample_data_caption = trim(str_replace(SEPARATOR_NEWLLINE,"\n",$node['attributes']['CAPTION']));
								if (!empty($node['attributes']['SEP'])) $ruleset_sample_data_sep = trim($node['attributes']['SEP']);
								if (!empty($node['attributes']['ENC'])) $ruleset_sample_data_enc = trim($node['attributes']['ENC']);
								$ruleset_sample_data_text = trim($node['value']);								
							}	
							break;										
							
						default:
							$this->errors[] = sprintf(JText::_('INVALID XML TAG'), $node['tag']);	
							break;
	
					}
				}																															
								
			}
		} else {
			$errors[] = JText::_('NO VALID RULESET ARCHIVES');
		}			
		
		// finally, decode some encoded values, based on compatibility mode
		if (!empty($this->rulesets)) {
			foreach ($this->rulesets as $xmlfile_noext => &$ruleset_archive) {
				$this->decodeXMLSafe($ruleset_archive);
				if ($ruleset_archive['meta']['compatibility'] < 4) {
					// uodate compatibility, to mark conversion
					$ruleset_archive['meta']['compatibility'] = 4;
					foreach ($ruleset_archive['rulesets'] as $ruleset_name => &$ruleset) {
						foreach ($ruleset['rules'] as &$rule) {
							// rule range
							if (!empty($rule['range'])) {
								$rule_range = $rule['range'];
								$range_raw = $rule_range;
								$rule_range = strtoupper(str_replace(' ','', trim($rule_range)));
								if (preg_match('/^SAME(.+)/i',$rule_range) || preg_match('/^CONTAIN(.+)/i',$rule_range)) {
									// encode base64 text values																											
									if (preg_match( '/^SAMEI(.+)$/i', $range_raw, $matches)) {
										$value = mb_strtoupper(trim($matches[1]));
										$rule_range = 'SAMEI'.base64_encode($value);
									} else if (preg_match( '/^SAMENI(.+)$/i', $range_raw, $matches)) {
										$value = mb_strtoupper(trim($matches[1]));
										$rule_range = 'SAMENI'.base64_encode($value);			
									} else if (preg_match( '/^SAMEN(.+)$/i', $range_raw, $matches)) {
										$value = mb_strtoupper(trim($matches[1]));
										$rule_range = 'SAMEN'.base64_encode($value);		
									} else if (preg_match( '/^SAME(.+)$/i', $range_raw, $matches)) {
										$value = trim($matches[1]);
										$rule_range = 'SAME'.base64_encode($value);
									} else if (preg_match( '/^CONTAINI(.+)$/i', $range_raw, $matches)) {
										$value = trim($matches[1]);
										$rule_range = 'CONTAINI'.base64_encode($value);
									} else if (preg_match( '/^CONTAINNI(.+)$/i', $range_raw, $matches)) {
										$value = trim($matches[1]);
										$rule_range = 'CONTAINNI'.base64_encode($value);
									} else if (preg_match( '/^CONTAINN(.+)$/i', $range_raw, $matches)) {
										$value = trim($matches[1]);
										$rule_range = 'CONTAINN'.base64_encode($value);
									} else if (preg_match( '/^CONTAINT(.+)$/i', $range_raw, $matches)) {
                                        $value = trim($matches[1]);
                                        $rule_range = 'CONTAINT'.base64_encode($value);
                                    } else if (preg_match( '/^CONTAIN(.+)$/i', $range_raw, $matches)) {
										$value = trim($matches[1]);
										$rule_range = 'CONTAIN'.base64_encode($value);
									}
									$rule['range'] = $rule_range;																																											
								} else {																					
									# <> are not allowed in the XML files, so replace them with LT and GT
									$gl_values = array('LTE','LT','GTE','GT');
									$sy_values = array('<=','<','>=','>');									
									$rule_range = str_replace($gl_values, $sy_values, $rule_range);						
									$rule['range'] = $rule_range;
								}								
							}
							
							// replacement text
							if (!empty($rule['replacement'])) {
								list($case_sensitive,$replace_from,$replace_to) = explode(REPLACEMENT_SEPARATOR,$rule['replacement'],3);
								$rule['replacement'] =  $case_sensitive.REPLACEMENT_SEPARATOR.base64_encode($replace_from).REPLACEMENT_SEPARATOR.base64_encode($replace_to);
							}
						}
					}
				}				
			}
		}		
				
		$total_count = empty($filename)?$archive_count:$ruleset_count;	
				
	}
	
	function getRulesets($filename = null, $limit=0, $limitstart=0, &$total_count) {					
	
		if (empty($this->rulesets)) {			
			$this->loadRulesets($filename,$limit,$limitstart,$total_count);
		}													

		if (empty($this->rulesets)) {
			return null;
		} else if (empty($filename)) {
			return $this->rulesets;	
		} else {					
			foreach ($this->rulesets as $archive_name => $ruleset_archive) {
				if ($ruleset_archive['filename'] == $filename) {
					return $ruleset_archive;
				}
			}
		}				
		
		return null;
	}
	
	function getAllRulesetArchiveFilenames($exclude_archive_filenames = array()) {
		$archive_filenames = array();
		$rulesets = $this->getRulesets(null,0,0,$total_count);			
		
		$found = false;				
		if (!empty($rulesets)) {			
			foreach ($this->rulesets as $archive_name => $ruleset_archive) {							
				if (!in_array($archive_name, $exclude_archive_filenames))
				$archive_filenames[] = $ruleset_archive['filename'];
			}					
		}		
		
		return $archive_filenames;
	}		
	
	function getAllRulesetArchiveNames($exclude_archive_names = array()) {
		$archive_names = array();
		$rulesets = $this->getRulesets(null,0,0,$total_count);			
		
		$found = false;				
		if (!empty($rulesets)) {			
			foreach ($this->rulesets as $archive_name => $ruleset_archive) {				
				if (!in_array($ruleset_archive['name'], $exclude_archive_names))
				$archive_names[] = $ruleset_archive['name'];
			}					
		}		
		
		return $archive_names;
	}	
	
	function getAllRulesetArchiveTitles($exclude_archive_titles = array()) {
		$archive_titles = array();
		$rulesets = $this->getRulesets(null,0,0,$total_count);			
		
		$found = false;				
		if (!empty($rulesets)) {			
			foreach ($this->rulesets as $archive_name => $ruleset_archive) {				
				if (!in_array($ruleset_archive['title'], $exclude_archive_titles))
				$archive_titles[] = htmlspecialchars($ruleset_archive['title'],ENT_COMPAT,'UTF-8');
			}					
		}		
		
		return $archive_titles;
	}		
	
	function getAllRulesetNames($exclude_ruleset_names = array(), $filename = null) {
		$ruleset_names = array();
		$rulesets = $this->getRulesets($filename,0,0,$total_count);			
		
		$found = false;				
		if (!empty($rulesets)) {			
			foreach ($this->rulesets as $archive_name => $ruleset_archive) {
				if (!empty($filename) && ($ruleset_archive['filename'] != $filename)) continue;								
				foreach ($ruleset_archive['rulesets'] as $ruleset_name => $ruleset) {
					if (!in_array($ruleset_name, $exclude_ruleset_names))
						$ruleset_names[] = $ruleset_name;
				}				
			}					
		}		
		
		return $ruleset_names;
	}
	
	function getRecommendedName($seed = null, $filename = null) {
		$max_id = 1024;
        if (empty($seed)) $seed = 'ruleset_';
		$all_ruleset_names = $this->getAllRulesetNames();
		for ($i=1;$i<$max_id;$i++) {
			$recommended_ruleset_name = $seed.$i;
			if (!in_array($recommended_ruleset_name, $all_ruleset_names)) {
				return $recommended_ruleset_name;
			}
		}		
		return '';
	}
	
	function getAllRulesetTitles($exclude_ruleset_titles = array(), $filename = null) {
		$ruleset_names = array();
		$rulesets = $this->getRulesets($filename,0,0,$total_count);			
		
		$found = false;				
		if (!empty($rulesets)) {			
			foreach ($this->rulesets as $archive_name => $ruleset_archive) {
				if (!empty($filename) && ($ruleset_archive['filename'] != $filename)) continue;								
				foreach ($ruleset_archive['rulesets'] as $ruleset_name => $ruleset) {
					if (!in_array($ruleset['title'], $exclude_ruleset_titles))
						$ruleset_titles[] = htmlspecialchars($ruleset['title'],ENT_COMPAT,'UTF-8');
				}				
			}					
		}		
		
		return $ruleset_titles;
	}
	
	function getRulesetConflicts() {
		if (empty($this->rulesets)) {
			$this->loadRulesets(null,0,0,$total_count);
		}				
		
		return $this->conflicts;	
	}		
	
	function _saveRulesetArchive($ruleset_archive) {
		$dir = TabulizerPath::getDirPath('rules');
		$filename = $dir . $ruleset_archive['filename'];			
		
		// make values safe to store in XML file
		$this->encodeXMLSafe($ruleset_archive, false);
		
		$meta = '';		
		$archive_meta = $ruleset_archive['meta'];
		if (isset($archive_meta['version'])) $meta .= ' version="'.$archive_meta['version'].'"';
		if (isset($archive_meta['compatibility'])) $meta .= ' compatibility="'.$archive_meta['compatibility'].'"';
		if (!empty($archive_meta['generator'])) $meta .= ' generator="'.$archive_meta['generator'].'"';
		if (!empty($archive_meta['last_modified'])) $meta .= ' last_modified="'.$archive_meta['last_modified'].'"';
		if (!empty($archive_meta['author_name'])) $meta .= ' author_name="'.$archive_meta['author_name'].'"';
		if (!empty($archive_meta['author_email'])) $meta .= ' author_email="'.$archive_meta['author_email'].'"';
		if (!empty($archive_meta['author_url'])) $meta .= ' author_url="'.$archive_meta['author_url'].'"';
		if (!empty($meta)) $meta = '	<meta '.$meta.'/>';

        $archive_description = empty($ruleset_archive['description'])?'':' description="'.$ruleset_archive['description'].'" ';
        $archive_style = empty($ruleset_archive['style'])?'':' style="'.$ruleset_archive['style'].'" ';
		
		$contents = '<?xml version="1.0" encoding="utf-8"?>
<rules name="'.$ruleset_archive['name'].'" title="'.$ruleset_archive['title'].'"'.$archive_description.$archive_style.'>' . "\n";
		if (!empty($meta)) $contents .= $meta."\n";

		$rulesets = &$ruleset_archive['rulesets'];
		foreach ($rulesets as $ruleset) {										
			// make values safe to store in XML file
			$this->encodeXMLSafe($ruleset, false);
			
			$extra_ruleset_attr = '';
		
			// style/CSS
			if (!empty($ruleset['style'])) $extra_ruleset_attr .= ' style="'.$ruleset['style'].'"';
            //  preselected
			if (!empty($ruleset['preselected'])) $extra_ruleset_attr .= ' preselected="1"';
			// sample data
			if (!empty($ruleset['sample_data'])) { 
				# important note: XML file has problems storing multiline
				$sample_data_attr = '';
				if (!empty($ruleset['sample_data_caption'])) $sample_data_attr .= ' caption="'.$ruleset['sample_data_caption'].'"';
				if (!empty($ruleset['sample_data_sep'])) $sample_data_attr .= ' sep="'.$ruleset['sample_data_sep'].'"';
				if (!empty($ruleset['sample_data_enc'])) $sample_data_attr .= ' enc="'.$ruleset['sample_data_enc'].'"';
				$sample_data = '  <sample_data '.$sample_data_attr.'>'.$ruleset['sample_data_text'].'</sample_data>' . "\n"; 
			} else { 
				$sample_data = ''; 
			}									
			
			$ruleset_block = '<ruleset name="'.$ruleset['name'].'" title="'.$ruleset['title'].'" description="'.$ruleset['description'].'" suffix="'.$ruleset['suffix'].'" '.$extra_ruleset_attr.' >' . "\n";
			if (!empty($sample_data)) $ruleset_block .= $sample_data;
			$rules = &$ruleset['rules'];														

            if (!empty($rules)) {
                foreach ($rules as $rule) {
                    if ($this->sanitizeRule($rule)) {
                        // make values safe to store in XML file
                        $this->encodeXMLSafe($rule, true);
                        $rule_attribues = '';
                        foreach ($rule as $key => $value) {
                            $rule_attribues .= $key . '="'.$value.'" ';
                        }
                        $ruleset_block .= '  <rule '.$rule_attribues.'></rule>' . "\n";
                    }
                }
            }
			$ruleset_block .= '</ruleset>' . "\n";
			$contents .= $ruleset_block;
		}				

		$contents .= '</rules>';							
		
		if (file_exists($filename)) {
			// show warning?
		}				
		
		$bytes_written = file_put_contents($filename, $contents);		
		if (!$bytes_written) {
			$msg = sprintf(JText::_('COM_TABULIZER_WRONG_RULESET_FILE_PERMISSIONS'),$filename);
            JFactory::getApplication()->enqueueMessage( $msg, 'warning' );
		}
		
		return $bytes_written;
	}
	
	function saveRulesetArchive($new_ruleset_archive) {			
	
		$filename = $new_ruleset_archive['filename'];
			
		if (empty($this->rulesets)) {
			$this->loadRulesets($filename,0,0,$total_count);						
		}					
		
		# copy rulesets from the orifginal archive, if any
		$new_ruleset_archive['rulesets'] = array();		
		if ($total_count) {
			foreach ($this->rulesets as $archive_name => $ruleset_archive) {
				if ($ruleset_archive['filename'] != $filename) continue;																	
				if (!empty($ruleset_archive['rulesets'])) $new_ruleset_archive['rulesets'] = $ruleset_archive['rulesets'];							
			}		
		}				
	
		return $this->_saveRulesetArchive($new_ruleset_archive);	
	}
	
	function _deleteRulesetArchive($filenames) {
		$dir = TabulizerPath::getDirPath('rules');
	
		if (empty($filenames)) return false;
		foreach ($filenames as $filename) {
			$filename = $dir . $filename;					
			if (file_exists($filename)) {
				if (!unlink($filename)) return false;
			} else return false;
		}
		
		return true;
	}
	
	function deleteRulesetArchive($filenames) {
		return $this->_deleteRulesetArchive($filenames);			
	}
	
	/**
	Ruleset
	*/
	
	function getRuleset($ruleset_name, $filename = null) {		
		
		if (empty($this->rulesets)) {
			$this->loadRulesets($filename, 0, 0, $total_count);
		}
		
		if (empty($this->rulesets)) {
			return null;
		} else {									
			foreach ($this->rulesets as $archive_name => $ruleset_archive) {
				if (!empty($filename) && ($ruleset_archive['filename'] != $filename)) continue;								
				foreach ($ruleset_archive['rulesets'] as $ruleset) {
					if ($ruleset['name'] == $ruleset_name) {
						$ruleset['filename'] = $ruleset_archive['filename'];
						return $ruleset;
					}				
				}		
			}
		}
		
		return null;
	}
	
	function _saveRuleset($new_ruleset) {									
	
		if (empty($this->rulesets)) {
			$this->loadRulesets($new_ruleset['filename'],0,0,$total_count);
		}

        if (isset($new_ruleset['source_name'])) $ruleset_name = $new_ruleset['source_name'];
        else $ruleset_name = $new_ruleset['name'];
		
		if (isset($this->rulesets)) {
			$found = false;
			foreach ($this->rulesets as $archive_name => $ruleset_archive) {
				if (!empty($new_ruleset['filename']) && ($ruleset_archive['filename'] != $new_ruleset['filename'])) continue;																	
				foreach ($ruleset_archive['rulesets'] as &$ruleset) {
					if ($ruleset['name'] == $ruleset_name) {
						$ruleset['name'] = (isset($new_ruleset['name']))?$new_ruleset['name']:'';
						$ruleset['title'] = (isset($new_ruleset['title']))?$new_ruleset['title']:'';
						$ruleset['description'] = (isset($new_ruleset['description']))?$new_ruleset['description']:'';
						$ruleset['style'] = (isset($new_ruleset['style']))?$new_ruleset['style']:'';
						$ruleset['suffix'] = (isset($new_ruleset['suffix']))?$new_ruleset['suffix']:'';
						$ruleset['preselected'] = (isset($new_ruleset['preselected']))?$new_ruleset['preselected']:null;																				
						if (!empty($new_ruleset['sample_data'])) {
							$ruleset['sample_data'] = 1;
							$ruleset['sample_data_caption'] = $new_ruleset['sample_data_caption'];
							$ruleset['sample_data_text'] = $new_ruleset['sample_data_text'];												
							$ruleset['sample_data_sep'] = $new_ruleset['sample_data_sep'];
							$ruleset['sample_data_enc'] = empty($new_ruleset['sample_data_enc'])?'':$new_ruleset['sample_data_enc'];
						} else {
							$ruleset['sample_data'] = null;
						}
						if (isset($new_ruleset['rules'])) $ruleset['rules'] = $new_ruleset['rules'];							
																																						
						return $this->_saveRulesetArchive($ruleset_archive);			
					}				
				}
				// add new ruleset
				$ruleset_archive['rulesets'][] = $new_ruleset;
				return $this->_saveRulesetArchive($ruleset_archive);					
			}			
		}		
		
		return false;		
	}
	
	function saveRuleset($ruleset) {
		return $this->_saveRuleset($ruleset);		
	}	
	
	function _deleteRuleset($ruleset_names, $filename) {
		$rulesets = $this->getRulesets($filename,0,0,$total_count);	
		
		$found = false;				
		if (!empty($rulesets)) {			
			foreach ($this->rulesets as $archive_name => $ruleset_archive) {
				if (!empty($filename) && ($ruleset_archive['filename'] != $filename)) continue;								
				foreach ($ruleset_archive['rulesets'] as $ruleset_name => $ruleset) {
					if (in_array($ruleset['name'],$ruleset_names)) {											
						unset($ruleset_archive['rulesets'][$ruleset_name]);		
						$found = true;
					}				
				}
				if ($found) return $this->_saveRulesetArchive($ruleset_archive);
			}					
		}		
				
		return false;			
	}
	
	function deleteRuleset($ruleset_names, $ruleset_file) {			
		return $this->_deleteRuleset($ruleset_names, $ruleset_file);
	}
	
	/**
	Rule
	*/
	
	function getRule($rule_id, $ruleset_name, $filename = null) {
		$ruleset = $this->getRuleset($ruleset_name, $filename);				
		
		if (!empty($ruleset)) {
			foreach ($ruleset['rules'] as $id => $rule) {
				if ($id == $rule_id) {
					return $rule;
				}
			}
		}
				
		return null;
	}
	
	function _saveRule($new_rule, $rule_id, $ruleset_name, $filename = null) {						
		$ruleset = $this->getRuleset($ruleset_name, $filename);														
		if (!empty($ruleset)) {
			if ($rule_id >= count($ruleset['rules'])) {
				$ruleset['rules'][] = $new_rule;																
				return $this->_saveRuleset($ruleset);
			} else {
				foreach ($ruleset['rules'] as $id => $rule) {
					if ($id == $rule_id) {
						$ruleset['rules'][$id] = $new_rule;															
						return $this->_saveRuleset($ruleset);
					}
				}
			}
		}
				
		return false;
	}
	
	function saveRule($rule, $rule_id, $ruleset_name, $filename = null) {					
		return $this->_saveRule($rule, $rule_id, $ruleset_name, $filename);	
	}
	
	function _deleteRule($rule_ids, $ruleset_name, $filename) {
		$ruleset = $this->getRuleset($ruleset_name, $filename);		
						
		rsort($rule_ids, SORT_NUMERIC);
		
		$found = false;				
		if (!empty($ruleset)) {			
			foreach ($rule_ids as $rule_id) {
				if (isset($ruleset['rules'][$rule_id])) {
					unset($ruleset['rules'][$rule_id]);					
					$found = true;
				}
			}
		}		
		
		if ($found) {
			return $this->_saveRuleset($ruleset);
		} else return false;	
				
	}
	
	function deleteRule($rule_ids, $ruleset_name, $filename = null) {
		return $this->_deleteRule($rule_ids, $ruleset_name, $filename);	
	}
	
	/**
	General
	*/
	
	function sanitizeRule(&$rule) {
		# remove empty/null attributes
		$rule_attributes = array('element' =>1, 'element_section' =>0, 'range'=>1, 'range_key'=>0, 'priority'=>0, 'style'=>0, 'attribute'=>0, 'autospan'=>0, 'th_tag'=>0, 'remove'=>0, 'format'=>0, 'replacement'=>0, 'calculation'=>0, 'modification'=>0, 'prepend'=>0, 'append'=>0, 'add_files'=>0, 'split'=>0, 'filter'=>0, 'column_filter'=>0, 'sort'=>0, 'pagination'=>0, 'scroll'=>0, 'theme'=>0, 'responsive'=>0, 'graph'=>0, 'export_table'=>0);
		foreach ($rule_attributes as $key=>$required) {
            if (empty($rule[$key])) unset($rule[$key]); break;
		}	
		return true;											
	}
	
	function encodeXMLSafe(&$values, $recursive = false) {	
		if (is_array($values)) {
			foreach ($values as $key=> &$value) { 
				if (!empty($value)) {
					if (is_array($value)) {
						if ($recursive) {
							$this->encodeXMLSafe($value);
						}
					} else {
						$value = htmlspecialchars($value,ENT_QUOTES,'UTF-8'); 
					}
				}	
			}
		} else {
			if (!empty($values)) {
				$values = htmlspecialchars($values,ENT_QUOTES,'UTF-8'); 
			}
		}			
	}		
	
	function decodeXMLSafe(&$values) {			
		if (is_array($values)) {
			foreach ($values as $key=> &$value) { 
				if (!empty($value)) {
					if (is_array($value)) {
						$this->decodeXMLSafe($value);
					} else {
						$value = htmlspecialchars_decode($value,ENT_QUOTES); 
					}
				}	
			}
		} else {
			if (!empty($values)) {
				$values = htmlspecialchars_decode($values,ENT_QUOTES); 
			}
		}					
	}
	
	function getErrors() {
		return $this->errors;
	}
	
}

?>