#!/Lighty2Go/Python27/python
# -*- coding: utf-8 -*-

#####################################################################################
# NIST-developed software is provided by NIST as a public service. You may use, 
# copy and distribute copies of the software in any medium, provided that you 
# keep intact this entire notice. You may improve, modify and create derivative 
# works of the software or any portion of the software, and you may copy and 
# distribute such modifications or works. Modified works should carry a notice 
# stating that you changed the software and should note the date and nature of 
# any such change. Please explicitly acknowledge the National Institute of 
# Standards and Technology as the source of the software.
# 
# NIST-developed software is expressly provided “AS IS.” NIST MAKES NO WARRANTY 
# OF ANY KIND, EXPRESS, IMPLIED, IN FACT OR ARISING BY OPERATION OF LAW, 
# INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS 
# FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT AND DATA ACCURACY. NIST NEITHER 
# REPRESENTS NOR WARRANTS THAT THE OPERATION OF THE SOFTWARE WILL BE 
# UNINTERRUPTED OR ERROR-FREE, OR THAT ANY DEFECTS WILL BE CORRECTED. NIST DOES 
# NOT WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF THE SOFTWARE OR 
# THE RESULTS THEREOF, INCLUDING BUT NOT LIMITED TO THE CORRECTNESS, ACCURACY, 
# RELIABILITY, OR USEFULNESS OF THE SOFTWARE.
# 
# You are solely responsible for determining the appropriateness of using and 
# distributing the software and you assume all risks associated with its use, 
# including but not limited to the risks and costs of program errors, compliance 
# with applicable laws, damage to or loss of data, programs or equipment, and the 
# unavailability or interruption of operation. This software is not intended to 
# be used in any situation where a failure could cause risk of injury or damage 
# to property. The software developed by NIST employees is not subject to 
# copyright protection within the United States.
#####################################################################################

#
# script to print common procedures
#
# call as: get_common.py <key_value>
#
#	the key-value selects the instructions to return
#	a list of key values is in the variable common_index
#	For example: get_common.py clock
#		generates html for calibrating the system clock
#

import sys
#import ft_di_common
from ft_di_common import *
from set_up import *

#
# generate HTML table showing attached devices & mount points
#

import sys
from sys import stdin
import os
import datetime
import time
import hashlib
import subprocess
import re

os_info = os.uname()
ver = "Tool: @(#) get_common.py Version 1.4 created 04/26/18 at 10:11:19\n"+"OS: %s Version %s\n"%(
	os_info[0],os_info[2])

#print "VERSION",ver
def kmgi(n):
	k = n/1024.0
	m = k/1024.0
	g = m/1024.0
	t = g/1024.0
	if k < 1000:
		u = 'KiB'
		s = k
	elif m < 1000:
		u = 'MiB'
		s = m
	elif g < 1000:
		u = 'GiB'
		s = g
	else:
		u = 'TiB'
		s = t
	return "%.2f %s"%(s,u)
def kmg(n):
	k = n/1000.0
	m = k/1000.0
	g = m/1000.0
	t = g/1000.0
	if k < 1000:
		u = 'KB'
		s = k
	elif m < 1000:
		u = 'MB'
		s = m
	elif g < 1000:
		u = 'GB'
		s = g
	else:
		u = 'TB'
		s = t
	return "%.2f %s"%(s,u)
class dev:
	def __init__ (x):
		x.name = 'sdx'
		x.remove = False
		x.bytes = 0
		x.sectors = 0
		x.gigabytes = 0
		x.type = 'disk'
		x.mount = ''
 
# The get_view() method uses the linux lsblk command to retrieve and print a list of
# attached devices.
# view_v_form: if view_v_form is set to 'view', print the list of devices. if view_v_form
#              is set to 'viewform', also print a radio button for each device so it can be selected.
# device: if view_v_form is set to 'viewform' and a device is passed, autoselect the radio button
#         for device.
# list_ftlogs: if true, print the FT-LOGS device / allow a user to select it. If false, do not.
def get_view(view_v_form, device, list_ftlogs):
#	print ver

	p_lsblk = subprocess.Popen("lsblk -b",shell=True,stdout=subprocess.PIPE)

	#p_lsblk_out = p_lsblk.communicate()	
	#print p_lsblk_out[0]

	#if os_info[0] == 'Darwin':
	#	p_lsblk = '''
	#		NAME   MAJ:MIN RM          SIZE RO TYPE MOUNTPOINT
	#		loop0    7:0    0     681328640  1 loop /rofs
	#		sda      8:0    0 1000204886016  0 disk 
	#		??sda1   8:1    0     419430400  0 part 
	#		??sda2   8:2    0  999783358464  0 part 
	#		sr0     11:0    1     716681216  0 rom  /cdrom
	#		sdb      8:16   1     128909312  0 disk 
	#		sdc      8:32   1    7739768832  0 disk 
	#		??sdc1   8:33   1    7738520576  0 part /media/cftt/FT-LOGS-2
	#	
	#	'''
	#else:
	
	
	log_root = ''
	devices = {}
	log_dev_is = ''
#	for line in p_lsblk_out:
	for line in p_lsblk.stdout:
		if line.find("sd") >= 0:
			xx = re.sub ('  *',' ',line.strip())
			x = re.sub ('^.*sd','sd',xx)
			z = x.split(' ')

			# we found a mounted log drive!
			if z[-1] == '/Lighty2Go/media/cftt/FT-LOGS':
				log_root = z[-1]
				log_dev_is = z[0]
				
			if z[-1] == '/Lighty2Go/media/cftt/FT-LOGS' and list_ftlogs == True:
			# csr if z[-1] == '/media/cftt/FT-LOGS' and list_ftlogs == False:
				# we found a mounted log drive and list_ftlogs is false, so a) don't create a
				# dev obj and b) remove any references to it that might be in devices
				if z[0][0:-1] in devices: del devices[z[0][0:-1]]
			elif z[-1] == '[SWAP]':
				continue
			elif z[-1] == '/cdrom':
				del devices[z[0][0:-1]]
			else:
				obj = dev()
				obj.name = z[0]
				if z[2] == '1': obj.remove = True
				else: obj.remove = False
				obj.bytes = int(z[3])
				obj.sectors = obj.bytes/512
				obj.gigabytes = obj.bytes/1000/1000/1000	
				obj.type = z[5]
				if len(z) == 7: obj.mount = z[6]
				devices[z[0]] = obj
	
	if os_info[0] == 'Darwin':
		if os.access("/Lighty2Go/media/cftt/FT-LOGS/",os.F_OK):
			log_root = '/Lighty2Go/media/cftt/FT-LOGS/'
		else: log_root = '/Lighty2Go/media/cftt/FT-LOGS/'

	dev_tab_head_a = '''
	        <p>
	        <table width="30%" border="2" cellpadding="2" cellspacing="2">
	        <tbody>
	        <tr> '''

	dev_tab_head_b = '''	
	        <b>Device</b><b><br>
	        </b></th>
	        <th valign="top" align="center"><b>Size </b><b><br></th>
	        <th valign="top" align="center"><b>N Sectors </b><b><br></th>
	        <th valign="top" align="center"><b>Type </b><b><br></th>
	        <th valign="top" align="center"><b>Mount Point </b><b><br></th>
	        </b></tr>
	''' 

	if view_v_form == 'viewform':
		# if we're printing a form, need to add an extra column for the
		# radio buttons
		dev_tab_head = dev_tab_head_a + '<th colspan="2">' + dev_tab_head_b
	else: 
		dev_tab_head = dev_tab_head_a + '<th>' + dev_tab_head_b	

#	print 'os_info: %s'%(os_info[0])
#	print log_root
#	print "\nDrives"
	print dev_tab_head
	if os_info[0] == 'Linux':
		# print the dev info pulled back from lsblk -b
		device_keys = devices.keys()
		device_keys.sort()
		for obj in device_keys:
			print '<tr>'
			# if we're printing the form v no form, add radio buttons
			# if view_v_form == 'viewform': print '<td style="text-align: center;"><input type="radio" name="device" value="%s"></td>'%(devices[obj].name)
			if view_v_form == 'viewform':
				if devices[obj].name == device: # case: auto select this device/option
#					print '<td style="text-align: center;"><input type="radio" name="device" checked="checked" value="%s" id="%s" onClick=\'formatyourthumb_js_checks("%s");testinterface_js_checks("%s");\'></td>'%(devices[obj].name, devices[obj].name, devices[obj].name, devices[obj].name)
					print '<td style="text-align: center;"><input type="radio" name="device" checked="checked" value="%s" id="%s" onClick=\'get_common_get_view_check_selection("%s",'%(devices[obj].name, devices[obj].name, devices[obj].name)					
					if devices[obj].mount:  # case: this particular device is mounted
						print '"%s");\'></td>'%("mounted")
					else: # case: this particular device is not mounted
						if re.search("sd[a-z]\d",devices[obj].name): # case: this device is an unmounted partition; we're finished
							print '"%s");\'></td>'%("no")
						else: # case: this device is an unmounted drive
							# check: does this drive contain any file systems that are mounted?
							has_mounted_fs = False
							for this_obj in device_keys:
								if re.search(devices[obj].name+"\d", devices[this_obj].name): # case: this_obj is one of obj's file systems/partitions
									if devices[this_obj].mount: # is it mounted?
										has_mounted_fs = True # obj contains a file system that is mounted							
							if has_mounted_fs:
								print '"%s");\'></td>'%("has_mounted_fs")
							else:
								print '"%s");\'></td>'%("no")
				else: # case: leave this device/option unselected
#					print '<td style="text-align: center;"><input type="radio" name="device" value="%s" id="%s" onClick=\'formatyourthumb_js_checks("%s");testinterface_js_checks("%s");\'></td>'%(devices[obj].name, devices[obj].name, devices[obj].name, devices[obj].name)
					print '<td style="text-align: center;"><input type="radio" name="device" value="%s" id="%s" onClick=\'get_common_get_view_check_selection("%s",'%(devices[obj].name, devices[obj].name, devices[obj].name)
					if devices[obj].mount: # case: this particular device is mounted
						print '"%s");\'></td>'%("mounted")
					else: # case: this particular device is not mounted
						if re.search("sd[a-z]\d",devices[obj].name): # case: this device is an unmounted partition; we're finished
							print '"%s");\'></td>'%("no")
						else: # case: this device is an unmounted drive
							# check: does this drive contain any file systems that are mounted?
							has_mounted_fs = False
							for this_obj in device_keys:
								if re.search(devices[obj].name+"\d", devices[this_obj].name): # case: this_obj is one of obj's file systems/partitions
									if devices[this_obj].mount: # is it mounted?
										has_mounted_fs = True # obj contains a file system that is mounted							
							if has_mounted_fs:
								print '"%s");\'></td>'%("has_mounted_fs")
							else:
								print '"%s");\'></td>'%("no")
								
			print '<td>%s</td> <td align="Right">%s</td> <td>%s</td> <td>%s</td> <td>%s</td>'%(
			devices[obj].name,
#			'{:,}'.format(devices[obj].gigabytes),
			" %s/%s"%(
			kmg (devices[obj].bytes),
			kmgi (devices[obj].bytes)) + ' &nbsp;({:,} B)'.format(devices[obj].bytes),
			'{:,}'.format(devices[obj].bytes/512),
			devices[obj].type,
			devices[obj].mount)
			print '</tr>'
	else:
		# not on Linux; must be on Mac. Can't pull back device info so 
		# print out some example device info
		print '''
<tr>
<td style="text-align: center;"><input type="radio" name="device" value="sda"></td>
<td>sda</td> <td align="Right"> 63.96 MB/61.00 MiB &nbsp;(63,963,136 B)</td> <td>124,928</td> <td>disk</td> <td></td>
</tr>
<tr>
<td style="text-align: center;"><input type="radio" name="device" value="sdb"></td>
<td>sdb</td> <td align="Right"> 75.50 MB/72.00 MiB &nbsp;(75,497,472 B)</td> <td>147,456</td> <td>disk</td> <td></td>
</tr>
<tr>
<td style="text-align: center;"><input type="radio" name="device" value="sdc"></td>
<td>sdc</td> <td align="Right"> 53.48 MB/51.00 MiB &nbsp;(53,477,376 B)</td> <td>104,448</td> <td>disk</td> <td></td>
</tr>
<tr>
<td style="text-align: center;"><input type="radio" name="device" value="sdd"></td>
<td>sdd</td> <td align="Right"> 2.05 GB/1.91 GiB &nbsp;(2,048,901,120 B)</td> <td>4,001,760</td> <td>disk</td> <td></td>
</tr>
<tr>
<td style="text-align: center;"><input type="radio" name="device" value="sdd1"></td>
<td>sdd1</td> <td align="Right"> 2.05 GB/1.91 GiB &nbsp;(2,048,900,096 B)</td> <td>4,001,758</td> <td>part</td> <td></td>
</tr>
<tr>
<td style="text-align: center;"><input type="radio" name="device" value="sde"></td>
<td>---</td> <td align="Right"><i>NOTE: This table filled with example data!!!</i></td><td> ---</td><td> ---</td><td> </td>
</tr>
               '''

	print '</tbody></table>'
	if log_dev_is != '':
		print '<p>Formatted log device /dev/%s mounted on /media/cftt/FT-LOGS<p>\n'%(
			log_dev_is)
#	if os.access("/tmp/FT-LOGS",os.F_OK):
#		print "Logs:",log_root
#		if os.path.isdir(log_root): print "is a dir"
#		else: print "not a dir"
#		dlist = os.listdir(log_root)
#	else: dlist = []
#	print
#	if len(dlist) == 0:
#		print "<p>No attached devices visible.<br>"
#	else:
#		print "Attached Devices"
#		for dir in dlist:
#			if os.path.isdir(log_root+'/'+dir) and dir[0] != '.':
#				if os.access(log_root+'/'+dir+'/'+"test-configuration.txt",os.F_OK):
#					cf = open(log_root+'/'+dir+'/'+"test-configuration.txt","r")
#					tool = cf.readline()[9:].strip()
#					version = cf.readline()[12:].strip()
#					print "Testing: ",tool,version," dir:",dir

stub = '''
<p>
THIS IS A STUB.
No procedure for %(action)s defined
<p>
'''

#mount_fs = '''
#	<p> Working on it
#'''
common_index = {
	'clock' : calibrate_clock,
	'setup-src' : media_setup,
	'mount' : mount_fs,
	'view' : view_dev,
	'viewform' : "",	
	'log' : format_log,
	'rmsetup' : setup_rm,
	'faultysectors' : create_faulty_sectors,
	'cfttdi' : sample_session,
	'partition' : create_partition
}

#print sys.argv,len(sys.argv)
if len(sys.argv) > 1:select = sys.argv[1]
else: select = ''

# case: get_common.py was called with a value for device 
if len(sys.argv) > 2:device = sys.argv[2]
else: device = ''

list_ftlogs = False # by default, don't print the FT-LOGS device / don't allow a user to select it
if len(sys.argv) > 3: # case: get_common.py was called with a value for list_ftlogs
	if sys.argv[3] == "true": # if "true" was passed, print the FT-LOGS device inline with 
		list_ftlogs = True      # the rest of the devices
    
if select in common_index:
	print common_index[select]
	if select == 'view': get_view('view', '', list_ftlogs)
	elif select == 'viewform': get_view('viewform', device, list_ftlogs)
elif select == 'index':
	ix = common_index.keys()
	ix.sort()
	for key in ix: print '<br>'+key
else:
	print stub%{'action':select}
	get_view('view', '', list_ftlogs)

