#!/usr/bin/python

'''Usage: %s target, imei, encodeKey, lrauvPath, username
send "outgoing" files to the indicated target
'''

import os
import sys
import time
import socket
import paramiko
import smtplib
import traceback

from curses.ascii import isdigit
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders


# TODO use subprocess module to control octave for queueOutgoing until the
# functionality of that m-script is ported to python.

def main():
    '''The main program'''
    target, imei, encodeKey, lrauvPath, username = parseCommandline()
    # TODO migrate to argparse and configparse
    try: 
        sendViaSFTP(target, lrauvPath, username)
    except socket.error, e:
        print 'socket.error: ', e
        print 'Could not connect to {0} via network.'.format(target)
        # TODO try connecting and sending file via Freewave?
        sendViaIridium(target, imei, encodeKey)
    except Exception, e: 
        raise e

def parseCommandline():
    '''Analyze command line arguments'''
    if( len( sys.argv ) > 1 ):
        target = sys.argv[1]
    else:
        print("Error: Must specify a target")
        quit()
    if( len( sys.argv ) > 2 ):
        imei= sys.argv[2]
        if imei == "None":
            imei = None
    else:
        imei=None
    if( len( sys.argv ) > 3 ):
        encodeKey= sys.argv[3]
        if encodeKey == "None":
            encodeKey = None
    else:
        imei=None
    if( len( sys.argv ) > 4 ):
        lrauvPath= sys.argv[4]
    else:
        lrauvPath="/mnt/mmc/LRAUV"
    if( len( sys.argv ) > 5 ):
        username= sys.argv[5]
    else:
        username="root"
    return target, imei, encodeKey, lrauvPath, username
    
def sendViaSFTP(host, lrauvPath, username='root', port=22):
    # figure out which files to copy
    localdir = os.path.join('Tools','HFRadarModel','outgoing', host)
    filesToCopy = [os.path.join(localdir, fn) 
            for fn in os.listdir(localdir) 
            if len(fn) == 10 and isdigit(fn[0])]
    filesToCopy.sort()
    # set up transport layer
    transport = paramiko.Transport((host, port))
    private_key_path = os.path.expanduser('~/.ssh/id_rsa')
    rsa_key = paramiko.RSAKey.from_private_key_file(private_key_path)
    transport.connect(username=username, pkey=rsa_key)
    cex = transport.get_exception() # Why do I have to do this explicitly?
    if cex: 
        transport.close()
        raise cex
###    raise socket.error # to force test iridium sending
    sftp = paramiko.SFTPClient.from_transport(transport)
    # put files on vehicle
    remotedir = os.path.join(lrauvPath,'Data','HFRadarModel')
        # TODO test and mkdir
        #sftp.mkdir(remoteDir)
    for src in filesToCopy:
        fn = os.path.basename(src)
        dst = os.path.join(remotedir, fn)
        atts = sftp.put(src, dst)
        if atts.st_size == 208: # TODO check md5sum as well...
            print 'Moved {0}, {1}, {2}'.format(fn, atts.st_size, atts.st_atime)
            # TODO archive in 'sent', same as Iridium
            os.remove(src)
    # remove 'extra' files on vehicle (why limit to 49?)
        #files = filter( validFileFilter, sftp.listdir(remotedir) )
    remoteFiles = [fn for fn in sftp.listdir(remotedir) 
            if (len(fn) is 10 and fn.isdigit())]
    remoteFiles.sort() # in-place list sort
    while( len(remoteFiles) > 49 ):
        fileToRemove = remoteFiles.pop(0)
        sftp.remove(os.path.join(remotedir, fileToRemove))
        print 'Removing old {0}'.format(fileToRemove)

def validFileFilter(name):
    return len(name)==10 and name.isdigit()

def sendViaIridium( target, imei, encodeKey ):
    localdir = "Tools/HFRadarModel/outgoing/%s" % target
    filesToSend = filter( validFileFilter, os.listdir(localdir) )
    filesToSend.sort()
    for file in filesToSend:
        localfile = "%s/%s" %( localdir, file )
        targetfile = "Data/HFRadarModel/%s" % file
        encodeCmd = "Tools/encode2Send.py %s %s %s" % ( localfile, targetfile, encodeKey )
        os.system(encodeCmd)
        sbdfile = "%s.000.sbd" % file
        send_mail('tethysadmin@mbari.org',
                ['data@sbd.iridium.com','tethysadmin@mbari.org'],
                imei,file,[sbdfile])
        # TODO make all of these above config variables...
        localfileBackup = "%s/%s.sent" %( localdir, file )
        os.rename(localfile,localfileBackup)
        os.remove(sbdfile)
        
def send_mail(send_from, send_to, subject, text, files=[], server="localhost"):
  assert type(send_to)==list
  assert type(files)==list

  msg = MIMEMultipart()
  msg['From'] = send_from
  msg['To'] = COMMASPACE.join(send_to)
  msg['Date'] = formatdate(localtime=True)
  msg['Subject'] = subject

  msg.attach( MIMEText(text) )

  for f in files:
    part = MIMEBase('application', "octet-stream")
    print( f)
    part.set_payload( open(f,"rb").read() )
    Encoders.encode_base64(part)
    part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f))
    msg.attach(part)

  smtp = smtplib.SMTP(server)
  smtp.set_debuglevel(1)
  smtp.sendmail(send_from, send_to, msg.as_string())
  print "Sent email from %s to %s with msg=%s" % (send_from, send_to, msg.as_string())
  smtp.close()

if __name__ == '__main__':
    main()
