import csv, re, os, time
import boto, boto.s3

# Product is hard-coded as 2120 for now
PRODUCT = '2120'

os.system('clear')
print ''
print ' -----------------------------------------------------------'
print '| Boulder Amplifiers 2120 D/A Converter Serial # Assignment |'
print ' -----------------------------------------------------------'
print ''
print ''

# Read in the DB and store it in memory
serial_dict = {}
try:
    with open('serial_mac_db.csv') as csvfile:
        if not csv.Sniffer().has_header(csvfile.read(1024)):
            print 'The file serial_mac_db.csv does not have a valid CSV header, cannot continue.'
            raw_input('Press Enter to quit.\n')
            exit(-1)
        csvfile.seek(0)
        reader = csv.DictReader(csvfile)
        for row in reader:
            serial_dict[row['serial']] = [row['MAC'].lower(),row['product']]
except Exception, e:
    print 'Error opening file serial_mac_db.csv: ' + str(e)
    raw_input('Cannot continue, press Enter to quit.\n')
    exit(-1)

# Ask the user which serial address they are assigning
bad_serial = True
while bad_serial == True:
    serial = raw_input('Please enter the serial number that you would like to assign to the unit: ')
    # Serial numbers must be alphanumeric
    serial = re.sub(r'\W+', '', serial)

    serial_confirm = raw_input('Please confirm the serial number: ')
    # Serial numbers must be alphanumeric
    serial_confirm = re.sub(r'\W+', '', serial_confirm)

    if serial != serial_confirm:
        print 'Serial numbers do not match.\n'
    elif len(serial) < 1:
        print 'Serial number must be at least 1 character long.\n'
    else:
        bad_serial = False

# Check if the serial number is already being used
was_duplicate = False
if serial in serial_dict:

    # Re-assigning a serial with the same product is valid
    if serial_dict[serial][1] == PRODUCT:
        print '\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
        print '!!!! This serial number has already been assigned to a different unit with the MAC address: ' + serial_dict[serial][0] + ' !!!!'
        print '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
        reassign_confirm = raw_input('\n\nAre you sure that you want to reassign this serial number / MAC address combination? [y/N]: ')

        if len(reassign_confirm) < 1 or (reassign_confirm[0] != 'y' and reassign_confirm[0] != 'Y'):
            raw_input('Will not reassign serial number, press Enter to quit.\n')
            exit(-1)

        # Proceed with the already assigned MAC address
        was_duplicate = True
        mac = serial_dict[serial][0]
    # Re-assigning a serial with a different product ID is not valid
    else:
        print '\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'
        print '!!!! This serial number has already been assigned to a different product: ' + serial_dict[serial][1] + ' !!!!'
        print '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'

        raw_input('\n\nWill not reassign serial number, press Enter to quit.\n')
        exit(-1)

if was_duplicate == False:
    # If this is a new serial number, find the next available MAC address in the range
    found_unused = False

    # MAC range: 70:B3:D5:4B:D0:00 through 70:B3:D5:4B:DF:FF
    base_mac = 0x70B3D54BD000
    final_mac = 0x70B3D54BDFFF

    for x in range(base_mac, final_mac + 1):
        test_mac_hex = '%x' % x
        test_mac_string = ':'.join(re.findall('..', test_mac_hex))

        couldnt_find_unused = False
        for key, value in serial_dict.iteritems():
            if test_mac_string == value[0]:
                couldnt_find_unused = True
                break

        if couldnt_find_unused == False:
            found_unused = True
            mac = test_mac_string
            print '\nFound unused MAC address: ' + mac
            break

    if found_unused == False:
        raw_input('Unable to find an unused MAC address, cannot continue. Press Enter to quit.\n')
        exit(-1)

# We have our new serial number and MAC ready to go, call the assignment script with these values
print '\n\nProceeding with serial #' + serial + ' and MAC address ' + mac + '\n\n'
raw_input('Press Enter to continue.\n\n')

assign_ret = os.system('./assign-serial-num.sh ' + serial + ' ' + mac)

if assign_ret:
    raw_input('There was an error during serial number assignment. Press Enter to quit.\n')
    exit(-1)

# Add the new serial number / MAC address combo to the DB if it wasn't a duplicate
if was_duplicate == False:
    try:
        exists = open('serial_mac_db.csv', 'r')
        exists.close()
        with open('serial_mac_db.csv', 'a+') as csvfile:
            fieldnames = ['serial', 'MAC', 'product']
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
            writer.writerow({'serial': serial, 'MAC': mac, 'product': PRODUCT})

        # Back-up the local DB copy to Amazon S3
        AWS_ACCESS_KEY_ID = 'xxxxx'
        AWS_ACCESS_KEY_SECRET = 'xxxxx'

        # Destination bucket name
        bucket_name = 'amp-macs'

        # Destination directory name on S3
        dest_dir = '/'

        # Get bucket instance
        conn = boto.connect_s3(AWS_ACCESS_KEY_ID, AWS_ACCESS_KEY_SECRET)
        bucket = conn.create_bucket(bucket_name, location=boto.s3.connection.Location.DEFAULT)

        # Make a copy of the backup file locally
        sourcepath = 'serial_mac_db-' + time.strftime("%Y%m%d_%H%M%S", time.gmtime()) + '.csv'
        copy_ret = os.system('cp serial_mac_db.csv ' + sourcepath)
        if copy_ret:
            print '\n\n!!!! The serial number and MAC address have been assigned, but there was an error updating the database: '
            raw_input('\nPlease press Enter and reboot the unit to complete the procedure.\n')
            exit(-1)

        # Upload the new file to Amazon
        destpath = os.path.join(dest_dir, sourcepath)
        print 'Uploading file \'%s\' to Amazon S3 bucket \'%s\'' % (sourcepath, bucket_name)

        k = boto.s3.key.Key(bucket)
        k.key = destpath
        k.set_contents_from_filename(sourcepath)
    except Exception, e:
        print '\n\n!!!! The serial number and MAC address have been assigned, but there was an error updating the database: '
        print str(e)
        raw_input('\nPlease press Enter and reboot the unit to complete the procedure.\n')
        exit(-1)

raw_input('\n\nSerial number and MAC address have been assigned! Please press Enter and reboot the unit to complete the procedure.\n')
exit(0)
