import sys, os
# PSSE_LOCATION = r"C:\Program Files (x86)\PTI\PSSE33\PSSBIN"
# sys.path.append(PSSE_LOCATION)
# os.environ['PATH'] = os.environ['PATH'] + ';' + PSSE_LOCATION
import psspy
import math
import psstools
_f, _i, _s = psspy._f, psspy._i, psspy._s 


def determineOSP(month):
	
	W1_JAN = [[155,161,06], [155,161,28], [152,988,01], [152,160,25], [152, 160, 29], [639, 187, 18]]
	W1 = [[155,161,06], [155,161,28], [152,988,01], [152, 160, 25], [661, 160, 29], [639, 187, 18]]
	
	W2_DEC = [[135, 155, 22], [135, 155, 26], [420,155,90], [420,155,03], [128,24,12], [128,24,40]]
	W2 = [[135, 155, 22], [135, 155, 26],[420,155,90], [420,155,03], [128,788,10], [128,81,14]]
	E1 = [[1484,1440,70], [1484,1440,97]]
	E2 = [[1499,1403,27], [1499,1427,53]]
	E3 = [[918,669,34], [1012,669,35]]
	E4 = [[943,737,36], [943,451,05]]
	E5 = [[159,943,24], [159,943,27]]
	E6 = [[165,746,48], [165,746,49]]
	E7 = [[1422,152,12], ]
	
	
	watlWeightingFactor = {"watl":0.5, "eatl":0.39, "W1":0.62, "W2":0}
	eatlWeightingFactor = {"watl":0.16, "eatl":0.25, "E1": -1.03, "E2":0.9, "E3":0.46, "E4":0.49, "E5":-0.25, "E6":0.01, "E7": -1.38}
	
	if month == "DEC":
		OWSP = getWATL_Dispatch()*watlWeightingFactor["watl"] + getEATL_Dispatch()*watlWeightingFactor["eatl"]  + getFlows(W1)*watlWeightingFactor["W1"] + getFlows(W2_DEC)*watlWeightingFactor["W2"]
	elif month == "JAN" or month == "FEB":
		OWSP = getWATL_Dispatch()*watlWeightingFactor["watl"] + getEATL_Dispatch()*watlWeightingFactor["eatl"]  + getFlows(W1_JAN)*watlWeightingFactor["W1"] + getFlows(W2)*watlWeightingFactor["W2"]
	else:
		OWSP = getWATL_Dispatch()*watlWeightingFactor["watl"] + getEATL_Dispatch()*watlWeightingFactor["eatl"]  + getFlows(W1)*watlWeightingFactor["W1"] + getFlows(W2)*watlWeightingFactor["W2"]
	
	print OWSP
	
	
	OESP = getWATL_Dispatch()*eatlWeightingFactor["watl"] + getEATL_Dispatch()*eatlWeightingFactor["eatl"]  + getFlows(E1)*eatlWeightingFactor["E1"] + getFlows(E2)*eatlWeightingFactor["E2"] + getFlows(E3)*eatlWeightingFactor["E3"] + getFlows(E4)*eatlWeightingFactor["E4"] + getFlows(E5)*eatlWeightingFactor["E5"] + getFlows(E6)*eatlWeightingFactor["E6"] + getFlows(E7)*eatlWeightingFactor["E7"]  
	print "OWSP, OESP : %s, %s" %(OWSP, OESP)
	return OWSP, OESP
	
def getFlows(group):
	totalFlow = 0
	for eachline in group:
		mwflow, mvarflow = getBranchFlow(eachline[0], eachline[1], str(eachline[2]).zfill(2))
		print eachline[0], eachline[1], str(eachline[2]).zfill(2), " = " , mwflow
		totalFlow += mwflow
	print "\t", totalFlow
	# raw_input()
	return totalFlow

def Solve():
	psspy.progress("\n FNSL - Lock tap Enable SVC Only\n")
	psspy.fnsl([0,0,0,1,2,0,99,0])
	psspy.fnsl([0,0,0,1,2,0,99,0])
	# checkSol()
	
def getWATL_Dispatch():
	watl_name_NtoS = "WATL_P1_SC"
	watl_bus_NtoS = 623  ### SUNNYBROOK Bus
	
	ierr, controlMode_NtoS = psspy.dc2int_2(watl_name_NtoS, "MDC")
	ierr, setVal_NtoS = psspy.dc2dat_2(watl_name_NtoS, watl_bus_NtoS, "SETVAL")
	
	watl_name_StoN = "WATL_P1_CS"
	watl_bus_StoN = 485 ## CROSSINGS Bus
	
	ierr, controlMode_StoN = psspy.dc2int_2(watl_name_StoN, "MDC")
	ierr, setVal_StoN = psspy.dc2dat_2(watl_name_StoN, watl_bus_StoN, "SETVAL")
	
	if controlMode_NtoS == 1 and controlMode_StoN == 0:
		setVal = abs(setVal_NtoS)
	elif controlMode_NtoS == 0 and controlMode_StoN == 1:
		setVal = -abs(setVal_StoN)
	elif controlMode_NtoS == 0 and controlMode_StoN == 0:
		setVal = 0
	else:
		raise Exception
	
	print setVal
	psspy.progress("\n Current WATL = %s\n" %setVal)
	return setVal
	
def getEATL_Dispatch():
	eatl_name_NtoS = "EATLP1_HN"
	eatl_bus_NtoS = 1615  ### HTHFIELD Bus
	
	ierr, controlMode_NtoS = psspy.dc2int_2(eatl_name_NtoS, "MDC")
	ierr, setVal_NtoS = psspy.dc2dat_2(eatl_name_NtoS, eatl_bus_NtoS, "SETVAL")
	
	eatl_name_StoN = "EATLP1_NH"
	eatl_bus_StoN = 1618 ## NEWELL Bus
	
	ierr, controlMode_StoN = psspy.dc2int_2(eatl_name_StoN, "MDC")
	ierr, setVal_StoN = psspy.dc2dat_2(eatl_name_StoN, eatl_bus_StoN, "SETVAL")
	
	if controlMode_NtoS == 1 and controlMode_StoN == 0:
		setVal = abs(setVal_NtoS)
	elif controlMode_NtoS == 0 and controlMode_StoN == 1:
		setVal = -abs(setVal_StoN)
	elif controlMode_NtoS == 0 and controlMode_StoN == 0:
		setVal = 0
	else:
		raise Exception
	
	print setVal
	psspy.progress("\n Current EATL = %s\n" %setVal)
	return setVal
	
def swShuntInfo(ibus):
	# ibus = 623
	ierr, currentBinit = psspy.swsdt1(ibus, "BINIT")
	ierr, blocks = psspy.swsint(ibus, "BLOCKS")
	
	mvar_steps = []
	neg_mvars = []
	pos_mvars = []
	
	for iblk in range(1,blocks+1):
		ierr, nsteps, mvar = psspy.swsblk(ibus, iblk)
		if mvar < 0 :
			# print {mvar:nsteps}
			neg_mvars.append((mvar,nsteps))
		else:
			pos_mvars.append((mvar,nsteps))
	print neg_mvars, pos_mvars
	
	total_neg_mvars = []
	binit = 0
	for eachmvar in neg_mvars:
		nsteps = eachmvar[1]
		mvar = eachmvar[0]
		for bstep in range(1, nsteps+1):
			binit += mvar
			# print iblk, bstep, mvar, binit
			total_neg_mvars.append(binit)
			mvar_steps.append(binit)
	print total_neg_mvars
	
	mvar_steps.append(0)
	
	total_pos_mvars = []
	binit = 0
	for eachmvar in pos_mvars:
		nsteps = eachmvar[1]
		mvar = eachmvar[0]
		for bstep in range(1, nsteps+1):
			binit += mvar
			# print iblk, bstep, mvar, binit
			total_pos_mvars.append(binit)
			mvar_steps.append(binit)
	print total_pos_mvars
	print mvar_steps
	mvar_steps.append(currentBinit)
	
	return currentBinit, mvar_steps

MvarLimitingLines = {"watl_north": [630, 623, "DC"], "watl_south": [485, 159, "DC"], "eatl_north": [1614, 1615, "29"], "eatl_south": [1618, 1012, "75"]}
adjustableSWShunts = {"watl_north": [623, ], "watl_south": [485, ], "eatl_north": [1615, ], "eatl_south": [1618, ]}
adjustableFacts = {"watl_south": ["CRO_SVCP", ], "eatl_south": ["SVCPLUS1", "SVCPLUS2"]}

MvarLimits = {"watl_north": 75, "watl_south": 35, "eatl_north": 75, "eatl_south": 35}



def setMvarFlowLimit(control):
	[ibus, jbus, ickt] = MvarLimitingLines[control]
	mwflow1, mvarflow1 = getBranchFlow(ibus, jbus, ickt)
	mwflow2, mvarflow2 = getBranchFlow(jbus, ibus, ickt)
	flows = [abs(mwflow1), abs(mwflow2)]
	mwflow = max(flows)
	desiredMvarLimit = mwflow*0.5
	return desiredMvarLimit

def adjustFilterBanks(control, MvarLimits):
	print "Adjusting ... ", control
	swBus = adjustableSWShunts[control][0]
	mvarLimit = MvarLimits[control]
	[ibus, jbus, ickt] = MvarLimitingLines[control]
	mwflow, mvarflow = getBranchFlow(ibus, jbus, ickt)
	currentBinit, mvar_steps = swShuntInfo(swBus)
	print "currentBinit : ", currentBinit
	print " mvarflow ", mvarflow
	# raw_input()
	diffs = []
	binits = []
	mvarflows = []
	
	if not (mvarflow >= -mvarLimit and mvarflow <= mvarLimit):
		if control == "watl_south" or control == "eatl_south":
			factsDevices = adjustableFacts[control]
			for factsDevice in factsDevices:
				if not (mvarflow >= -mvarLimit and mvarflow <= mvarLimit):
					ierr, vsetpoint = psspy.fcddat_2(factsDevice, "VSET")
					while mvarflow < -mvarLimit and vsetpoint < 1.1:
					# increase vsetpoint
						vsetpoint += 0.01
						psspy.facts_chng_2(factsDevice,[_i,_i,_i,_i,_i,_i],[_f,_f, vsetpoint,_f,_f,_f,_f,_f,_f,_f,_f,_f,_f],_s)
						Solve()
						mwflow, mvarflow = getBranchFlow(ibus, jbus, ickt)
					while mvarflow > mvarLimit and vsetpoint > 0.91:
					# reduce vsetpoint
						vsetpoint -= 0.01
						psspy.facts_chng_2(factsDevice,[_i,_i,_i,_i,_i,_i],[_f,_f, vsetpoint,_f,_f,_f,_f,_f,_f,_f,_f,_f,_f],_s)
						Solve()
						mwflow, mvarflow = getBranchFlow(ibus, jbus, ickt)
		
	mwflow, mvarflow = getBranchFlow(ibus, jbus, ickt)
	print " mvarflow ", mvarflow
	
	if not (mvarflow >= -mvarLimit and mvarflow <= mvarLimit):
		# print "HJ"
		psspy.save("Working_Case.sav")
		psspy.save("Trial_Case.sav")
		for step in mvar_steps:
			
			psspy.case("Working_Case.sav")
		# if mvarflow >= -mvarLimit and mvarflow <= mvarLimit:
			# break
		# else:
			
			binit = step
			psspy.switched_shunt_chng_3(swBus,[_i,_i,_i,_i,_i,_i,_i,_i,_i,_i,_i,_i],[_f,_f,_f,_f,_f,_f,_f,_f,_f,_f, binit,_f],_s)
			Solve()
			solved = psspy.solved()
			if solved == 0:
				# [ibus, jbus, ickt] = MvarLimitingLines[control]
				mwflow, mvarflow = getBranchFlow(ibus, jbus, ickt)
				print " mvarflow ", mvarflow
				diff = abs(abs(mvarflow) - mvarLimit)
				diffs.append(diff)
				binits.append(binit)
				mvarflows.append(abs(mvarflow))
				psspy.save("Trial_Case.sav")	
		psspy.case("Working_Case.sav")
		minDiff = min(diffs)
		minMvar = min(mvarflows)
		# foundBinit = binits[diffs.index(minDiff)]
		foundBinit = binits[mvarflows.index(minMvar)]
		print "foundBinit : ", foundBinit
		print "diffs :", diffs
		print "binits : ", binits
		print "mvarflows : ", mvarflows
		# raw_input()
		######## Apply the Found Settings to the SW SHunt
		psspy.switched_shunt_chng_3(swBus,[_i,_i,_i,_i,_i,_i,_i,_i,_i,_i,_i,_i],[_f,_f,_f,_f,_f,_f,_f,_f,_f,_f, foundBinit,_f],_s)
		Solve()
		mwflow, mvarflow = getBranchFlow(ibus, jbus, ickt)
		currentBinit = foundBinit
	print "foundBinit_ CurrentBinit : ", currentBinit	
	print " mvarflow ", mvarflow
	# raw_input()
		
	if not (mvarflow >= -mvarLimit and mvarflow <= mvarLimit):
		if control == "watl_south" or control == "eatl_south":
			factsDevices = adjustableFacts[control]
			for factsDevice in factsDevices:
				if not (mvarflow >= -mvarLimit and mvarflow <= mvarLimit):
					ierr, vsetpoint = psspy.fcddat_2(factsDevice, "VSET")
					while mvarflow < -mvarLimit and vsetpoint < 1.1:
					# increase vsetpoint
						vsetpoint += 0.01
						psspy.facts_chng_2(factsDevice,[_i,_i,_i,_i,_i,_i],[_f,_f, vsetpoint,_f,_f,_f,_f,_f,_f,_f,_f,_f,_f],_s)
						Solve()
						mwflow, mvarflow = getBranchFlow(ibus, jbus, ickt)
					while mvarflow > mvarLimit and vsetpoint > 0.91:
					# reduce vsetpoint
						vsetpoint -= 0.01
						psspy.facts_chng_2(factsDevice,[_i,_i,_i,_i,_i,_i],[_f,_f, vsetpoint,_f,_f,_f,_f,_f,_f,_f,_f,_f,_f],_s)
						Solve()
						mwflow, mvarflow = getBranchFlow(ibus, jbus, ickt)
		
	mwflow, mvarflow = getBranchFlow(ibus, jbus, ickt)
	print mvarflow
		
	# ### FACTS DEVICE update ####
	# factsName = r"""CRO_SVCP"""
	# psspy.facts_chng_2(factsName,[_i,_i,_i,_i,_i,_i],[_f,_f, vsetpoint,_f,_f,_f,_f,_f,_f,_f,_f,_f,_f],_s)
	
	# ########### Fixed Shunt Update ###
	# psspy.shunt_chng(ibus,ickt,status,[_f,_f])
	

	
	
	
	
def getBranchFlow(ibus, jbus, ickt):
	try:
		ierr, flow = psspy.brnflo(ibus,jbus,ickt)
		return flow.real, flow.imag
	except:
		print "!Branch Not Found!!!!"
		raise Exception
	
def setEATL(OESP):
	if OESP > 100 and OESP <= 1000:
		desiredVal = OESP
	elif OESP > 1000:
		desiredVal = 1000
	elif  OESP >= 0 and OESP <= 100:
		desiredVal = 100
	elif OESP < 0 and OESP >= -100:
		desiredVal = -100
	elif  OESP >= -1000 and OESP < -100:
		desiredVal = OESP
	elif OESP < -1000:
		desiredVal = -1000
	
	### Rounding####
	desiredVal = round(desiredVal, -1)
	psspy.progress("\n Setting EATL at .. %s \n" %desiredVal)
	
	if desiredVal > 0: ########## NtoS - HTHFIELDtoNewell
		psspy.two_terminal_dc_line_data(r"""EATLP1_HN""",[1,_i],[abs(desiredVal),_f,_f,_f,_f,_f,_f,_f],_s)
		psspy.two_terminal_dc_line_data(r"""EATLP1_NH""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)
	elif desiredVal < 0: ########## StoN - NewelltoHTHFIELD
		psspy.two_terminal_dc_line_data(r"""EATLP1_HN""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)
		psspy.two_terminal_dc_line_data(r"""EATLP1_NH""",[1,_i],[abs(desiredVal),_f,_f,_f,_f,_f,_f,_f],_s)
	else: 
		psspy.two_terminal_dc_line_data(r"""EATLP1_HN""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)
		psspy.two_terminal_dc_line_data(r"""EATLP1_NH""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)
	
	
	return desiredVal

	
def updateWATL(desiredVal):
	
	if desiredVal > 0: ########## NtoS - SUNNYBtoCROSSINGS
		psspy.two_terminal_dc_line_data(r"""WATL_P1_SC""",[1,_i],[abs(desiredVal),_f,_f,_f,_f,_f,_f,_f],_s)
		psspy.two_terminal_dc_line_data(r"""WATL_P1_CS""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)
		
	elif desiredVal < 0: ########## StoN - CROSSINGStoSUNNYB
		psspy.two_terminal_dc_line_data(r"""WATL_P1_SC""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)
		psspy.two_terminal_dc_line_data(r"""WATL_P1_CS""",[1,_i],[abs(desiredVal),_f,_f,_f,_f,_f,_f,_f],_s)
	else: 
		psspy.two_terminal_dc_line_data(r"""WATL_P1_SC""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)
		psspy.two_terminal_dc_line_data(r"""WATL_P1_CS""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)
	
def updateEATL(desiredVal):
	if desiredVal > 0: ########## NtoS - HTHFIELDtoNewell
		psspy.two_terminal_dc_line_data(r"""EATLP1_HN""",[1,_i],[abs(desiredVal),_f,_f,_f,_f,_f,_f,_f],_s)
		psspy.two_terminal_dc_line_data(r"""EATLP1_NH""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)
	elif desiredVal < 0: ########## StoN - NewelltoHTHFIELD
		psspy.two_terminal_dc_line_data(r"""EATLP1_HN""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)
		psspy.two_terminal_dc_line_data(r"""EATLP1_NH""",[1,_i],[abs(desiredVal),_f,_f,_f,_f,_f,_f,_f],_s)
	else: 
		psspy.two_terminal_dc_line_data(r"""EATLP1_HN""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)
		psspy.two_terminal_dc_line_data(r"""EATLP1_NH""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)
		
		
	
def setWATL(OWSP):
	if OWSP > 100 and OWSP <= 1000:
		desiredVal = OWSP
	elif OWSP > 1000:
		desiredVal = 1000
	elif  OWSP >= 0 and OWSP <= 100:
		desiredVal = 100
	elif OWSP < 0 and OWSP >= -100:
		desiredVal = -100
	elif  OWSP >= -1000 and OWSP < -100:
		desiredVal = OWSP
	elif OWSP < -1000:
		desiredVal = -1000
	
	### Rounding####
	desiredVal = round(desiredVal, -1)
	psspy.progress("\n Setting WATL at .. %s \n" %desiredVal)
	
	if desiredVal > 0: ########## NtoS - SUNNYBtoCROSSINGS
		psspy.two_terminal_dc_line_data(r"""WATL_P1_SC""",[1,_i],[abs(desiredVal),_f,_f,_f,_f,_f,_f,_f],_s)
		psspy.two_terminal_dc_line_data(r"""WATL_P1_CS""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)
		
	elif desiredVal < 0: ########## StoN - CROSSINGStoSUNNYB
		psspy.two_terminal_dc_line_data(r"""WATL_P1_SC""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)
		psspy.two_terminal_dc_line_data(r"""WATL_P1_CS""",[1,_i],[abs(desiredVal),_f,_f,_f,_f,_f,_f,_f],_s)
	else: 
		psspy.two_terminal_dc_line_data(r"""WATL_P1_SC""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)
		psspy.two_terminal_dc_line_data(r"""WATL_P1_CS""",[0,_i],[0,_f,_f,_f,_f,_f,_f,_f],_s)

	return desiredVal
		
def initializeHVDC():
	psspy.two_terminal_dc_line_data(r"""WATL_P1_CS""",[0,_i],[0.0,_f,_f,_f,_f,_f,_f,_f],_s)
	psspy.two_terminal_dc_line_data(r"""WATL_P1_SC""",[1,_i],[ 100.0,_f,_f,_f,_f,_f,_f,_f],_s)
	psspy.two_terminal_dc_line_data(r"""EATLP1_NH""",[0,_i],[0.0,_f,_f,_f,_f,_f,_f,_f],_s)
	psspy.two_terminal_dc_line_data(r"""EATLP1_HN""",[1,_i],[ 100.0,_f,_f,_f,_f,_f,_f,_f],_s)
	
	Solve()

def hvdcMain(month, s1_hvdcParameters):
# def Main():
	# psspy.progress_output(2,"hvdcout.txt",[0,0])
	minSetPointDiff = 100.0
	initializeHVDC()
	Solve()
	[s1OWSP, s1OESP] = [s1_hvdcParameters[0], s1_hvdcParameters[1]]
	[s1watlFlow, s1eatlFlow] = [s1_hvdcParameters[2], s1_hvdcParameters[3]]
	OWSP, OESP = determineOSP(month)
	savedOWSP = OWSP
	savedOESP = OESP
	print s1OWSP, s1OESP, s1watlFlow, s1eatlFlow
	print "OWSP, OESP : ", savedOWSP, savedOESP
	
	# x = (float(s1OWSP)-float(savedOWSP))
	# y = (float(s1OESP)-float(savedOESP))
	# print x, y
	# print 
	# raw_input()
	if abs(s1OWSP-savedOWSP) >= minSetPointDiff:
		print "using new OWSP ..."
		psspy.progress("\n using new OWSP : %s \n" %(savedOWSP))
		newWATL = setWATL(savedOWSP)
	else:
		print "Get back to S1 WATL ... "
		psspy.progress("\n getting back to S1 WATL : %s \n" %(s1watlFlow))
		updateWATL(s1watlFlow)
		newWATL = s1watlFlow
	
	if abs(s1OESP-savedOESP) >= minSetPointDiff:
		print "using new OESP ..."
		psspy.progress("\n using new OESP : %s \n" %(savedOESP))
		newEATL = setEATL(savedOESP)
	else:
		print "Get back to S1 EATL ... "
		psspy.progress("\n getting back to S1 EATL : %s \n" %(s1eatlFlow))
		updateEATL(s1eatlFlow)
		newEATL = s1eatlFlow
	
	Solve()
	# raw_input()
	# MvarLimits = dict()
	# for control in sorted(MvarLimitingLines.keys()):
		# MvarLimits[control] = setMvarFlowLimit(control)
	
	print MvarLimits
	for control in sorted(MvarLimitingLines.keys()):
		print "\nAdjusting Filter Banks to limit the Flows....\n"
		adjustFilterBanks(control, MvarLimits)
		# raw_input()
	for control in sorted(MvarLimitingLines.keys()):
		[ibus, jbus, ickt] = MvarLimitingLines[control]
		mwflow, mvarflow = getBranchFlow(ibus, jbus, ickt)
		print control, "---", mvarflow
		psspy.progress("\n %s = %s \n" %(control,mvarflow))
	
	return savedOWSP, savedOESP, newWATL, newEATL
	

# month = 'APR'
# s1_hvdcParameters = [8.36572479248, -109.714814568, 100, -110]
# hvdcMain(month, s1_hvdcParameters)
	
	