/**
 * Process all the raw data up to the previous day.
 *
 * The primary key on the {project_usage_raw} table will prevent duplicate
 * records provided we process them once the day is complete. If we pull them
 * out too soon and the site checks in again they will be counted twice.
 */
function project_usage_process_daily()
{
    // Timestamp for begining of the previous day.
    $timestamp = project_usage_daily_timestamp(NULL, 1);
    $time_0 = time();
    watchdog('project_usage', 'Starting to process daily usage data for !date.', array('!date' => format_date($timestamp, 'custom', 'Y-m-d')));
    // Assign API version term IDs.
    $terms = array();
    foreach (project_release_get_api_taxonomy() as $term) {
        $terms[$term->tid] = $term->name;
    }
    $num_updates = 0;
    $query = db_query("SELECT DISTINCT api_version FROM {project_usage_raw} WHERE tid = 0");
    while ($row = db_fetch_object($query)) {
        $tid = array_search($row->api_version, $terms);
        db_query("UPDATE {project_usage_raw} SET tid = %d WHERE api_version = '%s'", $tid, $row->api_version);
        $num_updates += db_affected_rows();
    }
    $time_1 = time();
    $substitutions = array('!rows' => format_plural($num_updates, '1 row', '@count rows'), '!delta' => format_interval($time_1 - $time_0));
    watchdog('project_usage', 'Assigned API version term IDs for !rows (!delta).', $substitutions);
    // Asign project and release node IDs.
    $num_updates = 0;
    $query = db_query("SELECT DISTINCT project_uri, project_version FROM {project_usage_raw} WHERE pid = 0 OR nid = 0");
    while ($row = db_fetch_object($query)) {
        $pid = db_result(db_query("SELECT pp.nid AS pid FROM {project_projects} pp WHERE pp.uri = '%s'", $row->project_uri));
        if ($pid) {
            $nid = db_result(db_query("SELECT prn.nid FROM {project_release_nodes} prn WHERE prn.pid = %d AND prn.version = '%s'", $pid, $row->project_version));
            db_query("UPDATE {project_usage_raw} SET pid = %d, nid = %d WHERE project_uri = '%s' AND project_version = '%s'", $pid, $nid, $row->project_uri, $row->project_version);
            $num_updates += db_affected_rows();
        }
    }
    $time_2 = time();
    $substitutions = array('!rows' => format_plural($num_updates, '1 row', '@count rows'), '!delta' => format_interval($time_2 - $time_1));
    watchdog('project_usage', 'Assigned project and release node IDs to !rows (!delta).', $substitutions);
    // Move usage records with project node IDs into the daily table and remove
    // the rest.
    db_query("INSERT INTO {project_usage_day} (timestamp, site_key, pid, nid, tid, ip_addr) SELECT timestamp, site_key, pid, nid, tid, ip_addr FROM {project_usage_raw} WHERE timestamp < %d AND pid <> 0", $timestamp);
    $num_new_day_rows = db_affected_rows();
    db_query("DELETE FROM {project_usage_raw} WHERE timestamp < %d", $timestamp);
    $num_deleted_raw_rows = db_affected_rows();
    $time_3 = time();
    $substitutions = array('!day_rows' => format_plural($num_new_day_rows, '1 row', '@count rows'), '!raw_rows' => format_plural($num_deleted_raw_rows, '1 row', '@count rows'), '!delta' => format_interval($time_3 - $time_2));
    watchdog('project_usage', 'Moved usage from raw to daily: !day_rows added to {project_usage_day}, !raw_rows deleted from {project_usage_raw} (!delta).', $substitutions);
    // Remove old daily records.
    $seconds = variable_get('project_usage_life_daily', 4 * PROJECT_USAGE_WEEK);
    db_query("DELETE FROM {project_usage_day} WHERE timestamp < %d", time() - $seconds);
    $time_4 = time();
    $substitutions = array('!rows' => format_plural(db_affected_rows(), '1 old daily row', '@count old daily rows'), '!delta' => format_interval($time_4 - $time_3));
    watchdog('project_usage', 'Removed !rows (!delta).', $substitutions);
    watchdog('project_usage', 'Completed daily usage data processing (total time: !delta).', array('!delta' => format_interval($time_4 - $time_0)));
}
/**
 * Process all the raw data up to the previous day.
 *
 * The primary key on the {project_usage_raw} table will prevent duplicate
 * records provided we process them once the day is complete. If we pull them
 * out too soon and the site checks in again they will be counted twice.
 */
function project_usage_process_daily()
{
    // Timestamp for beginning of the previous day.
    $timestamp = project_usage_daily_timestamp(NULL, 1);
    $time_0 = microtime(TRUE);
    watchdog('project_usage', 'Starting to process daily usage data for !date.', array('!date' => format_date($timestamp, 'custom', 'Y-m-d')));
    // Assign project and release node IDs.
    $num_updates = 0;
    $result = db_query("SELECT DISTINCT name, version FROM {project_usage_raw} WHERE project_nid = 0 OR release_nid = 0");
    foreach ($result as $row) {
        $project_nid = db_query("SELECT nid FROM {project} WHERE name = :name", array(':name' => $row->name))->fetchField();
        if ($project_nid) {
            $release_nid = db_query("SELECT nid FROM {project_release} WHERE project_nid = :project_nid AND version = :version", array(':project_nid' => $project_nid, ':version' => $row->version))->fetchField();
            if ($release_nid) {
                $update_result = db_query("UPDATE {project_usage_raw} SET project_nid = :project_nid, release_nid = :release_nid WHERE name = :name AND version = :version", array(':project_nid' => $project_nid, ':release_nid' => $release_nid, ':name' => $row->name, ':version' => $row->version));
                $num_updates += $update_result->rowCount();
            }
        }
    }
    $time_1 = time();
    $substitutions = array('!rows' => format_plural($num_updates, '1 row', '@count rows'), '!delta' => format_interval($time_1 - $time_0));
    watchdog('project_usage', 'Assigned project and release node IDs to !rows (!delta).', $substitutions);
    // Move usage records with project node IDs into the daily table and remove
    // the rest.
    $result = db_query("INSERT INTO {project_usage_day} (timestamp, site_key, project_nid, release_nid, version_api, hostname) SELECT timestamp, site_key, project_nid, release_nid, version_api, hostname FROM {project_usage_raw} WHERE timestamp < :timestamp AND project_nid <> 0", array(':timestamp' => $timestamp));
    $num_new_day_rows = $result->rowCount();
    $result = db_query("DELETE FROM {project_usage_raw} WHERE timestamp < :timestamp", array(':timestamp' => $timestamp));
    $num_deleted_raw_rows = $result->rowCount();
    $time_2 = microtime(TRUE);
    $substitutions = array('!day_rows' => format_plural($num_new_day_rows, '1 row', '@count rows'), '!raw_rows' => format_plural($num_deleted_raw_rows, '1 row', '@count rows'), '!delta' => format_interval($time_2 - $time_1));
    watchdog('project_usage', 'Moved usage from raw to daily: !day_rows added to {project_usage_day}, !raw_rows deleted from {project_usage_raw} (!delta).', $substitutions);
    // Remove old daily records.
    $seconds = config_get('project_usage.settings', 'life_daily');
    $result = db_query("DELETE FROM {project_usage_day} WHERE timestamp < :timestamp", array(':timestamp' => REQUEST_TIME - $seconds));
    $time_3 = microtime(TRUE);
    $substitutions = array('!rows' => format_plural($result->rowCount(), '1 old daily row', '@count old daily rows'), '!delta' => format_interval($time_3 - $time_2));
    watchdog('project_usage', 'Removed !rows (!delta).', $substitutions);
    watchdog('project_usage', 'Completed daily usage data processing (total time: !delta).', array('!delta' => format_interval($time_2 - $time_0)));
}
/**
 * Compute the weekly summaries for the week starting at the given timestamp.
 *
 * @param $week_start_timestamp
 *   Timestamp indicating the start of the week for which stats should be
 *   calculated.
 */
function project_usage_process_weekly($week_start_timestamp)
{
    // Ensure the timestamp is a starting timestamp.
    $start = project_usage_weekly_timestamp($week_start_timestamp);
    $end = project_usage_weekly_timestamp($week_start_timestamp, 1);
    // Safety check to prevent processing of the current week's numbers, as the
    // week has not yet finished.
    if ($end > REQUEST_TIME) {
        return;
    }
    $start_date = format_date($start, 'custom', 'Y-m-d');
    $end_date = format_date(project_usage_daily_timestamp($end, -1), 'custom', 'Y-m-d');
    // Try to compute the usage tallies per project and per release. If there
    // is a problem--perhaps some rows existed from a previous, incomplete
    // run that are preventing inserts, throw a watchdog error.
    try {
        $sql = "INSERT INTO {project_usage_week_project} (nid, timestamp, version_api, count) SELECT project_nid as nid, :start, version_api, COUNT(DISTINCT site_key) FROM {project_usage_day} WHERE timestamp >= :start AND timestamp < :end AND project_nid <> 0 GROUP BY project_nid, version_api";
        $query_args = array(':start' => $start, ':end' => $end);
        $result = db_query($sql, $query_args);
        $project_count = $result->rowCount();
    } catch (PDOException $e) {
        $project_count = 0;
        $substitutions = array('@start' => $start_date, '@end' => $end_date);
        watchdog('project_usage', 'Weekly project tallies for the week of @start through @end already calculated. No data updated.', $substitutions);
    }
    try {
        $sql = "INSERT INTO {project_usage_week_release} (nid, timestamp, count) SELECT release_nid as nid, :start, COUNT(DISTINCT site_key) FROM {project_usage_day} WHERE timestamp >= :start AND timestamp < :end AND release_nid <> 0 GROUP BY release_nid";
        $query_args = array(':start' => $start, ':end' => $end);
        $result = db_query($sql, $query_args);
        $release_count = $result->rowCount();
    } catch (PDOException $e) {
        $release_count = 0;
        $substitutions = array('@start' => $start_date, '@end' => $end_date);
        watchdog('project_usage', 'Weekly release tallies for the week of @start through @end already calculated. No data updated.', $substitutions);
    }
    $substitutions = array('@projects' => format_plural($project_count, '1 project', '@count projects'), '@releases' => format_plural($release_count, '1 release', '@count releases'), '@start' => $start_date, '@end' => $end_date);
    watchdog('project_usage', 'Completed weekly usage data processing on @projects and @releases for the week of @start through @end.', $substitutions);
}