<?php
  //////////////////////////////////////////////////////////////////////////////
  // Database Class 
  //============================================================================
  // Dependencies:
  //----------------------------------------------------------------------------
  // None
  //============================================================================
  // Modification History:
  //----------------------------------------------------------------------------
  // 2006-11-04: Created
  //////////////////////////////////////////////////////////////////////////////
  class Database extends Error
  {
    ## CONSTANT VARIABLES
      const DB_TYPES = 'mysql,mysqli'; // NO SPACES!
    ## END CONSTANT VARIABLES
    
    ## PUBLIC VARIABLES
    ## END PUBLIC VARIABLES
    
    ## PRIVATE VARIABLES
      private static $host;
      private static $port;
      private static $database;
      private static $username;
      private static $password;
      private static $type;
      private static $connection;
      private static $savedQueries;
      private static $savedResults;
    ## END PRIVATE VARIABLES
    
    ## CONSTRUCTOR
    ## END CONSTRUCTOR
    
    ## DECONSTRUCTOR
    ## END DECONSTRUCTOR
    
    ## PUBLIC METHODS
      // Initialize the Variables
      // Does not return anything, but acts like a constructor for Static classes
      public static function Initialize($varType, $varHost, $varPort, $varDatabase, $varUsername, $varPassword)
      {
        Error::Initialize();
        
        if (!self::ValidDatabaseTypes($varType))
        {
          Error::LogError("Database Type Invalid", "Database Type must be one of: " . self::DB_TYPES);
        }
        
        self::$host         = $varHost;
        self::$port         = $varPort;
        self::$type         = strtolower($varType);
        self::$database     = $varDatabase;
        self::$password     = $varPassword;
        self::$username     = $varUsername;
        self::$savedQueries = array();
        self::$savedResults = array();
        self::$connection   = self::ConnectToDatabase();
        
        self::SelectTheDatabase();
      }
      
      // DeInitialize the Variables
      // Does not return anything, but acts like a destructor for Static classes
      public static function DeInitialize()
      {
        // Remove Saved Queries
        for ($saved = 0; $saved < sizeof(self::$savedQueries); $saved++)
        {
          unset(self::$savedQueries[$saved]);
        }
        
        // Remove Saved Results
        for ($saved = 0; $saved < sizeof(self::$savedResults); $saved++)
        {
          unset(self::$savedResults[$saved]);
        }
        
        // Close the Database Connection
        switch (self::$type)
        {
          case "mysql":
            @mysql_close(self::$connection) or Error::LogError("MySQL Failed to Close", mysql_error(self::$connection));
            break;
          case "mysqli":
            @mysqli_close(self::$connection) or Error::LogError("MySQL Failed to Close", mysqli_error(self::$connection));
            break;
        }
        
        // Destroy Variables
        self::$host         = null;
        self::$port         = null;
        self::$type         = null;
        self::$database     = null;
        self::$password     = null;
        self::$username     = null;
        self::$connection   = null;
        self::$savedQueries = null;
        self::$savedResults = null;
        Error::DeInitialize();
      }
      
      // Database Types
      // Returns an array of database types
      public static function DatabaseTypes()
      {
        return split(",", self::DB_TYPES);
      }
      
      // Build Order By
      // Returns the SQL Syntax for ORDER BY
      public static function BuildOrderBy($varColumnName, $varDirection)
      {
        $orderby = "";
        if (self::$connection)
        {
          switch (self::$type)
          {
            case "mysql":
            case "mysqli":
              $orderby = "ORDER BY `{$varColumnName}` {$varDirection}";
              break;
          }
        }
        
        return $orderby;
      }
      
      // Build Limit
      // Returns the SQL Syntax for LIMIT
      public static function BuildLimit($varStartingRow, $varNumberOfRows)
      {
        $limit = "";
        if (self::$connection)
        {
          switch (self::$type)
          {
            case "mysql":
            case "mysqli":
              $limit = "LIMIT {$varStartingRow}, {$varNumberOfRows}";
              break;
          }
        }
        
        return $limit;
      }
      
      // Execute SQL Query
      // Returns the result of the query, which is typically a resource id
      public static function ExecuteQuery($sql, $name)
      {
        if (self::$connection)
        {
          if (strlen(trim($name)) != 0)
          {
            switch (self::$type)
            {
              case "mysql":
                if (!array_key_exists($name, self::$savedQueries))
                {
                  self::$savedQueries[$name] = @mysql_query($sql, self::$connection) or Error::LogError("Query Failed", mysql_error(self::$connection));
                }
                break;
              case "mysqli":
                if (!array_key_exists($name, self::$savedQueries))
                {
                  self::$savedQueries[$name] = @mysqli_query(self::$connection, $sql) or Error::LogError("Query Failed", mysqli_error(self::$connection));
                }
                break;
            }
            
            return self::$savedQueries[$name];
          }
          else
          {
            Error::LogError("Execute Query Name Missing", "The name parameter was empty, please provide a name for the query.");
          }
        }
        
        return null;
      }
      
      // Fetch Results
      // Returns an array of the query results
      public static function FetchResults($name)
      {
        $results = array();
        if (self::$connection)
        {
          if (strlen(trim($name)) != 0 && (array_key_exists($name, self::$savedQueries) || array_key_exists($name, self::$savedResults)))
          {
            if (array_key_exists($name, self::$savedQueries))
            {
              switch (self::$type)
              {
                case "mysql":
                  $row = 0;
                  while ($currentResult = @mysql_fetch_assoc(self::$savedQueries[$name]))
                  {
                    $col = 0;
                    foreach ($currentResult as $key => $value)
                    {
                      $results[$row][$col] = $value;
                      $results[$row][$key] = $value;
                      $col++;
                    }
                    
                    $row++;
                  }
                  break;
                case "mysqli":
                  $row = 0;
                  while ($currentResult = @mysqli_fetch_assoc(self::$savedQueries[$name]))
                  {
                    $col = 0;
                    foreach ($currentResult as $key => $value)
                    {
                      $results[$row][$col] = $value;
                      $results[$row][$key] = $value;
                      $col++;
                    }
                    
                    $row++;
                  }
                  break;
              }
            
              self::$savedResults[$name] = $results;
            }
            else
            {
              $results = self::$savedResults[$name];
            }
          }
          else
          {
            if (strlen(trim($name)) == 0)
            {
              Error::LogError("Fetch Results Name Missing", "The name parameter was empty, the name is required so it knows which results to return.");
            }
            else
            {
              Error::LogError("Fetch Results Name ('{$name}') Not Found", "The name provided did not have any query results associated with it.");
            }
          }
        }
        
        return $results;
      }
      
      // Free SQL Query Results
      // Returns nothing
      public static function FreeResults($name)
      {
        if (self::$connection)
        {
          if (strlen(trim($name)) != 0 && array_key_exists($name, self::$savedQueries))
          {
            switch (self::$type)
            {
              case "mysql":
                @mysql_free_result(self::$savedQueries[$name]) or Error::LogError("Free Results Error", mysql_error(self::$connection));
                unset(self::$savedQueries[$name]);
                break;
              case "mysqli":
                @mysqli_free_result(self::$savedQueries[$name]) or Error::LogError("Free Results Error", mysqli_error(self::$connection));
                unset(self::$savedQueries[$name]);
                break;
            }
          }
          else
          {
            if (strlen(trim($name)) == 0)
            {
              Error::LogError("Free Results Name Missing", "The name parameter was empty, the name is required so it knows which results to free up from memory.");
            }
            else
            {
              Error::LogWarning("Free Results Name ('{$name}') Not Found", "The name provided did not have any query results associated with it.");
            }
          }
        }
      }
      
      // Remove Saved Results
      // Returns nothing
      public static function RemoveSavedResults($name)
      {
        if (strlen(trim($name)) != 0 && array_key_exists($name, self::$savedResults))
        {
          unset(self::$savedResults[$name]);
        }
        else
        {
          if (strlen(trim($name)) == 0)
          {
            Error::LogError("Remove Saved Result Name Missing", "The name parameter was empty, the name is required so it knows which query to remove.");
          }
          else
          {
            Error::LogWarning("Remove Saved Result Name ('{$name}') Not Found", "The name provided was not a saved query.");
          }
        }
      }
      
      // Attempt Connect To Database
      // Returns true or false depending on if the connection failed or succeeded
      public static function AttemptConnectToDatabase($varType, $varHost, $varPort, $varDatabase, $varUsername, $varPassword)
      {
        self::$type       = $varType;
        self::$host       = $varHost;
        self::$port       = $varPort;
        self::$database   = $varDatabase;
        self::$username   = $varUsername;
        self::$password   = $varPassword;
        
        Error::ClearErrors();
        self::$connection = self::ConnectToDatabase();
        
        if (!Error::HasErrors())
        {
          return true;
        }
        else
        {
          return false;
        }
      }
      
      // MySQL Version
      // Returns the mysql version number
      public static function MysqlVersion()
      {
        $version = "";
        if (self::$connection)
        {
          switch (self::$type)
          {
            case "mysql":
              $version = mysql_get_server_info(self::$connection);
              break;
            case "mysqli":
              $version = mysqli_get_server_info(self::$connection);
              break;
          }
        }
        
        return $version;
      }
    ## END PUBLIC METHODS
    
    ## PRIVATE METHODS
      // Connect to Database
      // Returns the database connection resource
      private static function ConnectToDatabase()
      {
        $link = null;
        
        switch (self::$type)
        {
          case "mysql":
            if (strlen(trim(self::$port)) != 0)
            {
              $link = mysql_connect(self::$host . ":" . self::$port, self::$username, self::$password) or Error::LogError("Database Error", mysql_error());
            }
            else
            {
              $link = mysql_connect(self::$host, self::$username, self::$password) or Error::LogError("Database Error", mysql_error());
            }
            break;
          case "mysqli":
            $link = mysqli_connect(self::$host, self::$username, self::$password, self::$database, self::$port) or Error::LogError("Database Error", mysqli_connect_error());
            break;
        }
        
        return $link;
      }
      
      // Select the Database
      // Returns nothing
      private static function SelectTheDatabase()
      {
        switch (self::$type)
        {
          case "mysql":
            @mysql_select_db(self::$database, self::$connection) or Error::LogError("Database Selection", mysql_error(self::$connection));
            break;
        }
      }
      
      // Valid Database Types
      // Returns true or false depending on if the database type is valid
      private static function ValidDatabaseTypes($varType)
      {
        $types = split(',', str_replace(" ", "", self::DB_TYPES));
        
        return in_array($varType, $types);
      }
    ## END PRIVATE METHODS
    
    ## PROTECTED METHODS
    ## END PROTECTED METHODS
  }
?>