<?php
if( !defined( 'MYSQL_TABLE_PREFIX' ) ) define( 'MYSQL_TABLE_PREFIX', '' );
class DataBase extends FileJobs{
	var $aFieldsNames;
	var $aFieldsSort;
	var $aFilesDefNames;
	var $sFileName;
	var $rDBConnection;
	var $rLastResource;
	var $sLogFileName;
	// MYSQLI_ASSOC = 0x1
	// MYSQLI_NUM = 0x2
	// MYSQLI_BOTH = 0x3 = MYSQLI_ASSOC | MYSQLI_NUM
	const SINGLE_RECORD = 0x4;
	const SINGLE_COLUMN = 0x8;
	const SINGLE_VALUE = 0xC; //SINGLE_RECORD | SINGLE_COLUMN
	const ASSOCIATIVE = 0x10;
	static function &getInstance( ){
		static $oInstance = null;
		if( !isset( $oInstance ) ){
			$oInstance = new DataBase( );
			$oInstance->rDBConnection = ($GLOBALS["___mysqli_ston"] = mysqli_connect( MYSQL_HOST,  MYSQL_USER,  MYSQL_PASSWORD, MYSQL_DB, MYSQL_PORT ));
			mysqli_query( $oInstance->rDBConnection ,  'SET NAMES \'utf8\';');
			$oInstance->sLogFileName = null;//uniqid();
		}
		return $oInstance;
	}
	function setFileName( $sFileName ){
		$this->sFileName = $sFileName;
	}
	function throwTableName( $sDatabase ){
		return MYSQL_TABLE_PREFIX . preg_replace( '|^database/(.*)\.php$|', '$1', $sDatabase );
	}
	function throwRoutineName( $sRoutine ){
		return MYSQL_TABLE_PREFIX . str_replace( '%%', LANGUAGE, $sRoutine );
	}
	function executeSQL( $sql, $return = false, $flag = MYSQLI_ASSOC, $mIndex = null ){
		$log = date('Y-m-d H:i:s') . "\n" . $sql . "\n";
		$time = microtime( true );
		if( !( $flag & MYSQLI_BOTH ) ) $flag = $flag | MYSQLI_ASSOC;
		if( ( $flag & self::ASSOCIATIVE ) && ( !isset( $mIndex ) ) ) $flag = $flag & ~MYSQLI_ASSOC | MYSQLI_NUM;
		if( $flag & self::SINGLE_COLUMN ) $flag = $flag & ~MYSQLI_ASSOC | MYSQLI_NUM;
		$r = mysqli_query( $this->rDBConnection ,  $sql );
		$log .= ( microtime( true ) - $time ) . "\n\n";
		if( $this->sLogFileName ) file_put_contents( 'logs/sql'.$this->sLogFileName.'.log', $log, FILE_APPEND );
		if( $r ){
			$this->rLastResource = $r;
			if( $return ){
				$aReturn = Array( );
				while( $row = mysqli_fetch_array( $r,  $flag & MYSQLI_BOTH ) ){
					if( ( $flag & self::ASSOCIATIVE ) && ( !isset( $mIndex ) ) ) $aReturn[$row[0]] = $row[1];
					elseif( ( $flag & self::ASSOCIATIVE ) && ( isset( $mIndex ) ) ) $aReturn[$row[$mIndex]] = $row;
					elseif( $flag & self::SINGLE_COLUMN ) $aReturn[] = $row[0];
					else $aReturn[] = $row;
				}
				if( $flag & self::SINGLE_RECORD ) return $aReturn[0];
				else return $aReturn;
			} else{
				return true;
			}
		} else{
			die( ((is_object( $this->rDBConnection )) ? mysqli_error( $this->rDBConnection ) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '<br />' . $sql );
			return false;
		}
	}
	function numRows( ){
		return mysqli_num_rows( $this->rLastResource );
	}
	function affectedRows( ){
		return mysqli_affected_rows( $this->rDBConnection );
	}
	function throwArrayRelated( $sFileName, $mValue, $sSearch, $sGet ){
		$sql = 'SELECT `' . $sGet . '` FROM `' . $this->throwTableName( $sFileName ) . '` WHERE `' . $sSearch . '` = \'' . mysqli_real_escape_string( $this->rDBConnection ,  $mValue) . '\'';
		return $this->executeSQL( $sql, true, DataBase::SINGLE_COLUMN );
	}
	function setFileDefVariables( $sFileName ){
		if( !isset( $this->aFilesDefNames[$sFileName] ) ){
			$aExp = $this->throwNameExtOfFile( $sFileName );
			$this->aFilesDefNames[$sFileName] = $aExp[0] . '.def' . '.' . $aExp[1];
			if( !is_file( $this->aFilesDefNames[$sFileName] ) ){
				die( 'DataBase error - no definition file <b>' . $this->aFilesDefNames[$sFileName] . '</b><br />' );
			}
			include $this->aFilesDefNames[$sFileName];
			$this->aFieldsNames[$sFileName] = $aFieldsNames;
			if( isset( $aFieldsSort ) ) $this->aFieldsSort[$sFileName] = $aFieldsSort;
			else $this->aFieldsSort[$sFileName] = null;
		}
	}
	function save( $sFileName, $aData, $sId = null ){
		$this->setFileName( $sFileName );
		$this->setFileDefVariables( $this->sFileName );
		if( is_file( $this->aFilesDefNames[$this->sFileName] ) && is_array( $aData ) ){
			$sTableName = $this->throwTableName( $this->sFileName );
			$aNames = Array( );
			$aValues = Array( );
			$aNamesValues = Array( );
			foreach( $this->aFieldsNames[$this->sFileName] as $sIndex ){
				if( isset( $aData[$sIndex] ) ){
					if( strpos( $sIndex, 'f' ) === 0 ) $aData[$sIndex] = str_replace( ',', '.', $aData[$sIndex] );
					$aNames[] = '`' . $sIndex . '`';
					$sNames = implode( ', ', $aNames );
					$aValues[] = ( $aData[$sIndex] === '' ? 'NULL' : '\'' . mysqli_real_escape_string( $this->rDBConnection ,  $aData[$sIndex]) . '\'' );
					$sValues = implode( ', ', $aValues );
					$aNamesValues[] = '`' . $sIndex . '` = ' . ( $aData[$sIndex] === '' ? 'NULL' : '\'' . mysqli_real_escape_string( $this->rDBConnection , $aData[$sIndex]) . '\'' );
					$sNamesValues = implode( ', ', $aNamesValues );
				}
			}
			if( isset( $sId ) ){
				$sql = 'UPDATE `' . $sTableName . '` SET ' . $sNamesValues . ' WHERE ';
				if( is_array( $sId ) ){
					$conds = Array();
					foreach( $sId as $cond ){
						$conds[] = '`' . $cond . '`=\'' . mysqli_real_escape_string( $this->rDBConnection ,  $aData[$cond]) . '\'';
					}
					$sql .= implode( ' AND ', $conds );
					$sId = array_shift( $sId );
				} else{
					$sql .= '`' . $sId . '`=\'' . mysqli_real_escape_string( $this->rDBConnection ,  $aData[$sId]) . '\'';
				}
				$this->executeSQL( $sql );
				$info = mysqli_info( $this->rDBConnection );
				$matched = preg_replace( '/^[^:]*: (\\d+)[^\\d].*$/', '$1', $info );
				if( !$matched ) $sId = null;
				else return $aData[$sId];
			}
			if( !isset( $sId ) ){
				$sql = 'INSERT INTO `' . $sTableName . '` ( ' . $sNames . ' ) VALUES ( ' . $sValues . ' )';
				$this->executeSQL( $sql );
				if( mysqli_affected_rows( $this->rDBConnection ) ) return ((is_null($___mysqli_res = mysqli_insert_id( $this->rDBConnection ))) ? false : $___mysqli_res);
			}
			return false;
		} else return false;
	}
	function throwLastId( $sFile, $sIndex ){
		$this->setFileName( $sFile );
		$sTableName = $this->throwTableName( $this->sFileName );
		$sql = 'SELECT MAX( `' . $sIndex . '` ) AS `iMax` FROM `' . $sTableName . '`';
		return $this->executeSQL( $sql, true, DataBase::SINGLE_VALUE );

	}
	function throwFileArraySmall( $sFile, $sIndexFirst, $sIndexSecond, $sOrder = null, $aWhere = Array() ){
		$sql = 'SELECT `' . $this->escape( $sIndexFirst ) . '`, `' . $this->escape( $sIndexSecond ) . '` FROM `' . $this->throwTableName( $sFile ) . '`';
		if( !empty( $aWhere ) ){
			$aWhereS = Array( );
			foreach( $aWhere as $sKey => $mValue ){
				$aWhereS[] = '`' . $sKey . '` = \'' . mysqli_real_escape_string( $this->rDBConnection ,  $mValue) . '\'';
			}
			$sql.= ' WHERE ' . implode( ' AND ', $aWhereS );
		}
		if( isset( $sOrder ) && !empty( $sOrder ) ) $sql.= ' ORDER BY `' . $sOrder . '` ASC';
		else $sql.= $this->generateDefaultSort( $sFile );
		return $this->executeSQL( $sql, true, DataBase::ASSOCIATIVE );
	}
	function throwData( $sFile, $mValue, $mIndex ){
		$this->setFileName( $sFile );
		$sTableName = $this->throwTableName( $this->sFileName );
		$sql = 'SELECT * FROM `' . $sTableName . '` WHERE';
		$bAnd = false;
		if( is_array( $mIndex ) ) foreach( $mIndex as $sIndex ){
			$sql.= ( $bAnd ? ' AND' : null ) . ' `' . $sIndex . '` = \'' . mysqli_real_escape_string( $this->rDBConnection ,  $mValue[$sIndex]) . '\'';
			$bAnd = true;
		} else{
			$sql.= ' `' . $mIndex . '` = \'' . mysqli_real_escape_string( $this->rDBConnection ,  $mValue) . '\'';
		}
		return $this->executeSQL( $sql, true, DataBase::SINGLE_RECORD );
	}
	function throwDataFromFiles( $aFiles, $mValues, $mIndexes ){
		if( is_array( $aFiles ) ){
			foreach( $aFiles as $i => $sFile ){
				$sIndex = is_array( $mIndexes ) ? $mIndexes[$i] : $mIndexes;
				$mValue = is_array( $mValues ) ? $mValues[$i] : $mValues;
				$aData = $this->throwData( $sFile, $mValue, $sIndex );
				if( isset( $aData ) ){
					if( !isset( $aReturn ) ) $aReturn = $aData;
					else $aReturn = array_merge( $aReturn, $aData );
				}
			}
			if( isset( $aReturn ) ) return $aReturn;
		}
	}
	function deleteInFile( $sFile, $mValue, $sIndex ){
		$this->setFileName( $sFile );
		$sTableName = $this->throwTableName( $this->sFileName );
		if( is_array( $mValue ) ){
			foreach( $mValue as $sValue => $x ) if( $x ){
				$sql = 'DELETE FROM `' . $sTableName . '` WHERE `' . $sIndex . '` = \'' . mysqli_real_escape_string( $this->rDBConnection ,  $sValue) . '\'';
				$this->executeSQL( $sql );
			}
		} else{
			$sql = 'DELETE FROM `' . $sTableName . '` WHERE `' . $sIndex . '` = \'' . mysqli_real_escape_string( $this->rDBConnection ,  $mValue) . '\'';
			$this->executeSQL( $sql );
		}
	}
	function delete( $sFile, $aCondition, $bMulti = false ){
		$aWhere = Array( );
		if( $bMulti ){
			foreach( $aCondition as $aCond ){
				$aWhereInner = Array( );
				foreach( $aCond as $sName => $mValue ){
					$aWhereInner[] = '`' . $sName . '` = \'' . $this->escape( $mValue ) . '\'';
				}
				$aWhere[] = implode( ' AND ', $aWhereInner );
			}
			$sWhere = '( ' . implode( ' ) OR ( ', $aWhere ) . ' )';
		} else{
			foreach( $aCondition as $sName => $mValue ){
				$aWhere[] = '`' . $sName . '` = \'' . $this->escape( $mValue ) . '\'';
			}
			$sWhere = implode( ' AND ', $aWhere );
		}
		$this->executeSQL( 'DELETE FROM `' . $this->throwTableName( $sFile ) . '` WHERE ' . $sWhere );
	}
	function generateDefaultSort( $sFile ){
		if( isset( $this->aFieldsSort[$sFile] ) && is_array( $this->aFieldsSort[$sFile] ) && !empty( $this->aFieldsSort[$sFile] ) ){
			return ' ORDER BY ' . implode( ' ASC, ', $this->aFieldsSort[$sFile] ) . ' ASC ';
		}
	}
	function throwFileArray( $sFile, $aWhere = null, $iPage = null, $iMax = null, $returnNum = false ){
		$this->setFileName( $sFile );
		$sTableName = $this->throwTableName( $this->sFileName );
		$sql = 'SELECT SQL_CALC_FOUND_ROWS * FROM `' . $sTableName . '`';
		if( isset( $aWhere ) ){
			$sql.= ' WHERE 1';
			foreach( $aWhere as $sIndex => $mValue ){
				$sql.= ' AND `' . $sIndex . '` = \'' . $this->escape( $mValue ) . '\'';
				}
			}
		$sql.= $this->generateDefaultSort( $this->sFileName );
		if( !isset( $iPage ) ){
			$iPage = 1;
		}
		if( isset( $iMax ) ){
			$iMax = intval( $iMax );
			if( $iMax > 0 ){
				$sql.= ' LIMIT ' . ( ( $iPage - 1 ) * $iMax ) . ', ' . $iMax;
			}
		}
		$aData = $this->executeSQL( $sql, true, $returnNum ? MYSQLI_NUM : MYSQLI_ASSOC );
		if( isset( $aData ) ){
			return $aData;
		} else{
			return null;
		}
	}
	function cacheFilesIndexes( $mFiles ){
		if( is_array( $mFiles ) ){
			foreach( $mFiles as $iKey => $sFile ){
				$this->setFileDefVariables( $sFile );
			}
		} else{
			$this->setFileDefVariables( $mFiles );
		}
	}
	function update( $sFile, $aSet, $aWhere = Array( ) ){
		$this->setFileName( $sFile );
		$this->setFileDefVariables( $this->sFileName );
		$sTableName = $this->throwTableName( $this->sFileName );
		if( is_file( $this->aFilesDefNames[$this->sFileName] ) ){
			$aNamesValues = Array( );
			$aSet = array_intersect_key( $aSet, array_flip( $this->aFieldsNames[$this->sFileName] ) );
			foreach( $aSet as $sName => $mValue ){
				if( strpos( $sName, 'f' ) === 0 ) $mValue = str_replace( ',', '.', $mValue );
				$aNamesValues[] = '`' . $sName . '` = ' . ( $mValue === '' ? 'NULL' : '\'' . mysqli_real_escape_string( $this->rDBConnection ,  $mValue) . '\'' );
			}
			if( empty( $aNamesValues ) ) return false;
			$sql = 'UPDATE `' . $sTableName . '` SET ' . implode( ', ', $aNamesValues );
			if( !empty( $aWhere ) ){
				$aWhereS = Array( );
				foreach( $aWhere as $sKey => $mValue ){
					$aWhereS[] = '`' . $sKey . '` = \'' . mysqli_real_escape_string( $this->rDBConnection ,  $mValue) . '\'';
				}
				$sql.= ' WHERE ' . implode( ' AND ', $aWhereS );
			}
			$this->executeSQL( $sql );
			$info = mysqli_info( $this->rDBConnection );
			$matched = preg_replace( '/^[^:]*: (\\d+)[^\\d].*$/', '$1', $info );
			if( !$matched ) return false;
			else return true;
		}
		return null;
	}
	function escape( $string ){
		return mysqli_real_escape_string( $this->rDBConnection ,  $string);
	}
};
?>