#!/usr/bin/python

import sys
import os
import getopt
import psycopg2
import time

def command_line_error(msg):
	sys.stderr.write('%s: %s\n' % (progname, msg))
	sys.stderr.write('run %s with no arguments for usage\n' % progname)
	return

progname = os.path.basename(sys.argv[0])
save_one_flag = False
list_only_flag = False

if len(sys.argv) == 1:
	print """
usage: %s [-l] [-1] <IP address> <file ID> <month> <day> <user ID>'

Fixes a download count using the method described in the NITRC Internal 
wiki page "Fix_a_Download_Count_Details".  This script does not log the 
alteration or update the site metrics or reporting tables.

Arguments (all required):

    IP address -- the IP address of the downloads to remove

    file ID -- the file ID of the downloads

    month -- the month of the downloads (in the form YYYYMM, as stored in 
             frs_dlstats_file.month)

    day -- the day of the month of the downloads

    user ID -- the numeric user ID of the downloads

Options:

    -l -- list what would be done, but don't actually alter the download 
          counts

    -1 -- leave one row in frs_dlstats_file

References:

    http://www.nitrc.org/plugins/mwiki/index.php/nitrcint:Fix_a_Download_Count

    http://www.nitrc.org/plugins/mwiki/index.php/nitrcint:AlteredFRSCounts

    http://www.nitrc.org/plugins/mwiki/index.php/nitrcint:Fix_a_Download_Count_Details

23 July 2009 ch
""" % progname
	sys.exit(1)

try:
	(opts, args) = getopt.getopt(sys.argv[1:], '1l')
except getopt.error, data:
	command_line_error(str(data))
	sys.exit(1)

for (option, value) in opts:
	if option == '-1':
		save_one_flag = True
	if option == '-l':
		list_only_flag = True

if len(args) != 5:
	command_line_error('wrong number of non-option arguments')
	sys.exit(1)

(ip_address, file_id, month, day, user_id) = args

try:
	file_id = int(file_id)
except ValueError:
	command_line_error('bad value "%s" for file ID' % file_id)
	sys.exit(1)

try:
	month = int(month)
except ValueError:
	command_line_error('bad value "%s" for month' % month)
	sys.exit(1)

try:
	day = int(day)
except ValueError:
	command_line_error('bad value "%s" for day' % day)
	sys.exit(1)

try:
	user_id = int(user_id)
except ValueError:
	command_line_error('bad value "%s" for user ID' % user_id)
	sys.exit(1)

db = psycopg2.connect(user='gforge')
c = db.cursor()

query_params = {'ip_address': ip_address, 
                'file_id': file_id, 
                'month': month, 
                'day': day, 
                'user_id': user_id}

print '------------------------------------------------------------------'
print 'copying offending records to frs_dlstats_file_removed'
print

query = """INSERT INTO frs_dlstats_file_removed 
                  (SELECT *
                     FROM frs_dlstats_file
                    WHERE ip_address = %(ip_address)s 
                      AND file_id = %(file_id)s 
                      AND month = %(month)s 
                      AND day = %(day)s 
                      AND user_id = %(user_id)s)"""

print c.mogrify(query, query_params)
print

c.execute(query, query_params)
n_copied = c.rowcount

print 'copied %d records' % n_copied
print

print '------------------------------------------------------------------'
print 'removing offending records from frs_dlstats_file'
print

query = """DELETE FROM frs_dlstats_file
            WHERE ip_address = %(ip_address)s 
              AND file_id = %(file_id)s 
              AND month = %(month)s 
              AND day = %(day)s 
              AND user_id = %(user_id)s"""

print c.mogrify(query, query_params)
print

c.execute(query, query_params)
n_deleted = c.rowcount

print 'deleted %d records' % n_deleted
print

if n_copied != n_deleted:
	fmt = '%s: ERROR: n_copied (%d) != n_deleted (%d)\n'
	sys.stderr.write(fmt % (progname, n_copied, n_deleted))
	sys.stderr.write('%s: bailing out\n' % progname)
	c.close()
	db.rollback()
	sys.exit(1)

if save_one_flag:
	print '------------------------------------------------------------------'
	print 'creating one record in frs_dlstats_file'
	print
	query = """INSERT INTO frs_dlstats_file (ip_address, 
	                                         file_id, 
	                                         month, 
	                                         day, 
	                                         user_id)
	           VALUES (%(ip_address)s, 
	                   %(file_id)s, 
	                   %(month)s, 
	                   %(day)s, 
	                   %(user_id)s)"""
	print c.mogrify(query, query_params)
	print
	c.execute(query, query_params)
	if c.rowcount == 1:
		print 'inserted %d record' % c.rowcount
	else:
		print 'inserted %d records' % c.rowcount
	print
	if c.rowcount != 1:
		sys.stderr.write('%s: ERROR: inserted %d records\n' % (progname, 
		                                                       c.rowcount))
		sys.stderr.write('%s: bailing out\n' % progname)
		c.close()
		db.rollback()
		sys.exit(1)

print '------------------------------------------------------------------'
print 'updating frs_dlstats_filetotal_agg'
print

query = """UPDATE frs_dlstats_filetotal_agg
              SET downloads = (SELECT COUNT(*)
                                 FROM frs_dlstats_file
                                 WHERE file_id = %(file_id)s) 
            WHERE file_id = %(file_id)s"""

print c.mogrify(query, query_params)
print
c.execute(query, query_params)
if c.rowcount == 1:
	print 'updated %d row' % c.rowcount
else:
	print 'updated %d row' % c.rowcount
print

if c.rowcount != 1:
	sys.stderr.write('%s: ERROR: updated %d rows\n' % (progname, c.rowcount))
	sys.stderr.write('%s: bailing out\n' % progname)
	c.close()
	db.rollback()
	sys.exit(1)

c.close()

print '------------------------------------------------------------------'
print 'summary'
print ''

if list_only_flag:
	print 'dummy run complete; rolling back database'
	print ''
	db.rollback()
else:
	print 'committing changes'
	print ''
	db.commit()
	print 'ran %s %s using:' % (progname, time.strftime('%Y-%m-%d %H:%M %Z'))
	print ''
	print '    IP address: %s' % ip_address
	print '       file ID: %d' % file_id
	print '         month: %d' % month
	print '           day: %d' % day
	print '       user ID: %d' % user_id
	print ''
	if save_one_flag:
		print '%d rows removed, 1 added' % n_deleted
	else:
		print '%d rows removed, 0 added' % n_deleted
	print ''

db.close()

sys.exit(0)

# eof
