1<?php
2/*
3** Zabbix
4** Copyright (C) 2001-2021 Zabbix SIA
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19**/
20
21
22/**
23 * A class for rendering HTML trees.
24 */
25class CTree {
26
27	protected $tree;
28	private $fields;
29	private $treename;
30	private $size;
31	private $maxlevel;
32
33	public function __construct($treename, $value = [], $fields = []) {
34		$this->maxlevel = 0;
35		$this->tree = $value;
36		$this->fields = $fields;
37		$this->treename = $treename;
38		$this->size = count($value);
39
40		if (!$this->checkTree()) {
41			$this->destroy();
42			return false;
43		}
44		else {
45			$this->countDepth();
46		}
47	}
48
49	public function getTree() {
50		return $this->tree;
51	}
52
53	public function getHTML() {
54		$html[] = $this->createJS();
55		$html[] = $this->simpleHTML();
56		return $html;
57	}
58
59	private function makeHeaders() {
60		$headers = array_values($this->fields);
61
62		$keys = array_keys($this->fields);
63		array_shift($keys);
64		$this->fields = $keys;
65
66		return $headers;
67	}
68
69	private function simpleHTML() {
70		$table = (new CTableInfo())
71			->setHeader($this->makeHeaders());
72
73		foreach ($this->tree as $id => $rows) {
74			$table->addRow($this->makeRow($id));
75		}
76		return $table;
77	}
78
79	private function makeRow($id) {
80		$tr = (new CRow())->setId('id_'.$id);
81		if ($this->tree[$id]['parentid'] != 0) {
82			$tr->setAttribute('style', 'display: none;');
83		}
84
85		$tr->addItem($this->makeCell($id));
86		foreach ($this->fields as $value) {
87			$tr->addItem($this->makeCol($id, $value));
88		}
89		return $tr;
90	}
91
92	/**
93	 * Returns a column object for the given row and field.
94	 *
95	 * @param $rowId
96	 * @param $colName
97	 *
98	 * @return CCol
99	 */
100	protected function makeCol($rowId, $colName) {
101		return new CCol($this->tree[$rowId][$colName]);
102	}
103
104	private function makeCell($id) {
105		$td = new CCol();
106
107		$caption = new CSpan();
108
109		if ($id != 0 && array_key_exists('childnodes', $this->tree[$id])) {
110			$caption->addItem((new CSimpleButton((new CSpan())->addClass('arrow-right')))
111				->addClass(ZBX_STYLE_TREEVIEW)
112				->onClick($this->treename.'.closeSNodeX("'.$id.'", this.getElementsByTagName(\'span\')[0]);')
113				->setId('idi_'.$id)
114			);
115		}
116		$caption->addItem($this->tree[$id]['caption']);
117
118		if ($this->tree[$id]['Level'] != 0) {
119			$level = $this->tree[$id]['Level'];
120			$caption->setAttribute('style', 'padding-left:'.(2 * $level).'em;');
121		}
122		$td->addItem($caption);
123
124		return $td;
125	}
126
127	private function countDepth() {
128		foreach ($this->tree as $id => $rows) {
129			if ($rows['id'] == 0) {
130				$this->tree[$id]['Level'] = 0;
131				continue;
132			}
133			$parentid = $this->tree[$id]['parentid'];
134
135			$this->tree[$parentid]['nodetype'] = 2;
136			$this->tree[$id]['Level'] = isset($this->tree[$parentid]['Level']) ? $this->tree[$parentid]['Level'] + 1 : 1;
137
138			if ($this->maxlevel < $this->tree[$id]['Level']) {
139				$this->maxlevel = $this->tree[$id]['Level'];
140			}
141		}
142	}
143
144	public function createJS() {
145		$js = '<script src="js/class.ctree.js" type="text/javascript"></script>'."\n".
146				'<script type="text/javascript"> var '.$this->treename.'_tree = {};';
147
148		foreach ($this->tree as $id => $rows) {
149			$parentid = $rows['parentid'];
150			$this->tree[$parentid]['nodelist'] .= $id.',';
151		}
152
153		foreach ($this->tree as $id => $rows) {
154			if ($rows['nodetype'] == '2') {
155				$rows['nodelist'] = rtrim($rows['nodelist'], ',');
156				$js .= $this->treename.'_tree[\''.$id.'\'] = { status: \'close\', nodelist : \''.$rows['nodelist'].'\', parentid : \''.$rows['parentid'].'\'};';
157				$js .= "\n";
158			}
159		}
160
161		$js.= 'var '.$this->treename.' = null';
162		$js.= '</script>'."\n";
163
164		zbx_add_post_js($this->treename.' = new CTree("tree_'.CWebUser::$data['alias'].'_'.$this->treename.'", '.$this->treename.'_tree);');
165
166		return new CJsScript($js);
167	}
168
169	private function checkTree() {
170		if (!is_array($this->tree)) {
171			return false;
172		}
173		foreach ($this->tree as $id => $cell) {
174			$this->tree[$id]['nodetype'] = 0;
175
176			$parentid = $cell['parentid'];
177			$this->tree[$parentid]['childnodes'][] = $id;
178			$this->tree[$id]['nodelist'] = '';
179		}
180		return true;
181	}
182
183	private function destroy() {
184		unset($this->tree);
185	}
186}
187