<?php

/**
 * $_SESSION['TableAcl_cache'][$tableID] = array(
 *   [db] => DB zasob ID
 *   [name] => Table name
 *   [opis] => Table opis
 *   [fields] => array(
 *     [$fieldID] => array(
 *       [name] => name
 *       [perms] => perms (FORM_TREAT)
 *       [opis] => opis
 *     )
 *   )
 *   [types] => array(
 *     [$fieldID] => array(
 *       [type] => type
 *       [null] => bool
 *       [default] => default value
 *     )
 *   )
 * );
 */
class TableAcl {

	private $_zasobID = '';
	private $_db = '';
	private $_name = '';
	private $_label = '';
	private $_opis = '';
	private $_fields = array();
	private $_types = array();
	private $_virtualFieldsIdList = array();

	public function __construct($zasobID) {
		$this->_zasobID = $zasobID;
	}

	public function getID() {
		return $this->_zasobID;
	}

	public function setName($name) {
		$this->_name = $name;
	}

	public function getName() {
		return $this->_name;
	}

	public function setOpis($opis) {
		$this->_opis = $opis;
	}

	public function getOpis() {
		return $this->_opis;
	}

	public function setLabel($label) {
		$this->_label = $label;
	}

	public function getLabel() {
		return $this->_label;
	}

	public function getRawLabel($posLimit = 20) {
		$label = $this->_label;
		if (empty($label) && !empty($this->_opis)) {
			$label = $this->_opis;
			if (mb_strlen($this->_opis) > $posLimit) {
				$pos = strpos($this->_opis, ' - ');
				if ($pos > $posLimit || $pos < 5) {
					$pos = $posLimit;
					$label = mb_substr($this->_opis, 0, $posLimit, 'utf-8') . '...';
				} else {
					$label = mb_substr($this->_opis, 0, $pos, 'utf-8');
				}
			}
		}
		if (empty($label)) {
			$label = $this->_name;
		}
		return $label;
	}

	public function getShortLabel($posLimit = 20) {
		$shortLabel = $this->getRawLabel($posLimit);
		$opis = $this->_opis;
		$shortLabel = '<span title="' . htmlspecialchars($opis) . '">' . $shortLabel . '</span>';
		return $shortLabel;
	}

	public function getLongLabel($posLimit = 30) {
		$longLabel = $this->getRawLabel($posLimit);
		$opis = $this->_opis;
		if ($longLabel != $this->_name) {
			$longLabel .= ' <em>' . $this->_name . '</em>';
		}

		$longLabel = '<span title="' . htmlspecialchars($opis) . '">' . $longLabel . '</span>';
		return $longLabel;
	}

	public function setDB($db) {
		$this->_db = $db;
	}

	public function getDB() {
		return $this->_db;
	}

	public function addField($fieldID, $name, $opis, $sort_prio, $label = '') {
		$field = array();
		$field['name'] = $name;
		$field['perms'] = '';
		$field['opis'] = $opis;
		$field['sort_prio'] = $sort_prio;
		$field['label'] = $label;
		$this->_fields[$fieldID] = $field;
	}

	public function getField($fieldID) {
		return $this->_fields[$fieldID];
	}

	public function hasField($fieldID) {
		return array_key_exists($fieldID, $this->_fields);
	}

	public function removeField($fieldID) {
		if (array_key_exists($fieldID, $this->_fields)) {
			unset($this->_fields[$fieldID]);
		}
	}

	public function getFields() {
		return $this->_fields;
	}

	public function setFieldPerms($fieldID, $perms) {
		if (array_key_exists($fieldID, $this->_fields)) {
			$this->_fields[$fieldID]['perms'] .= $perms;
		}
	}

	public function getFieldPerms($fieldID) {
		if (array_key_exists($fieldID, $this->_fields)) {
			$perms = V::get('perms', '', $this->_fields[$fieldID]);
			if ($perms) {
				return implode(',', array_unique(str_split($perms)));
			}
		}
		return '';
	}

	public function hasFieldPerm($fieldID, $perm) {
		if (array_key_exists($fieldID, $this->_fields)) {
			if (false !== strpos($this->_fields[$fieldID]['perms'], $perm)) {
				return true;
			}
			return false;
		}
		return false;
	}

	public function getFieldIdByName($fieldName) {
		$fieldID = 0;
		if (empty($fieldName)) {
			return;
		}
		foreach ($this->_fields as $kID => $vField) {
			if ($vField['name'] == $fieldName) {
				$fieldID = $kID;
			}
		}
		return $fieldID;
	}

	public function hasSuperAccessPerms() {
		foreach ($this->_fields as $kFldID => $vFld) {
			if ($this->hasFieldPerm($kFldID, 'S')) {
				return true;
			}
			else if ($this->hasFieldPerm($kFldID, 'V')) {
				return true;
			}
		}
		return false;
	}

	public function hasPermSuperWrite() {
		foreach ($this->_fields as $kFldID => $vFld) {
			if ($this->hasFieldPerm($kFldID, 'S')) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 
	 */
	public function canWriteRecord($record) {

		$dbgArr = array();
		$dbgArr['record_owner'] = (isset($record->L_APPOITMENT_USER))? $record->L_APPOITMENT_USER : '';
		$dbgArr['record_write'] = (isset($record->A_ADM_COMPANY))? $record->A_ADM_COMPANY : '';
		$dbgArr['record_read'] = (isset($record->A_CLASSIFIED))? $record->A_CLASSIFIED : '';
		$dbgArr['user_groups'] = User::getLdapGroupsNames();
		if(V::get('DBG_ACL', '', $_REQUEST) > 2){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">dbgArr (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($dbgArr);echo'</pre>';}

		if ($dbgArr['record_owner'] && $dbgArr['record_owner'] == User::getLogin()) {
			if(V::get('DBG_ACL', '', $_REQUEST) > 2){echo '<p>true - is record owner</p>';}
			return true;
		}

		if ($dbgArr['record_write']) {
			if (in_array($dbgArr['record_write'], $dbgArr['user_groups'])) {
				if(V::get('DBG_ACL', '', $_REQUEST) > 2){echo '<p>true - has group write</p>';}
				return true;
			}
		} else {
			if(V::get('DBG_ACL', '', $_REQUEST) > 2){echo '<p>true - group write not set</p>';}
			return true;
		}

		return false;
	}

	public function canReadRecord($record) {
		$dbgArr = array();
		$dbgArr['record_owner'] = (isset($record->L_APPOITMENT_USER))? $record->L_APPOITMENT_USER : '';
		$dbgArr['record_write'] = (isset($record->A_ADM_COMPANY))? $record->A_ADM_COMPANY : '';
		$dbgArr['record_read'] = (isset($record->A_CLASSIFIED))? $record->A_CLASSIFIED : '';
		$dbgArr['user_groups'] = User::getLdapGroupsNames();
		if(V::get('DBG_ACL', '', $_REQUEST) > 2){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">record('.$record->ID.') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($dbgArr);echo'</pre>';}

		if ($dbgArr['record_owner'] && $dbgArr['record_owner'] == User::getLogin()) {
			if(V::get('DBG_ACL', '', $_REQUEST) > 2){echo '<p>true - is record owner</p>';}
			return true;
		}

		if ($dbgArr['record_read']) {
			if (in_array($dbgArr['record_read'], $dbgArr['user_groups'])) {
				if(V::get('DBG_ACL', '', $_REQUEST) > 2){echo '<p>true - has group read</p>';}
				return true;
			}
		} else {
			if(V::get('DBG_ACL', '', $_REQUEST) > 2){echo '<p>true - group read not set</p>';}
			return true;
		}

		return false;
	}

	/**
	 * @param $taskPerm - 'C', 'W', 'R'
	 */
	public function isAllowed($fieldID, $taskPerm, $record = null) {
		if (!in_array($taskPerm, array('C', 'W', 'R'))) {
			return false;
		}
		$adminFields = array();
		$adminFields[] = 'ID';
		$adminFields[] = 'A_RECORD_CREATE_DATE';
		$adminFields[] = 'A_RECORD_CREATE_AUTHOR';
		$adminFields[] = 'A_RECORD_UPDATE_DATE';
		$adminFields[] = 'A_RECORD_UPDATE_AUTHOR';
		$fieldName = $this->_fields[$fieldID]['name'];
		if ($taskPerm == 'R' && in_array($fieldName, $adminFields)) {
			return true;
		}

		// check perm: allow 'RS', 'WS' - can R/W field even if cant read record
		// check 'O' - can read field even if cant read field but can read record
		if(V::get('DBG_ACL', '', $_REQUEST) > 1){ echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;"> (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r(array('Field'=>$fieldID.'('.$fieldName.')'
				,'taskPerm'=>$taskPerm
				,'canReadRecord'=>'"'.$this->canReadRecord($record).'"'
				,'hasFieldPerm(O) || canWriteRecord'=>'"'.$this->hasFieldPerm($fieldID, 'O').'" || "'.$this->canReadRecord($record).'"'
				,'hasFieldPerm(S)'=>'"'.$this->hasFieldPerm($fieldID, 'S').'"'
				,'hasFieldPerm(V)'=>'"'.$this->hasFieldPerm($fieldID, 'V').'"'
			));echo'</pre>'; }
		if (!$this->hasFieldPerm($fieldID, $taskPerm)) {
			if ($taskPerm == 'R' && $this->hasFieldPerm($fieldID, 'V')) {
				return true;
			} else if ($taskPerm == 'R'
				&& $record
				&& $this->hasFieldPerm($fieldID, 'O')
				&& ($this->canReadRecord($record) || $this->canWriteRecord($record))
			) {
				return true;// 'WO' or 'CO'
			}
			return false;
		}

		// check 'R' - require can read record, or V - Super View
		if ($taskPerm == 'R') {
			if ($this->canReadRecord($record) || $this->hasFieldPerm($fieldID, 'V')) {
				return true;
			} else {
				return false;
			}
		}

		// 'C' and 'W' require colType
		$colType = $this->getFieldTypeById($fieldID);
		if (!$colType) {
			return false;
		}
		if ($taskPerm == 'W') {
			if ($record) {
				if(V::get('DBG_ACL', '', $_REQUEST) > 1){echo '(Field: '.$fieldID.', canWriteRecord: ' . $this->canWriteRecord($record) . ' || (hasFieldPerm(S): ' . $this->hasFieldPerm($fieldID, 'S') . ' && hasFieldPerm(W): ' . $this->hasFieldPerm($fieldID, 'W') . '))';}
				return ($this->canWriteRecord($record)|| $this->hasFieldPerm($fieldID, 'S'));
			}
		}
		return true;
	}

	/**
	 * @param $taskPerm - 'C', 'W'
	 */
	public function showFormItem($taskPerm, $fieldID, $fName, $fValue, $params = array(), $record = null) {
		$out = '';
		if (!$this->isAllowed($fieldID, $taskPerm, $record)) {
			if ($taskPerm == 'R') {
				$out .= 'Brak uprawnień do odczytu';
			}
			else if ($taskPerm == 'W') {
				$out .= 'Brak uprawnień do zapisu';
			} else {
				$out .= 'Brak uprawnień do tego pola (' . $taskPerm . ')';
			}
			return $out;
		}

		$colName = $this->_fields[$fieldID]['name'];
		if ($colName == 'ID') {
			return $out;
		}

		$colType = $this->getFieldTypeById($fieldID);
		if (!$colType) {
			$out .= 'Error - unknown type';
			return $out;
		}

		Lib::loadClass('Typespecial');
		$typeSpecial = Typespecial::getInstance($fieldID, $colName);

		$html = new stdClass();
		$html->_params = array();
		$html->tag = 'input';
		$html->cnt = '';
		$html->attrs = array();
		$html->attrs['id'] = $fName;
		$html->attrs['name'] = $fName;
		$html->attrs['type'] = 'text';
		$html->attrs['value'] = htmlspecialchars($fValue);
		if (isset($params['tabindex'])) {
			$html->attrs['tabindex'] = $params['tabindex'];
		}
		if (!$this->hasFieldPerm($fieldID, $taskPerm)) {
			$html->attrs['disabled'] = 'disabled';
		}
		$maxGrid = V::get('maxGrid', 10, $params);

		/* Form input Relative sizing:
<input class="input-mini" type="text" placeholder=".input-mini">
<input class="input-small" type="text" placeholder=".input-small">
<input class="input-medium" type="text" placeholder=".input-medium">
<input class="input-large" type="text" placeholder=".input-large">
<input class="input-xlarge" type="text" placeholder=".input-xlarge">
<input class="input-xxlarge" type="text" placeholder=".input-xxlarge">
		 */
		if (substr($colType['type'], 0, 3) == 'int' 
				|| substr($colType['type'], 0, 7) == 'tinyint'
				|| substr($colType['type'], 0, 8) == 'smallint'
		) {
			//$h->Type_value = (int)str_replace(array(' ','(',')'), '', substr($h->Type, 4));
			$html->attrs['type'] = 'number';
			$html->attrs['class'] []= 'input-small';
		}
		else if (substr($colType['type'], 0, 6) == 'double') {
			$html->attrs['type'] = 'text';
			$html->attrs['class'] []= 'input-small';
		}
		else if (substr($colType['type'], 0, 7) == 'decimal') {
			$html->attrs['type'] = 'text';
			$html->attrs['class'] []= 'input-small';
		}
		else if (substr($colType['type'], 0, 7) == 'varchar'
				|| substr($colType['type'], 0, 4) == 'char'
			) {
			//$h->Type_value = (int)str_replace(array(' ','(',')'), '', substr($h->Type, 8));
			$html->attrs['type'] = 'text';
			$maxLength = (int)str_replace(array(' ','(',')'), '', substr($colType['type'], strpos($colType['type'], '(') + 1, -1));
			if ($maxLength > 0) {
				$html->attrs['maxlength'] = $maxLength;
			}
			$valLength = strlen($fValue);
			if (isset($params['widthClass'])) {
				if ($params['widthClass'] == 'inside-modal') {
					$html->attrs['style'] = 'width:98%;';
				} else {
					$html->attrs['style'] = 'width:98%;';
				}
			} else {
				if ($maxLength < 11) {
					$html->attrs['class'] []= 'span2';
				} else if ($maxLength < 31) {
					$html->attrs['class'] []= 'span5';
				} else if ($maxLength < 51) {
					$html->attrs['class'] []= (8 <= $maxGrid)? 'span8' : "span{$maxGrid}";
				} else if ($maxLength < 101) {
					$html->attrs['class'] []= (10 <= $maxGrid)? 'span10' : "span{$maxGrid}";
				} else {
					$html->attrs['class'] []= (12 <= $maxGrid)? 'span12' : "span{$maxGrid}";
				}
			}
		}
		else if (substr($colType['type'], 0, 4) == 'date') {
			$testDatePicker = true;
			if ($testDatePicker) {
				$html->attrs['type'] = 'text';
				$html->_params[] = 'date';
				if (substr($colType['type'], 0, 8) == 'datetime') {
					$html->attrs['class'][] = 'se_type-datetime';// datetimepicker';
					$html->attrs['data-format'] = 'yyyy-MM-dd hh:mm';
					$html->attrs['maxlength'] = 19;
				} else {
					$html->attrs['class'][] = 'se_type-date';// datepicker';
					$html->attrs['maxlength'] = 10;
				}
				if (substr($html->attrs['value'], 0, 10) == '0000-00-00') {
					$html->attrs['value'] = '';
				}
			} else {
				$html->attrs['type'] = 'date';
			}
		}
		else if (substr($colType['type'], 0, 4) == 'enum') {
			unset($html->attrs['type']);
			unset($html->attrs['value']);
			$html->tag = 'select';

			$values = explode(',', str_replace(array('(',')',"'",'"'), '', substr($colType['type'], 5)));
			$selValue = $fValue;
			if (empty($selValue) && $selValue !== '0' && !empty($colType['default'])) {
				if ($taskPerm == 'C') {
					$selValue = $colType['default'];
				} else if ($taskPerm == 'W' && $this->isAllowed($fieldID, 'R', $record)) {
					$selValue = $colType['default'];
				}
			}

			$html->cnt .= '<option value="">' . "" . '</option>';
			if (!empty($selValue) && !in_array($selValue, $values)) {
				$html->cnt .= '<option value="' . $selValue . '" selected="selected">' . $selValue . '</option>';
			}
			foreach ($values as $val) {
				$sel = ($selValue == $val)? ' selected="selected"' : '';
				$html->cnt .= '<option value="' . $val . '"' . $sel . '>' . $val . '</option>';
			}
		}
		else if (substr($colType['type'], 0, 4) == 'text') {
			$html->tag = 'textarea';
			$html->cnt = htmlspecialchars($fValue);
			if (isset($params['widthClass'])) {
				if ($params['widthClass'] == 'inside-modal') {
					$html->attrs['style'] = 'width:98%;';
				} else {
					$html->attrs['style'] = 'width:98%;';
				}
			} else {
				$html->attrs['class'][] = (8 <= $maxGrid)? 'span8' : "span{$maxGrid}";
			}
			$html->attrs['rows'] = '3';
			unset($html->attrs['type']);
			unset($html->attrs['value']);
		}
		else {
			echo'unknown Type "'.$colType['type'].'"';
		}

		$attrsOut = array();
		foreach ($html->attrs as $k => $v) {
			if (is_array($v)) $v = implode(' ', $v);
			$attrsOut[] = "{$k}=\"{$v}\"";
		}

		if (in_array($html->tag, array('select', 'textarea'))) {
			$out .= '<' . $html->tag . '' . (($attrsOut)? ' ' . implode(' ', $attrsOut) : '') . '>';
			$out .= $html->cnt;
			$out .= '</' . $html->tag . '>';
		} else {
			$out .= '<' . $html->tag . '' . (($attrsOut)? ' ' . implode(' ', $attrsOut) : '') . ' />';
		}

		if (in_array('date', $html->_params)) {
			$out = '<div class="input-append">' . $out . '<span class="add-on">
					<i data-time-icon="icon-time" data-date-icon="icon-calendar" class="icon-calendar"></i>
				</span>
			</div>';
		}

		if (true == V::get('appendBack', '', $params)) {
			if ($html->tag == 'input' && $taskPerm == 'W') {
				$out = '<div class="input-append show-last-value">' . $out . '<button class="btn btn-appendBack" type="button" title="' . htmlspecialchars($fValue) . '"><i class="icon-arrow-left"></i> Cofnij</button></div>';
			}
		}

		if ($typeSpecial) {
			$tsParams = array();
			$tsValue = V::get('typespecialValue', '', $params);
			if (!empty($tsValue)) {
				$tsParams['typespecialValue'] = $tsValue;
			}
			$out .= ' ' . $typeSpecial->showFormItem($this->_zasobID, $fName, $fValue, $tsParams, $record);
		}

		return $out;
	}

	/**
	 * Get column object. Not initialize
	 * @returns object - column instance if exists else null
	 * 
	 * static
	 */
	public static function getInstance($tableID) {
		static $_cache;
		if (!$_cache) $_cache = array();
		if (array_key_exists($tableID, $_cache)) {
			return $_cache[$tableID];
		}
		if (!empty($_SESSION['TableAcl_cache'][$tableID])) {
			$obj = new TableAcl($tableID);
			$obj->fromArray($_SESSION['TableAcl_cache'][$tableID]);
			$_cache[$tableID] = $obj;
			return $_cache[$tableID];
		}
		return null;
	}

	public function init($force = false) {
		if ($this->isInitialized() && $force == false) {
			return;
		}
		$dbID = $this->getDB();
		$tblName = $this->getName();
		$db = DB::getDB($dbID);
		if (!$db) {
			die('Error - Brak konfiguracji dla bazy danych ID=' . $dbID);
		}
		$res = $db->query("show fields from `{$tblName}` ");
		while ($h = $db->fetch_row($res)) {
			$fieldName = $h[0];
			$fieldType = $h[1];
			$this->_types[$fieldName] = array('type'=>$h[1], 'null'=>('YES' == $h[2]), 'default'=>$h[4]);
		}
		uasort($this->_fields, array($this, 'sortFieldsCallback'));

		$this->_fixDateFields();
		$this->_sortEnumFields();
		$this->_fixProjectType();

		$fieldIds = array_keys($this->_fields);
		Lib::loadClass('Typespecial');
		$vColsIdList = Typespecial::initFields($fieldIds);
		if (!empty($vColsIdList)) {
			$this->_virtualFieldsIdList = $vColsIdList;
		}

		$this->save();
	}

	private function _fixProjectType() {
		$tblName = $this->getName();
		$fldName = 'M_DIST_TYPE';
		if ($tblName == 'IN7_MK_BAZA_DYSTRYBUCJI') {
			foreach ($this->_fields as $kFldId => $vFld) {
				if ($vFld['name'] == $fldName) {
					$sqlTypes = array();

					if (!empty($this->_types[$fldName])) {
						if (substr($this->_types[$fldName]['type'], 0, 4) == 'enum') {
							$sqlTypes = explode(',', str_replace(array('(',')',"'",'"'), '', substr($this->_types[$fldName]['type'], 5)));
						}
					}

					if (!empty($sqlTypes)) {
						$allowedTypes = array();
						$db = DB::getDB();
						$sql = "select z.DESC
							from `CRM_LISTA_ZASOBOW` as z
							where z.`A_STATUS`='NORMAL'
								and z.`PARENT_ID`={$kFldId}
							order by z.`DESC` asc
						";
						$res = $db->query($sql);
						while ($r = $db->fetch($res)) {
							if (in_array($r->DESC, $sqlTypes)) {
								$allowedTypes[] = $r->DESC;
							}
						}

						sort($allowedTypes);

						if (!empty($allowedTypes)) {
							$this->_types[$fldName]['type'] = "enum('" . implode("','", $allowedTypes) . "')";
						}
					}
				}
			}
		}
	}

	private function _sortEnumFields() {
		foreach ($this->_fields as $kFldId => $vFld) {
			$type = $this->getFieldTypeById($kFldId);
			if (!empty($type['type'])) {
				if (substr($type['type'], 0, 4) == 'enum') {
					$sqlTypes = explode(',', str_replace(array('(',')',"'",'"'), '', substr($type['type'], 5)));

					if (!empty($sqlTypes)) {
						sort($sqlTypes);
						$this->_types[$vFld['name']]['type'] = "enum('" . implode("','", $sqlTypes) . "')";
					}
				}
			}
		}
	}

	private function _fixDateFields() {
		foreach ($this->_types as $kFldName => $vType) {
			if ($kFldName == 'L_APPOITMENT_DATE') {
				$this->_types[$kFldName]['type'] = 'datetime';
			} else if ($kFldName == 'A_PROBLEM_DATE') {
				$this->_types[$kFldName]['type'] = 'datetime';
			}
		}
	}

	public function getUniqueKeys() {
		$sqlKeys = array();
		$dbID = $this->getDB();
		$tblName = $this->getName();
		$db = DB::getDB($dbID);
		if (!$db) {
			die('Error - Brak konfiguracji dla bazy danych ID=' . $dbID);
		}
		$sql = "SHOW KEYS FROM  `{$tblName}`";
		$res = $db->query($sql);
		while ($r = $db->fetch($res)) {
			if ($r->Non_unique == '0') {
				$sqlKeys[$r->Column_name] = true;
			}
		}
		$sqlKeys = array_keys($sqlKeys);
		return $sqlKeys;
	}

	public function sortFieldsCallback($a, $b) {
		if ($a['name'] == 'ID') {
			return -1;
		}
		else if ($b['name'] == 'ID') {
			return 1;
		}
		else if ($a['sort_prio'] < $b['sort_prio']) {
			return -1;
		}
		else if ($a['sort_prio'] > $b['sort_prio']) {
			return 1;
		}
		else {
			return 0;
		}
	}

	public function isInitialized() {
		return (!empty($this->_types));
	}

	/**
	 * Save data in session cache.
	 */
	function save() {
		$_SESSION['TableAcl_cache'][$this->_zasobID] = $this->toArray();
	}

	public function getFieldTypeById($fieldID) {
		if (!array_key_exists($fieldID, $this->_fields)) {
			return null;
		}
		$colName = $this->_fields[$fieldID]['name'];
		if (!array_key_exists($colName, $this->_types)) {
			return null;
		}
		return $this->_types[$colName];
	}

	public function getFieldType($colName) {
		if (!array_key_exists($colName, $this->_types)) {
			return null;
		}
		return $this->_types[$colName];
	}

	public function hasFieldType($colName) {
		if (array_key_exists($colName, $this->_types)) {
			return true;
		}
		return false;
	}

	public function getVisibleFieldList() {
		$cols = array();
		$id = 0;
		foreach ($this->_fields as $kFieldID => $vField) {
			if ($vField['name'] == 'ID') {
				$id = $kFieldID;
			}
		}
		$cols[$id] = 'ID';
		foreach ($this->_fields as $kFieldID => $vField) {
			if ($vField['name'] == 'ID') {
				continue;
			}
			$cols[$kFieldID] = $vField['name'];
		}
		return $cols;
	}

	/**
	 * List of real fields in database.
	 */
	public function getRealFieldList() {
		$cols = array();
		$cols[] = 'ID';
		foreach ($this->_fields as $kFieldID => $vField) {
			if ($vField['name'] == 'ID') {
				continue;
			}
			if (array_key_exists($vField['name'], $this->_types)) {
				$cols[] = $vField['name'];
			}
		}
		return $cols;
	}

	public function getVirtualFieldList() {
		$cols = array();
		foreach ($this->_fields as $kFieldID => $vField) {
			if ($vField['name'] == 'ID') {
				continue;
			}

			if (in_array($kFieldID, $this->_virtualFieldsIdList)) {
				$cols[$kFieldID] = $vField['name'];
			}
			else if (!array_key_exists($vField['name'], $this->_types)) {
				$cols[$kFieldID] = $vField['name'];
			}
		}
		return $cols;
	}

	public function getFieldLabel($fieldID) {
		if (array_key_exists($fieldID, $this->_fields)) {
			if (!empty($this->_fields[$fieldID]['label'])) {
				return $this->_fields[$fieldID]['label'];
			}
		}
		return null;
	}

	public function getTypes() {
		return $this->_types;
	}

	public function fixEmptyValueFromUser($fieldID) {
		$value = '';
		$type = $this->getFieldTypeById($fieldID);
		if ($type) {
			if ($type['type'] == 'date') {
				$value = $type['default'];
			}

			// fix bug when field is unique and is null allowed: change empty string to null
			if ($type['null']) {
				$value = 'NULL';
			}

			// fix bug when field is enum and is set to '0': for php '0' is empty
			if (substr($type['type'], 0, 4) == 'enum') {// && $args["f{$fieldID}"] === '0') {
				if (false !== strpos($type['type'], "''")) {
					// enum('', '1','2')
					$value = '';
				} else if (false !== strpos($type['type'], "'0'")) {
					// enum('0', '1','2')
					$value = '0';
				} else {
					$value = $type['default'];
				}
			}
		}
		return $value;
	}

	public function fromArray($arr) {
		$this->_db = $arr['db'];
		$this->_name = $arr['name'];
		$this->_label = $arr['label'];
		$this->_opis = $arr['opis'];
		$this->_fields = $arr['fields'];
		$this->_virtualFieldsIdList = $arr['virtualFieldsIdList'];
		$this->_types = $arr['types'];
	}

	public function toArray() {
		$arr = array();
		$arr['db'] = $this->_db;
		$arr['name'] = $this->_name;
		$arr['label'] = $this->_label;
		$arr['opis'] = $this->_opis;
		$arr['fields'] = $this->_fields;
		$arr['virtualFieldsIdList'] = $this->_virtualFieldsIdList;
		$arr['types'] = $this->_types;
		return $arr;
	}

}
