/**
  * Deletes a single group, given its group_id
  *
  * @version 1.0
  * @since 1.0
  *
  * @param int $group_id | id of the group
  * @return bool | False on failure. True on success.
  */
 public function deleteGroup($group_id)
 {
     global $fox;
     $db = new FOX_db();
     $columns = array("mode" => "include", "col" => array("is_default", "name"));
     $ctrl = array("format" => "row_array");
     try {
         $group = $db->runSelectQueryCol(self::$struct, "group_id", "=", $group_id, $columns, $ctrl);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 1, 'text' => "DB select exception", 'data' => array("data" => $data, "col" => "group_id", "op" => "=", "val" => $group_id, "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     // If the group we're trying to delete is the default group, reject the action. There must *always* be a
     // default group on the system. If the admin wants to delete the default group, they have to make
     // another group the default group first.
     if ($group["is_default"] == true) {
         //echo "\nclass.user.group.types::deleteGroup() - attempted delete on default group\n";
         return false;
     }
     // Trap trying to delete a nonexistent group
     if (!$group) {
         //echo "\nclass.user.group.types::deleteGroup() - attempted delete on nonexistent group: $group_id \n";
         return false;
     }
     // Get the user_id of every user in the group we're deleting
     $columns = array("mode" => "include", "col" => "user_id");
     $ctrl = array("format" => "col");
     try {
         $user_ids = $db->runSelectQueryCol(FOX_uGroupMember::_struct(), "group_id", "=", $group_id, $columns, $ctrl);
     } catch (FOX_exception $child) {
         throw new FOX_exception(array('numeric' => 2, 'text' => "DB select exception", 'data' => array("data" => $data, "col" => "group_id", "op" => "=", "val" => $group_id, "columns" => $columns, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
     }
     // CASE 1: There are users that are members of the group
     // ===============================================================================
     if ($user_ids) {
         // Load all of the groups that each user is currently in, except
         // the group we're removing them from
         $args = array(array("col" => "user_id", "op" => "=", "val" => $user_ids), array("col" => "group_id", "op" => "!=", "val" => $group_id));
         $ctrl = array("format" => "array_key_array_grouped", "key_col" => array("user_id", "group_id"));
         try {
             $in_groups = $db->runSelectQuery(FOX_uGroupMember::_struct(), $args, $columns = null, $ctrl);
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 3, 'text' => "DB select exception", 'data' => array("args" => $args, "ctrl" => $ctrl), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
         }
         // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
         try {
             $started_transaction = $db->beginTransaction();
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 4, 'text' => "beginTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
         }
         if ($started_transaction) {
             $keys_ok = true;
             try {
                 $gk = new FOX_uGroupKeyRing();
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 2, 'text' => "FOX_uGroupKeyRing constructor exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
             }
             foreach ($user_ids as $user) {
                 // Get the combined keyring of all the user's other groups
                 try {
                     $keep_keys = $gk->getKeys($in_groups[$user]);
                 } catch (FOX_exception $child) {
                     throw new FOX_exception(array('numeric' => 5, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("user" => $in_groups[$user]), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                 }
                 // Get the keyring of the group we're removing the user from
                 try {
                     $drop_keys = $gk->getKeys($group_id);
                 } catch (FOX_exception $child) {
                     throw new FOX_exception(array('numeric' => 6, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("group_id" => $group_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                 }
                 // Intersect the $keep_keys and $drop_keys arrays to get
                 // a list of keys we need to revoke from the user
                 if ($keep_keys && $drop_keys) {
                     $revoke_keys = array_diff($drop_keys, $keep_keys);
                 } else {
                     $revoke_keys = $drop_keys;
                 }
                 // Revoke all the keys we previously calculated
                 if ($revoke_keys) {
                     $ks = new FOX_uKeyRing();
                     try {
                         $revoke_ok = $ks->revokeKey($user, $revoke_keys);
                     } catch (FOX_exception $child) {
                         throw new FOX_exception(array('numeric' => 7, 'text' => "FOX_uKeyRing revokeKeys exception", 'data' => array("user" => $user, "revoke_keys" => $revoke_keys), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                     }
                     if (!$revoke_ok) {
                         $keys_ok = false;
                     }
                 } else {
                     // Handle no keys to revoke
                     $keys_ok = true;
                 }
             }
             unset($user);
             // Because we are inside a transaction, we have to directly delete items from
             // the other class's db tables. If we deleted items using the other class's
             // functions, the other classes would remove them from their caches before we
             // could confirm all steps in the transaction were successful.
             // ============================================================================
             // Drop the group-user pairs from the group members table
             $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id));
             try {
                 $gm_ok = $db->runDeleteQuery(FOX_uGroupMember::_struct(), $args);
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 8, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
             }
             // Drop the group-key pairs from the group keyring table
             $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id));
             try {
                 $gk_ok = $db->runDeleteQuery(FOX_uGroupKeyRing::_struct(), $args);
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 9, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
             }
             // Drop the group from the group types table
             $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id));
             try {
                 $gt_ok = $db->runDeleteQuery(self::$struct, $args);
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 10, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
             }
             // Update the cache
             if ($keys_ok && $gm_ok !== false && $gk_ok !== false && $gt_ok) {
                 // Handle groups with no members and
                 // groups with no keys returning (int)0
                 try {
                     $commit_ok = $db->commitTransaction();
                 } catch (FOX_exception $child) {
                     throw new FOX_exception(array('numeric' => 11, 'text' => "commitTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                 }
                 if ($commit_ok) {
                     // Because we directly modified other class's db tables, we have to
                     // flush the cache for the affected classes
                     try {
                         $fox->cache->flushNamespace("FOX_uGroupMember");
                     } catch (FOX_exception $child) {
                         throw new FOX_exception(array('numeric' => 12, 'text' => "FOX_uGroupMember flushNamespace exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                     }
                     try {
                         $fox->cache->flushNamespace("FOX_uGroupKeyRing");
                     } catch (FOX_exception $child) {
                         throw new FOX_exception(array('numeric' => 13, 'text' => "FOX_uGroupKeyRing flushNamespace exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                     }
                     // Load, update, writeback
                     try {
                         self::loadCache();
                     } catch (FOX_exception $child) {
                         throw new FOX_exception(array('numeric' => 14, 'text' => "FOX_uGroupKeyRing getKeys exception", 'data' => array("user" => $group_id), 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                     }
                     unset($this->cache["ids"][$group["name"]]);
                     $cache_ok = self::saveCache();
                     return $cache_ok;
                 } else {
                     return false;
                 }
             }
         } else {
             // If we couldn't start a transaction, return false
             return false;
         }
         // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     } else {
         // @@@@@@ BEGIN TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
         try {
             $started_transaction = $db->beginTransaction();
         } catch (FOX_exception $child) {
             throw new FOX_exception(array('numeric' => 15, 'text' => "beginTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
         }
         if ($started_transaction) {
             // Because we are inside a transaction, we have to directly delete items from
             // the other class's db tables. If we deleted items using the other class's
             // functions, the other classes would remove them from their caches before we
             // could confirm all steps in the transaction were successful.
             // ============================================================================
             // Drop the group-key pairs from the group keyring table
             $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id));
             try {
                 $gk_ok = $db->runDeleteQuery(FOX_uGroupKeyRing::_struct(), $args);
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 16, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
             }
             // Drop the group from the group types table
             $args = array(array("col" => "group_id", "op" => "=", "val" => $group_id));
             try {
                 $gt_ok = $db->runDeleteQuery(self::$struct, $args);
             } catch (FOX_exception $child) {
                 throw new FOX_exception(array('numeric' => 17, 'text' => "DB delete exception", 'data' => $args, 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
             }
             // Update the cache
             if ($gk_ok !== false && $gt_ok) {
                 // Handle groups with no keys
                 // returning (int)0
                 try {
                     $commit_ok = $db->commitTransaction();
                 } catch (FOX_exception $child) {
                     throw new FOX_exception(array('numeric' => 18, 'text' => "commitTransaction exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                 }
                 if ($commit_ok) {
                     // Because we directly modified another class's db table, we
                     // have to flush the cache for the affected class
                     try {
                         $fox->cache->flushNamespace("FOX_uGroupKeyRing");
                     } catch (FOX_exception $child) {
                         throw new FOX_exception(array('numeric' => 2, 'text' => "FOX_uGroupKeyRing flushNamespace exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                     }
                     // Load, update, writeback
                     try {
                         self::loadCache();
                     } catch (FOX_exception $child) {
                         throw new FOX_exception(array('numeric' => 19, 'text' => "loadCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                     }
                     unset($this->cache["ids"][$group["name"]]);
                     try {
                         $cache_ok = self::saveCache();
                     } catch (FOX_exception $child) {
                         throw new FOX_exception(array('numeric' => 20, 'text' => "saveCache exception", 'file' => __FILE__, 'line' => __LINE__, 'method' => __METHOD__, 'child' => $child));
                     }
                     return $cache_ok;
                 } else {
                     return false;
                 }
             }
         } else {
             // If we couldn't start a transaction, return false
             return false;
         }
         // @@@@@@ END TRANSACTION @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     }
     // It might be possible to do this using a sophisticated query
     // Remove all keys granted by the group, from every user on the site, unless another group grants
     // the key, and the user is a member of that other group
     // ========================================================
     // DELETE kst
     // FROM user_keystore_table AS kst
     // INNER JOIN group_members_table AS gmt ON kst.user_id = gmt.user_id	    // user has to be a member of the deleted group
     // INNER JOIN group_keyring_table AS gkt ON gmt.group_id = gkt.group_id	    // key has to be granted by the deleted group
     // WHERE kst.key_id NOT IN (SELECT key_id
     //			    FROM group_keyring_table AS gkt2
     //			    INNER JOIN group_members_table AS gmt2 ON gkt2.group_id = gmt2.group_id
     //			    WHERE gmt2.group_id != gmt.group_id	    // where the key does not belong to another group
     //			    AND gmt2.user_id = gmt.user_id )	    // and the user is a member of that group
     // AND gkt.group_id = [this group]
     // AND gmt.group_id = [this group]
     // ...It also might be possible to do this using MySQL "foreign keys"
 }