<?php

namespace FOP;

class Database {
  
  

    // --- Statische Eigenschaften ---
  
  static private $db ;
  static private $lastSeqName ;

    // --- Statische Methoden ---
  
  public static function getLastInsertId() { 
    
    
    // --- BLOCK: main ---
    return self::$db->lastInsertId(self::$lastSeqName ? qi(self::$lastSeqName) /* workaround because PDO does not properly escape */ : null);
    
  }

  public static function beginTransaction() { 
    
    
    // --- BLOCK: main ---
    return self::$db->beginTransaction();
    
  }

  public static function commitTransaction() { 
    
    
    // --- BLOCK: main ---
    return self::$db->commit();
    
  }

  public static function rollbackTransaction() { 
    
    
    // --- BLOCK: main ---
    return self::$db->rollBack();
    
  }

  public static function inTransaction() { 
    
    
    // --- BLOCK: main ---
    return self::$db->inTransaction();
    
  }

  public static function errorInfo() { 
    
    
    // --- BLOCK: main ---
    return self::$db->errorInfo();
    
  }

  public static function enterMaintainanceMode() { 
    
    
    // --- BLOCK: main ---
    
	self::$db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_WARNING);

    
  }

  public static function getDB() { 
    
    
    // --- BLOCK: main ---
    return self::$db;
    
  }

  public static function prepare($sql) { 
    
    
    // --- BLOCK: main ---
    
	if (self::getDriver() == 'pgsql' && preg_match('/\s*INSERT\s*INTO\s*"((""|[^"])+)"/i', $sql, $match)) {
		$tbl = str_replace('""', '"', $match[1]);
		if ($tbl == 'cron') self::$lastSeqName = $tbl . '_id_seq'; else
		if ($tbl == 'fop_idlist') self::$lastSeqName = $tbl . '_id_seq'; else
		if ($tbl == 'fop_exceptions') self::$lastSeqName = $tbl . '_id_seq'; else
		if ($tbl == 'ChatgruppeSubscriptions') self::$lastSeqName = $tbl . '_Id_seq'; else
		if ($tbl == 'PLZ') self::$lastSeqName = $tbl . '_PLZ_seq'; else
		self::$lastSeqName = $tbl . '_ID_seq';
	}
	return self::$db->prepare($sql);
    
  }

  public static function exec($sql) { 
    
    
    // --- BLOCK: main ---
    return self::$db->exec($sql);
    
  }

  public static function ensureIsLoaded() { 
    
    
    // --- BLOCK: main ---
    
  // Can be called to ensure class is loaded and initialized

    
  }

  public static function getDriver() { 
    
    
    // --- BLOCK: main ---
    return \FOP\Configuration::getFOPDatabaseDriver();
    
  }

  public static function getHost() { 
    
    
    // --- BLOCK: main ---
    return \FOP\Configuration::getFOPDatabaseHost();
    
  }

  public static function getDatabase() { 
    
    
    // --- BLOCK: main ---
    return \FOP\Configuration::getFOPDatabaseDatabase();
    
  }

  public static function getUsername() { 
    
    
    // --- BLOCK: main ---
    return \FOP\Configuration::getFOPDatabaseUsername();
    
  }

  public static function getPassword() { 
    
    
    // --- BLOCK: main ---
    return \FOP\Configuration::getFOPDatabasePassword();
    
  }

  public static function translateType($type) { 
    
    
    // --- BLOCK: main ---
    
	$type = strtolower($type);
	if (self::getDriver() == 'mysql') {
		$type = str_replace(', ', ',', $type); // mysqls way of writing decimal(12,1) is without space
		if ($type == 'int') return 'int(11)';
		if ($type == 'integer') return 'int(11)';
		if ($type == 'bigint') return 'bigint(20)';
		if ($type == 'boolean') return 'int(11)';
	}
	if (self::getDriver() == 'pgsql') {
		if ($type == 'boolean') return 'bool';
		if ($type == 'int') return 'int4';
		if ($type == 'integer') return 'int4';
		if ($type == 'bigint') return 'int8';
		if ($type == 'longtext') return 'text';
		if ($type == 'longblob') return 'bytea';
		if ($type == 'double precision') return 'float8';
		if (substr($type, 0, 7) == 'decimal') return 'numeric' . substr($type, 7);
	}
	return $type;

    
  }

  public static function sessionVarSQL($x) { 
    
    
    // --- BLOCK: main ---
    
	$result = \FOP\Database::getDriver() == 'pgsql' ? "current_setting('fop.$x', TRUE)" : "@fop_$x";
	if (($x == 'time' || $x == 'user') && \FOP\Database::getDriver() == 'pgsql') $result .= '::INTEGER';
	return $result;
    
  }

  public static function setTime($t) { 
    
    
    // --- BLOCK: main ---
    
	 if (self::getDriver() == 'mysql') {
		 self::query('SELECT @fop_time := ' . self::quote($t));
	 } else if (self::getDriver() == 'pgsql') {
		 self::query('SET SESSION "fop.time" = ' . intval($t));
	 }

    
  }

  public static function quote($value) { 
    
    
    // --- BLOCK: main ---
    if ($value === null) return 'NULL';
    if ($value === false) return 'FALSE';
    if ($value === true) return 'TRUE';
	 if (is_float($value)) return str_replace(',', '.', $value);
	 if (is_array($value)) $value = json_encode($value);
    return self::$db->quote($value);
    
  }

  public static function quoteIdent($value) { 
    
    
    // --- BLOCK: main ---
    
	if (self::getDriver() == 'pgsql') {
		// PostgreSQL
		return '"' . str_replace('"', '""', $value) . '"';
	}
	// MySQL syntax
	return '`' . str_replace('`', '``', $value) . '`';

    
  }

  public static function query($sql) { 
    
    
    // --- BLOCK: main ---
    
	$startTime = microtime(true);
	$result = self::$db->query($sql);
	$endTime = microtime(true);
	\FOP\Database::logQuery($sql, $endTime - $startTime);
	if (self::getDriver() == 'pgsql' && preg_match('/\s*INSERT\s*INTO\s*"((""|[^"])+)"/i', $sql, $match)) {
		$tbl = str_replace('""', '"', $match[1]);
		if ($tbl == 'cron') self::$lastSeqName = $tbl . '_id_seq'; else
		if ($tbl == 'fop_idlist') self::$lastSeqName = $tbl . '_id_seq'; else
		if ($tbl == 'fop_exceptions') self::$lastSeqName = $tbl . '_id_seq'; else
		if ($tbl == 'ChatgruppeSubscriptions') self::$lastSeqName = $tbl . '_Id_seq'; else
		if ($tbl == 'PLZ') self::$lastSeqName = $tbl . '_PLZ_seq'; else
		self::$lastSeqName = $tbl . '_ID_seq';
	}
	return $result;
    
  }

  public static function logQuery($sql, $time) { 
    
    
    // --- BLOCK: main ---
    
	// variant 1: error log
	// error_log('SQL query ' . $time . 's: ' . substr($sql, 0, 50));

	// variant 2: SQL table
	/* 
			CREATE TABLE `fop_sql` (
			  `ID` int(11) NOT NULL,
			  `time` bigint(20) NOT NULL,
			  `sql` text NOT NULL,
			  `duration` double NOT NULL
			) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
			ALTER TABLE `fop_sql`
			  ADD PRIMARY KEY (`ID`);
			ALTER TABLE `fop_sql`
			  MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT;
  */
	// self::$db->query('INSERT INTO fop_sql(`time`, `sql`, `duration`) VALUES (UNIX_TIMESTAMP(), '.self::quote($sql).','.self::quote($time).')');

	// TODO:!!!! WICHTIG !!!! Sicherstellen, dass Aufruf das Ergebnis von getLastInsertId nicht verfälscht


    
  }

  public static function initialize() { 
    
    
    // --- BLOCK: dbinit ---
    
    try {
		  // pdo parameter je nach Treiber
		  $addon = '';
		  if (self::getDriver() == 'mysql') {
			  $addon .= ';charset=utf8mb4';
		  } else if (self::getDriver() == 'pgsql') {
			  $addon .= ';options=\'--client_encoding=UTF8\'';
		  }
        self::$db = new \PDO(self::getDriver() . ":host=" . self::getHost() . ";dbname=" . self::getDatabase() . $addon, self::getUsername(), self::getPassword());
    } catch (\PDOException $e) {
        if(\FOP\Configuration::isActive()){
            throw $e; // during setup: throw so we can catch the exception and show in setup menu
        }
        // otherwise: print our custom error message and deny
        http_response_code(500);
        error_log("Connection Failed!: " . $e->getMessage());
        die("Could not connect to database");
    }
    self::$db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
	\FOP\I18n::ensureIsLoaded();
	\FOP\I18N::initialize();
	 if (self::getDriver() == 'mysql') {
		 self::query('SET SESSION group_concat_max_len = 1000000,
						 @fop_time = ' . self::quote(time()) . ',
						 @fop_dateformat = ' . self::quote(_('dateformat_mysql')) . ',
						 @fop_datetimeformat = ' . self::quote(_('datetimeformat_mysql')) . '');
	 } else if (self::getDriver() == 'pgsql') {
		 self::query('SET SESSION "fop.time" = ' . time());
		 self::query('SET SESSION "fop.dateformat" = ' . self::quote(_('dateformat_pgsql')));
		 self::query('SET SESSION "fop.datetimeformat" = ' . self::quote(_('datetimeformat_pgsql')));
	 }

    
  }

  public static function setup(&$config) { 
    
    
    // --- BLOCK: dbcheck ---
    

require('dbcheck.php');



    
  }


  
  

  
  
}

\FOP\Database::initialize(); 

