#!/usr/bin/python


import sys
import Drobo
import time
import getopt
import string
import os
import types
import textwrap

toprint = ("config", "capacity", "protocol", "settings", "slots",
           "firmware", "status", "options", "luns")

def usage():
   print "\nUsage: drobom [options] <command> [ arguments... ] \n"
   print " drobo management interface, version: %s\n" % Drobo.VERSION
   print "options may be one of: "
   print " -c, --command <command>\tcommand to run."
   print " -d, --device <device>\tpick a specific disk, rather than scan"
   print " -h, --help \t\tprint this help text"
   print " -v, --verbose <debug_code>\t bit-field, default is 0 (off) "
   print "\t1  - General"
   print "\t2  - Hardware Dialog"
   print "\t4  - Initiation"
   print "\t8  - DMP layer"
   print "\t16 - Detection"
   print "\t63 - All of the above"
   print "\t128- Simulate presence of Drobo for testing\n"
   print " -V, --version\treport version of drobo-utils."
   print "\ncommand is one of: "
   print "\tblink\tidentify the drobo by making the lights blink"
   print "\tdiag \tdump diagnostics file into /tmp directory"
   print "\tdiagprint <file>  - print diagnostic file to stdout"
   print "\tformat\tPrepares a script to format LUNS from a device. Arguments:"
   print "\t\t<fstype>\tfile system type.  One of: ext3, ntfs, FAT32"
   print "\t\t<confirmation>\tSpecify 'PleaseEraseMyData' if you"
   print "\t\t\t\treally mean it"
   print "\t\tNote: This places a script in /tmp, which you must run."
   print "\tfwcheck\tquery drobo.com for updates to firmware for the given Drobo"
   print "\tfwload\tload a specific firmware for the given Drobo. Arguments:"
   print "\t\t<fwimage>\tthe firmware file to load."
   print "\tfwupgrade\tupgrade the firmware to the latest and greatest,"
   print "\t\t\trecommended by DRI"
   print "\tinfo <options>\tprint information on a Drobo"
   print "\t\t<options>\tcomma separated list of:"
   opt_str = ', '.join(toprint)
   for line in textwrap.wrap(opt_str, 40):
      print "\t\t\t\t" + line
   print "\tlist \tshow device files for all Drobos found."
   print "\tname <name> \tSet Drobo name"
   print "\tsettime\tsync Drobo's clock to UTC"
   print "\tsetlunsize\tSet the size of LUNS on device. Arguments:"
   print "\t\t<sz>\tinteger number of TiB to set the lunsize to"
   print "\t\t<confirmation>\tSpecify 'PleaseEraseMyData' if you"
   print "\t\t\t\treally mean it"
   print "\t\tNote: After execution, Drobo reboots, wait a few minutes"
   print "\t\t\tbefore accessing again"
   print "\tshutdown\tShutdown drobo"
   print "\t\t\t(DRI calls this 'standby'. Shutdown also umounts.)"
   print "\tstatus\treport how is the Drobo doing"
   print "\tview\tstart up a management dashboard GUI"


def printconfig(d):
  config=d.GetSubPageConfig()
  if Drobo.DEBUG & Drobo.DBG_Chatty:
    print 'query config result: '
    print config
    print 'max lun size is: ', config[2]
    print
  else:
    print config

def printcapacity(d):
  c=d.GetSubPageCapacity()
  if Drobo.DEBUG & Drobo.DBG_Chatty:
    print 'query capacity result:'
    print c
    print 'Physical space... used: ',  c[1] , ' free: ' , c[0],  ' Total: ', c[2]
    print
  else:
    print c


def printprotocol(d):
  protocol=d.GetSubPageProtocol()
  if Drobo.DEBUG & Drobo.DBG_Chatty:
    print 'query protocol version result: '
    print protocol 
    print
  else:
    print protocol

def printsettings(d):
  settings=d.GetSubPageSettings()
  if Drobo.DEBUG & Drobo.DBG_Chatty:
    print 'query settings result:' 
    print settings
    print 'Drobo time is', time.ctime(settings[0])
    print
  else:
    print settings
  
def printslots(d):
  slotinfo=d.GetSubPageSlotInfo()
  if Drobo.DEBUG & Drobo.DBG_Chatty:
    print 'query slotinfo result:  number of slots:', d.slot_count
  print slotinfo
  
def printfirmware(d):
  firmware=d.GetSubPageFirmware()
  if Drobo.DEBUG & Drobo.DBG_Chatty:
    print 'query firmware result:' 
    print firmware
    print 'drobo says firmware revision: ', str(firmware[0]), '.', str(firmware[1]), '(', str(firmware[2]), ') was built: ', firmware[5]
    print
  else:
    print firmware
  
def printstatus(d):
  status=d.GetSubPageStatus()
  if Drobo.DEBUG & Drobo.DBG_Chatty:
    print 'query status result:' 
    print status
    print
  else:
    print status
  
def printoptions(d):
  options=d.GetSubPageOptions()
  if Drobo.DEBUG & Drobo.DBG_Chatty:
    print 'query options result:'
    print options
  else:
    print options
  
def printluns(d):
  luninfo=d.GetSubPageLUNs()
  if Drobo.DEBUG & Drobo.DBG_Chatty:
    print 'query luninfo result:'
    for i in luninfo:
       print i
    print
  else:
    for i in luninfo:
       print i
 
def info(d,choices):
  if debug & Drobo.DBG_Chatty:
    print '---------------------------------------------------------'
    print 'Info about Drobo ' ,
    print '   Name:', d.GetSubPageSettings()[2],
    print '      Devices:', ':'.join(d.char_devs)
    print '---------------------------------------------------------'

  for c in choices:
     eval( "print" + c + "(d)"  )

  if debug & Drobo.DBG_Chatty:
    print '---------------------------------------------------------'

def update(pct):
  print "write is %2d%% done." % ( pct )


# Mainline...

if ( len(sys.argv) == 1 ) or (sys.argv[1] == 'help'):
  usage()
  sys.exit()

device=None
cmd=None
#default is chatty
debug=1

try:
   opts, args = getopt.getopt(sys.argv[1:], "c:d:hv:V", \
       ["command=", "device=", "help", "verbosity=", "version"])
except getopt.GetoptError, err:
   usage()
   sys.exit(2)


for o, a in opts:
        if o in ("-c", "--command"):
	    cmd = a
        elif o in ("-d", "--device"):
	    device=a
        elif o in ("-h", "--help"):
            usage()
            sys.exit()
        elif o in ("-v", "--verbosity", "--verbose") :
            debug = int(a)
        elif o in ("-V", "--version" ):
            print Drobo.VERSION
            sys.exit()
        else:
            assert False, "unhandled option"

if cmd==None :
  if (len(args) == 0):
     usage()
     sys.exit()
  cmd=args[0]

if (os.geteuid() != 0) and (debug & Drobo.DBG_Simulation == 0):
   print "Please try again as root."
   sys.exit()

l = Drobo.DiscoverLUNs(debug)
if not l:
   print "No Drobos discovered"
   sys.exit()

# find the requested Drobo...
match=False
if device != None:
   for i in l:
      if type(i) == types.ListType:
         for j in i:
            if device in j:
               l=[i]
               match=True
      elif device in i:
         l=[i]
         match=True

if device != None and not match:
   print "given device: %s, is not a Drobo" % d
   sys.exit()
 
if cmd == 'list':
   print ' '.join(map(lambda x: ':'.join(x) , l ))
   sys.exit()

if debug & Drobo.DBG_Detection:
   print "found ", l

for u in l:
  d=Drobo.Drobo(u,debug)
  #assert d is a valid drobo object...

  if cmd == "blink":
     d.Blink() 

  elif cmd == "diag":
     f=d.dumpDiagnostics()
     print "diagnostics in ", f

  elif cmd == "diagprint":
     print d.decodeDiagnostics( args[1] )

  elif cmd == "format":
     if len(args) < 3 :
        print 'This is guaranteed to erase your disk, so you must say: PleaseEraseMyData'
        sys.exit()

     if args[2] != 'PleaseEraseMyData':
        print 'This is guaranteed to erase your disk, so you must say: PleaseEraseMyData'
        sys.exit()

     print 'You asked nicely, so I will format %s as you requested' % args[1]
     d.format_script(args[1])
     print 'OK, I built the script but nothing is erased yet...'
     print 'If you are really sure, go ahead and do: sh /tmp/fmtscript'

  elif cmd == 'fwcheck':
     tuple=d.PickLatestFirmware()
     print tuple[3]

  elif cmd == 'fwload':
     if d.PickFirmware(args[1]):
       d.writeFirmware(update)
     d.Sync()

  elif cmd == 'fwupgrade':
     if d.updateFirmwareRepository():
       d.writeFirmware(update)
       d.Sync()

  elif cmd == 'info':
     if len(args) > 1:
       toprint=args[1].split(',')
     info(d,toprint)

  elif cmd == "name": 
    d.Sync(args[1])          

  elif cmd == "setlunsize": 
     lunsize=int(args[1])

     if lunsize not in (1, 2, 4, 8, 16):
        print 'lun size needs to be 1, 2, 4, 8, or 16 TiB; %d is invalid' % lunsize
        sys.exit()

     if lunsize > 2:
        print 'WARNING: lun size > 2 TiB known not work in many cases under Linux' 

     if len(args) < 3 :
        print 'This is guaranteed to erase your disk, so you must say: PleaseEraseMyData'
        sys.exit()

     if args[2] != 'PleaseEraseMyData':
        print 'This is guaranteed to erase your disk, so you must say: PleaseEraseMyData'
        sys.exit()

     print 'You asked nicely, so I will set the lunsize to %d as you requested' % lunsize
     d.SetLunSize(lunsize)
     print 'Done... Drobo is likely now rebooting.  In a few minutes, it will come back with the new LUN size.'

  elif cmd == "set": 
     what = args[1]
     if what == "time" :
        d.Sync()
     else:
        options=d.GetSubPageOptions()
        if args[1] in options.keys():
           # TODO: are all options integers? no..
           if args[2] == 'True':
               value=True
           elif args[2] == 'False':
               value=False
           elif args[1] == 'IPAddress' or args[1] == 'NetMask':
               value=args[2]
           else:
               value=int(args[2])

           options[args[1]]=value
        else:
           print 'option not present: ', args[1]

        d.SetOptions( options ) 

  elif cmd == "settime": 
     d.Sync()          

  elif cmd == "shutdown":
     d.Standby() 
   
  elif cmd == "status":
     c=d.GetSubPageCapacity()
     n=d.GetSubPageSettings()
     if c[2] > 0 :
         pfull = 100 * ((c[1]+1.0)/c[2])
     else:
         print "firmware too old to report capacity properly... or the drobo is empty..."
         pfull = -1

     m=':'.join(d.DiscoverMounts())
     if m == "":
       m="-"
     if n[2] == "":
       n[2] = "-"
     print "%s %s %s %02d%% full - %s" % ( ':'.join(d.char_devs), m, n[2], \
          pfull, d.GetSubPageStatus() )

  elif cmd == "time":
     settings=d.GetSubPageSettings()
     print "Drobo says it is:", time.ctime(settings[0])

  elif cmd == "view":
     import sys,subprocess
     try: 
       from PyQt4 import QtGui
       from PyQt4 import QtCore
       from DroboGUI import DroboGUI
     except:
       print "QT support missing, no GUI possible"

     # fire up a GUI for the given LUN, stays foreground...
     app = QtGui.QApplication(sys.argv)
     tb = DroboGUI(d)
     tb.show()
     app.exec_()

  else:
     usage()
     print "Unknown Command: ", cmd
