#!/usr/bin/python

import sys
import os
if os.path.exists('/usr/share/pyshared'):
    sys.path.append('/usr/share/pyshared')
import ast
from optparse import OptionParser
from dcbnetlink import DcbController
from collections import defaultdict
from subprocess import Popen, PIPE
from tc_wrap import *

DCB_CAP_DCBX_VER_IEEE = 0x8
NUMBER_OF_QCN_PARAMS = 12
NUMBER_OF_QCN_STATS = 10
NUMBER_OF_TCS = 8

list_params = ["rpg_enable", "rppp_max_rps", "rpg_time_reset", "rpg_byte_reset", "rpg_threshold", "rpg_max_rate", "rpg_ai_rate", "rpg_hai_rate", "rpg_gd", "rpg_min_dec_fac", "rpg_min_rate", "cndd_state_machine"]
list_statistics = ["rppp_rp_centiseconds", "rppp_created_rps", "ignored_cnm", "estimated_total_rate", "cnms_handled_successfully", "min_total_limiters_rate", "max_total_limiters_rate"]


class QCN:
    def get(self):
	raise "Not implemented"
    def set(self, qcn):
	raise "Not implemented"
    def getstats(self):
	raise "Not implemented"


class QCNNL(QCN):
    def __init__(self,ctrl):
	self.ctrl = ctrl
    def get(self):
	return ctrl.get_ieee_qcn()

    def set(self, qcn):
	ctrl.set_ieee_qcn(qcn)

    def get_statistics(self):
	return ctrl.get_ieee_qcnstats()

class QCNSysfs(QCN):
    def __init__(self, path):
	self.path = path

    def get(self):
	qcn_params = []
	f = open(self.path, "r")
	for item in f.read().split():
		if (item == "priority" or item == "|priority"):
			lastItem = item
			continue
		elif (item == ":" or item == "|"):
			continue
		elif (lastItem == "priority" or lastItem == "|priority"):
			lastItem = ""
			continue
		qcn_params.append(int(item))
	f.close()
	return qcn_params

    def set(self, qcn):
	f = open(self.path, "w")
	f.write(" ".join(str(r) for r in qcn))
	f.close()

class QCNStatsSysfs(QCN):
    def __init__(self, path):
	self.path = path

    def get_statistics(self):
	qcn_stats = []
	f = open(self.path, "r")
	for item in f.read().split():
		if (item == "priority" or item == "|priority"):
			lastItem = item
			continue
		elif (item == ":" or item == "|"):
			continue
		elif (lastItem == "priority" or lastItem == "|priority"):
			lastItem = ""
			continue
		qcn_stats.append(int(item))
	f.close()
	return qcn_stats

def pretty_print_qcn(qcn, values):
	# Deal with an additions of qcn parameters which were not added to the tool #
	additions = (len(qcn) - (NUMBER_OF_TCS * NUMBER_OF_QCN_PARAMS)) / NUMBER_OF_TCS

	for tc in range(NUMBER_OF_TCS):
		print "priority %d:" % tc
		for val in values:
			if isinstance(qcn, list):
				print "\t%s: %d" % (val,qcn[(tc * (len(values) + additions)) + values.index(val)])
			else:
				print "\t%s: %d" % (val,qcn[values.index(val)][tc])
		print


def update_paremeter(qcn, listPerTc, param):
	# Deal with an additions of qcn parameters which were not added to the tool #
	additions = (len(qcn) - (NUMBER_OF_TCS * NUMBER_OF_QCN_PARAMS)) / NUMBER_OF_TCS

	for tc in range(NUMBER_OF_TCS):
		if (listPerTc[tc] != -1):
			if isinstance(qcn, list):
				qcn[(tc * (NUMBER_OF_QCN_PARAMS + additions)) + list_params.index(param)] = listPerTc[tc]
			else:
				qcn[list_params.index(param)][tc] = listPerTc[tc]
	return qcn



parser = OptionParser(usage="%prog -i <interface> [options]", version="%prog 1.0")

parser.add_option("-i", "--interface", dest="intf",
			help="Interface name")
parser.add_option("-g", "--get_type", dest="type", choices=["parameters", "statistics"],
			help="Type of information to get: \"statistics\" or \"parameters\"")

parser.add_option("--rpg_enable", nargs=8, type="int", dest="rpg_enable_list",
			help="Set value of rpg_enable according to priority, use spaces between values and -1 for unknown values.")

parser.add_option("--rppp_max_rps", nargs=8, type="int", dest="rppp_max_rps_list",
			help="Set value of rppp_max_rps according to priority, use spaces between values and -1 for unknown values.")

parser.add_option("--rpg_time_reset", nargs=8, type="int", dest="rpg_time_reset_list",
			help="Set value of rpg_time_reset according to priority, use spaces between values and -1 for unknown values.")

parser.add_option("--rpg_byte_reset", nargs=8, type="int", dest="rpg_byte_reset_list",
			help="Set value of rpg_byte_reset according to priority, use spaces between values and -1 for unknown values.")

parser.add_option("--rpg_threshold", nargs=8, type="int", dest="rpg_threshold_list",
			help="Set value of rpg_threshold according to priority, use spaces between values and -1 for unknown values.")

parser.add_option("--rpg_max_rate", nargs=8, type="int", dest="rpg_max_rate_list",
			help="Set value of rpg_max_rate according to priority, use spaces between values and -1 for unknown values.")

parser.add_option("--rpg_ai_rate", nargs=8, type="int", dest="rpg_ai_rate_list",
			help="Set value of rpg_ai_rate according to priority, use spaces between values and -1 for unknown values.")

parser.add_option("--rpg_hai_rate", nargs=8, type="int", dest="rpg_hai_rate_list",
			help="Set value of rpg_hai_rate according to priority, use spaces between values and -1 for unknown values.")

parser.add_option("--rpg_gd", nargs=8, type="int", dest="rpg_gd_list",
			help="Set value of rpg_gd according to priority, use spaces between values and -1 for unknown values.")

parser.add_option("--rpg_min_dec_fac", nargs=8, type="int", dest="rpg_min_dec_fac_list",
			help="Set value of rpg_min_dec_fac according to priority, use spaces between values and -1 for unknown values.")

parser.add_option("--rpg_min_rate", nargs=8, type="int", dest="rpg_min_rate_list",
			help="Set value of rpg_min_rate according to priority, use spaces between values and -1 for unknown values.")

parser.add_option("--cndd_state_machine", nargs=8, type="int", dest="cndd_state_machine_list",
			help="Set value of cndd_state_machine according to priority, use spaces between values and -1 for unknown values.")

(options, args) = parser.parse_args()

if len(args) > 0:
    print "Bad arguments"
    parser.print_usage()
    sys.exit(1)

if (options.intf == None):
	print "Interface name is required"
	parser.print_usage()
	sys.exit(1)

tmp_list = ast.literal_eval(options.__str__()).values()

if (tmp_list.count(None) == len(tmp_list) - 1):
	print "No action was asked for, choose -h to see options"
	parser.print_usage()
	sys.exit(1)

qcn_path = "/sys/class/net/" + options.intf + "/qos/qcn"
qcn_stats_path = "/sys/class/net/" + options.intf + "/qos/qcn_stats"

ctrl = DcbController(options.intf)

try:
	qcn_main = None
	if (not os.path.exists(qcn_path)):
		qcn_main = QCNNL(ctrl)
	else:
		if (options.type == "statistics"):
			qcn_main = QCNStatsSysfs(qcn_stats_path)
		else:
			qcn_main = QCNSysfs(qcn_path)

	if (options.type == "parameters"):
		qcn = qcn_main.get()
		pretty_print_qcn(qcn, list_params)
	elif (options.type == "statistics"):
		qcn = qcn_main.get_statistics()
		pretty_print_qcn(qcn, list_statistics)

	else:

		qcn = qcn_main.get()

		if (options.rpg_enable_list != None):
			qcn = update_paremeter(qcn, options.rpg_enable_list, "rpg_enable")

		if (options.rppp_max_rps_list != None):
			qcn = update_paremeter(qcn, options.rppp_max_rps_list, "rppp_max_rps")

		if (options.rpg_time_reset_list != None):
			qcn = update_paremeter(qcn, options.rpg_time_reset_list, "rpg_time_reset")

		if (options.rpg_byte_reset_list != None):
			qcn = update_paremeter(qcn, options.rpg_byte_reset_list, "rpg_byte_reset")

		if (options.rpg_threshold_list != None):
			qcn = update_paremeter(qcn, options.rpg_threshold_list, "rpg_threshold")

		if (options.rpg_max_rate_list != None):
			qcn = update_paremeter(qcn, options.rpg_max_rate_list, "rpg_max_rate")

		if (options.rpg_ai_rate_list != None):
			qcn = update_paremeter(qcn, options.rpg_ai_rate_list, "rpg_ai_rate")

		if (options.rpg_hai_rate_list != None):
			qcn = update_paremeter(qcn, options.rpg_hai_rate_list, "rpg_hai_rate")

		if (options.rpg_gd_list != None):
			qcn = update_paremeter(qcn, options.rpg_gd_list, "rpg_gd")

		if (options.rpg_min_dec_fac_list != None):
			qcn = update_paremeter(qcn, options.rpg_min_dec_fac_list, "rpg_min_dec_fac")

		if (options.rpg_min_rate_list != None):
			qcn = update_paremeter(qcn, options.rpg_min_rate_list, "rpg_min_rate")

		if (options.cndd_state_machine_list != None):
			qcn = update_paremeter(qcn, options.cndd_state_machine_list, "cndd_state_machine")

		qcn_main.set(qcn)


except:
        print "QCN is not supported on your system!"
        qcn = []


