1<?php
2
3
4if (!class_exists('settingslevel',false)){
5require_once('settingswrapper.class.php');
6
7
8class settingslevel{
9	public $path = null;				// absolute path
10	protected $_parent = null;			// the parent or null if it's the root
11	protected $_hierarchy = null;			// the settingshierarchy containing this level.
12	private $_children = array();		// children levels
13	private $_settings = null;			// the array of settingswrapper (by key) to this level has.
14	private $_values = null;			// values (array: key=>[prot,value]) for the level.
15
16	function __construct(settingshierarchy $hierarchy, settingslevel $parent = null, $path){
17		$this->_parent = $parent;
18		$this->_hierarchy = $hierarchy;
19		$this->path = ':'.ltrim($path,':');
20	}
21
22	function getLevelNameRelative(){
23		if ($this->path == ':'){
24			global $lang;
25			return '['.$lang['mediaroot'].']';
26		}
27		if (!$this->_parent){
28			return $this->path;
29		}
30		$val = substr($this->path,strlen($this->_parent->path));
31		if ($val[0] == ':') $val = substr($val,1);
32		return $val;
33	}
34	function getHierarchy(){
35		return $this->_hierarchy;
36	}
37	function getCurrent($key){
38		/*	1, if there is protected value then that (here)
39			2, if there is value for level then that (in getCurrentNoProt)
40			3, parent's current value (in getCurrentNoProt) */
41		if (($v = $this->getProtected($key)) !== null) {return $v;}
42		return $this->getCurrentNoProt($key);
43
44	}
45	private function getCurrentNoProt($key){
46		// getCurrentNoProt: getProtected() may return getCurrent() value, but getCurrent() value checks getProtected()... we need a getCurrent() without calling getProtected()
47		/*	1, if there is protected value then that (in getCurrent)
48			2, if there is value for level then that (here)
49			3, parent's current value (here) */
50		if (($v = @$this->_values[$key]['value']) !== null){ return $v;	}
51		if ($this->_parent) { return $this->_parent->getCurrent($key);	}
52		/*		root's current:
53			1, if there is protected, then that (done)
54			2, if root has value then that (done)
55			3, if config's local then that
56			4, config's default
57		*/
58		if (($v = $this->_hierarchy->getLocal($key)) !== null) {return $v;}
59		return $this->_hierarchy->getDefault($key);
60	}
61
62	function getDefault($key){
63		/*	1, if there is a protected value then that
64			2, parents's current value */
65		if (($v = $this->getProtected($key)) !== null) {return $v;}
66		if ($this->_parent){		return $this->_parent->getCurrent($key);	}
67		/* root's default:
68			1, if config's protected then that (done)
69			2, if config's local then that
70			3, config's default */
71		if (($v = $this->_hierarchy->getLocal($key)) !== null) {return $v;}
72		return $this->_hierarchy->getDefault($key);
73	}
74
75
76	function getLocal($key){
77		/*	1, if there is a protected value then null
78			2, if the level has value then that
79			3, null */
80		if (($v = $this->getProtected($key)) !== null) {return null;}
81		if (($v = @$this->_values[$key]['value']) !== null){ return $v;	}
82		return null;
83	}
84
85	function getProtected($key){
86		/*	1, if there is a protected value from parent then that
87			2, if there is a protection on this level then the current value
88			3, null */
89		if (($v = $this->getParentProtected($key)) !== null)  {return $v;}
90		if (@$this->_values[$key]['protect']){ return $this->getCurrentNoProt($key); }
91		return null;
92	}
93	function getParentProtected($key){
94		if ($this->_parent){	// check parent level.
95			return $this->_parent->getProtected($key);
96		}
97		return $this->_hierarchy->getProtected($key);
98	}
99
100
101	function isLevelValue($key){
102		return isset($this->_values[$key]['value']);
103	}
104	function getLevelValue($key){
105		return @$this->_values[$key]['value'];
106	}
107	function isLevelValueIgnored($key){
108		return (isset($this->_values[$key]['value']) && ($this->getParentProtected($key) !== null));
109	}
110	function isLevelProtected($key){
111		return isset($this->_values[$key]['protect']);
112	}
113
114	function setValues(array $values){	// setValues should always be called before getSettings. If not, just ignore.
115		if ($this->_settings === null)
116			$this->_values = $values;
117	}
118	function getValues(){
119		return $this->_values;
120	}
121
122	function getValuesRecursive(){
123		$ret = array();
124		$v = $this->getValues();
125		if (!empty($v)){
126			$ret[$this->path] = $v;
127		}
128		foreach($this->_children as $child){
129			$ret = array_merge($ret,$child->getValuesRecursive());
130		}
131		return $ret;
132	}
133	function getAllValues(){
134		$ret = array();
135		foreach ($this->_hierarchy->getFieldConfig() as $key=>$meta){
136			$ret[$key] = $this->getCurrent($key);
137		}
138		return $ret;
139	}
140
141
142	function getParent(){
143		return $this->_parent;
144	}
145
146	protected function _getSettings(){
147		if (!$this->_settings){
148			foreach ($this->_hierarchy->getFieldConfig() as $key=>$meta){
149				$this->_settings[$key] = new settingswrapper($key,$this,$meta,$this->_values[$key]);
150			}
151		}
152		return $this->_settings;
153	}
154	function checkValues($data){
155		$set = $this->_getSettings();
156		$check_success = true;
157		foreach ($data as $key=>$new){
158			if (isset($new['config'])){
159				if (!$set[$key]->tryUpdate($new['config'])){	// returns false on error
160					$check_success = false;
161				}else{
162					$par_val = $this->getDefault($key);
163					if ($set[$key]->_value !== null && $par_val !== $set[$key]->_value){
164						$this->_values[$key]['value'] = $set[$key]->_value;	// we do need to save value, as it's not default. (default == parent's value)
165					}else{
166						unset($this->_values[$key]['value']);				// we do need to delete the value, as it's default.
167					}
168				}
169			}
170			if (isset($new['protect'])){
171				if ($new['protect'] === 'false') $new['protect'] = false;
172				if ($new['protect'] === 'true') $new['protect'] = true;
173				$par_val = $this->getParentProtected($key);
174				$toset = $par_val ? null : $new['protect'];
175				$set[$key]->setProtect($toset);
176				if ($toset)	$this->_values[$key]['protect'] = true;	// we only save if a level is protected.
177				else unset($this->_values[$key]['protect']);
178			}
179			if (empty($this->_values[$key]))
180				unset($this->_values[$key]);
181		}
182		if (!$check_success){
183			$this->_markChanged(array_keys($data));
184		}
185		return $check_success;
186	}
187	protected function _markChanged($keys){
188		$set = $this->_getSettings();
189		foreach ($keys as $key){
190			$set[$key]->markChanged($key);
191		}
192	}
193
194	protected function _getTitle(){
195		return sprintf(settingshierarchy::$helper->getLang('settings_for_%s'),$this->path);
196	}
197	protected function _getButtons(){
198		return
199			"<button id='settingstree_save_button' onclick=\"jQuery(this).trigger('settingstree_save'); return false;\">".settingshierarchy::$helper->getLang('save')."</button>
200			<button id='settingstree_cancel_button'  onclick=\"jQuery(this).trigger('settingstree_cancel'); return false;\">".settingshierarchy::$helper->getLang('cancel')."</button>";
201
202	}
203
204	function showHtml(){
205
206		// DECIDE: non-ajax compatibility: plain posts and js states in hidden fields?
207//		$ret .= "<input type='hidden' name='settingstree_path' value='{$this->path}' /><input type='hidden' name='settingstree_pluginname' value='{$this->_hierarchy->getPluginName()}' />";
208		$ret .= "<div class='settingstree_error_area'></div>";
209		$ret .= "<div id='config__manager' data-path='{$this->path}'><fieldset><legend>{$this->_getTitle()}</legend><div class='table'><table class='inline'><tbody>";
210		foreach ($this->_getSettings() as $key => $setting){
211			$ret .= $setting->showHtml();
212		}
213		$ret .= "</tbody></table></div></fieldset></div>";
214		$ret .= "<div class='settingstree_error_area'></div>";
215		$ret .= "<div class='settingstree_buttons'>{$this->_getButtons()}</div>";
216		return $ret;
217	}
218	function getExport($options){
219		$level = new settingslevel_export($this->_hierarchy,$this,$this->path);
220		$level->setOptions($options);
221		return $level;
222	}
223
224	function getPath(){
225		return $this->path;
226	}
227	function isRoot(){
228		return !$this->_parent;
229	}
230
231	function getLevel(array $path){
232		if (empty($path)){
233			return $this;
234		}
235		$child = array_shift($path);
236		if ($child == ''){
237			global $conf;
238			$child = $conf['start'];
239		}
240		if (!($c = @$this->_children[$child])){
241			$this->_children[$child] = new static($this->_hierarchy,$this,$this->path.':'.$child);
242			$c = $this->_children[$child];
243		}
244		return $c->getLevel($path);
245	}
246
247	function addLevel($path,$values){
248		if (!is_array($path)){
249			$path = explode(':',ltrim($path,':'));	// explode path if not already exploded.
250		}
251		if (empty($path)){
252			$this->setValues($values);
253			return;
254		}
255		$child = array_shift($path);
256		if ($child == '') {
257			global $conf;
258			$child = $conf['start'];
259		}
260		if (!($c = @$this->_children[$child])){
261			$this->_children[$child] = new static($this->_hierarchy,$this,$this->path.':'.$child);
262			$c = $this->_children[$child];
263		}
264		$c->addLevel($path,$values);
265	}
266
267	function getChildren(){
268		return $this->_children;
269	}
270}
271
272class settingslevel_export extends settingslevel{
273	private $_title = null;
274	function setOptions($options){
275		$this->_title = @$options['title'];
276	}
277
278	protected function _getTitle(){
279		return $this->_title !== null ? $this->_title : settingshierarchy::$helper->getLang('export_options');;
280	}
281	protected function _getButtons(){
282		return
283			"<button id='settingstree_export_button' onclick=\"jQuery(this).trigger('settingstree_export'); return false;\">".settingshierarchy::$helper->getLang('export')."</button>
284			<button id='settingstree_close_button'  onclick=\"jQuery(this).trigger('settingstree_close'); return false;\">".settingshierarchy::$helper->getLang('cancel')."</button>";
285	}
286	function getAllValues(){
287		$ret = array();
288		foreach ($this->_hierarchy->getFieldConfig() as $key=>$meta){
289			if ($meta['_ignore_for_export']) continue;
290			$ret[$key] = $this->getCurrent($key);
291		}
292		return $ret;
293	}
294
295
296	protected function _getSettings(){
297		if (!$this->_settings){
298			foreach ($this->_hierarchy->getFieldConfig() as $key=>$meta){
299				if ($meta['_ignore_for_export']) continue;
300				$this->_settings[$key] = new settingswrapper_export($key,$this,$meta,$this->_values[$key]);
301			}
302		}
303		return $this->_settings;
304	}
305
306}
307
308} // class_exists