import numpy as N
import re
import sys
import os
from uncertainties import ufloat
from uncertainties.umath import * 

def process_raw_results(rawfile, savedir,rho_mirror,dni):
	"""Process the raw Solstice `simul` output into readable CSV files

	``Arguments``

	  * rawfile (str): the directory of the `simul` file that generated by Solstice
	  * savedir (str): the directory for saving the organised results
	  * rho_mirror (float): mirror reflectivity (needed for reporting energy sums)
	  * dni (float): the direct normal irradiance (W/m2), required to obtain performance of individual heliostat

	``Returns``

	  * efficiency_total (float): the total optical efficiency
	  * performance_hst (numpy array): the breakdown of losses of each individual heliostat
	  * The simulation results are created and written in the `savedir`
		
	"""

	# FIXME this approach seems fundamentally a bit messy... we are carefully
	# load the text output from 'solppraw' and then assuming that we can
	# correctly find the right bits of data in the right place. Wouldn't it
	# be easier and more robust to modify solppraw to create output that can
	# be directly loaded, along with data labels, eg a YAML file? Or to
	# create 'result-raw.csv' directly?

	rows = []
	index = 0
	with open(rawfile) as f:
		for r in f.readlines():
			if index<20:
				pass #sys.stderr.write("Line %d: %s"%(index,r))

			if r[0] == "#":
				#sys.stderr.write("^------Comment\n")
				#comment line
				rows.append([r])
			else:
				rows.append(r.split())			
			index+=1

	results=N.array([])

	# sun direction

	#sys.stderr.write("SUN DIRECTION?\n")
	#sys.stderr.write(rows[0][0]+"\n")
	sun=re.findall("[-+]?\d*\.\d+|\d+", rows[0][0])
	#sys.stderr.write("SUN = %s\n"%(repr(sun),))

	azimuth=sun[0]
	elevation=sun[1]

	def get_rc(row,col):
		return float(rows[row][col])

	# Global results

	num_res=int(get_rc(1,0)) # number of global results
	num_rec=int(get_rc(1,1))
	num_hst=get_rc(1,2)
	num_rays=get_rc(1,3)

	potential=get_rc(2,0) #W
	potential_err=get_rc(2,1)

	absorbed=get_rc(3,0)
	absorbed_err=get_rc(3,1)    

	Fcos=get_rc(4,0)
	Fcos_err=get_rc(4,1)  

	shadow_loss=get_rc(5,0)
	shadow_err=get_rc(5,1)    

	missing_loss=get_rc(6,0)
	missing_err=get_rc(6,1) 

	material_loss=get_rc(7,0)
	material_err=get_rc(7,1)    

	atmospheric_loss=get_rc(8,0)
	atmospheric_err=get_rc(8,1)  

	# Target (receiver)
	# 0 receiver name
	# 1 - 2 id and area
	# 3 - 24 (total 22) front
	# 25- 46 (total 22) back 
	rec_area=get_rc(num_res+2,2) # m2  
	
	rec_front_income=get_rc(num_res+2,3)
	rec_front_income_err=get_rc(num_res+2,4)
	#rec_no_material_loss=get_rc(num_res+2,5)
	#rec_no_material_loss_err=get_rc(num_res+2,6)
	#rec_no_atmo_loss=get_rc(num_res+2,7)
	#rec_no_atmo_loss_err=get_rc(num_res+2,8)
	#rec_material_loss=get_rc(num_res+2,9)
	#rec_material_loss_err=get_rc(num_res+2,10)
	rec_front_absorbed=get_rc(num_res+2,13)
	rec_front_absorbed_err=get_rc(num_res+2,14)
	rec_front_eff=get_rc(num_res+2,23)
	rec_front_eff_err=get_rc(num_res+2,24)

	rec_back_income=get_rc(num_res+2,25)
	rec_back_income_err=get_rc(num_res+2,26)
	rec_back_absorbed=get_rc(num_res+2,35)
	rec_back_absorbed_err=get_rc(num_res+2,36)
	rec_back_eff=get_rc(num_res+2,-2)
	rec_back_eff_err=get_rc(num_res+2,-1)

	if num_rec>1:
		#Virtual target
		vir_area=get_rc(num_res+3,2)
		vir_income=get_rc(num_res+3,3)
		vir_income_err=get_rc(num_res+3,4)
	
	raw_res=N.array([
		['name','value', 'error']
		,['sun_azimuth', azimuth,'']
		,['sun_elevation', elevation, '']
		,['num hst', num_hst,'']
		,['num rays',num_rays, '']
		,['potential flux', potential, potential_err]
		,['absorbed flux', absorbed, absorbed_err]
		,['Cosine factor', Fcos, Fcos_err]
		,['shadow loss', shadow_loss, shadow_err]
		,['Mising loss', missing_loss, missing_err]
		,['materials loss', material_loss, material_err]
		,['atomospheric loss', atmospheric_loss, atmospheric_err]
		,['','','']
		,['Target', '','']
		,['area', rec_area, '']
		,['front income flux', rec_front_income, rec_front_income_err]
		,['back income flux', rec_back_income, rec_back_income_err]
		,['front absorbed flux', rec_front_absorbed, rec_front_absorbed_err]
		,['back absorbed flux', rec_back_absorbed, rec_back_absorbed_err]
		,['front efficiency', rec_front_eff, rec_front_eff_err]
		,['back efficiency', rec_back_eff, rec_back_eff_err]
		,['','','']
		,['Virtual plane','','']
		,['area', vir_area, '']
		,['income flux', vir_income,vir_income_err]
	])

	#sys.stderr.write(repr(raw_res))
	#sys.stderr.write("SHAPE = %s" % (repr(raw_res.shape)))

	N.savetxt(savedir+'/result-raw.csv', raw_res, fmt='%s', delimiter=',')

	Qtotal=ufloat(potential, 0)
	Fcos=ufloat(Fcos,Fcos_err) 
	Qcos=Qtotal*(1.-Fcos)
	Qshade=ufloat(shadow_loss,shadow_err)
	Qfield_abs=(Qtotal-Qcos-Qshade)*(1.-float(rho_mirror))
	Qatm=ufloat(atmospheric_loss, atmospheric_err)
	Qspil=ufloat(vir_income,vir_income_err)
	Qabs=ufloat(absorbed, absorbed_err)
	Qrefl=ufloat(rec_front_income,rec_front_income_err)+ufloat(rec_back_income,rec_back_income_err)-Qabs
	Qblock=Qtotal-Qcos-Qshade-Qfield_abs-Qspil-Qabs-Qrefl-Qatm

	organised=N.array([
		['Name', 'Value', '+/-Error']
		,['Qall (kW)', Qtotal.n/1000., Qtotal.s/1000.]
		,['Qcos (kW)', Qcos.n/1000.,Qcos.s/1000.]
		,['Qshad (kW)', Qshade.n/1000., Qshade.s/1000.]
		,['Qfield_abs (kW)', Qfield_abs.n/1000., Qfield_abs.s/1000.]
		,['Qblcok (kW)', Qblock.n/1000.,  Qblock.s/1000.]
		,['Qatm (kW)',Qatm.n/1000., Qatm.s/1000.]
		,['Qspil (kW)', Qspil.n/1000., Qspil.s/1000.]
		,['Qrefl (kW)', Qrefl.n/1000.,Qrefl.s/1000.]
		,['Qabs (kW)', Qabs.n/1000., Qabs.s/1000.]
		,['rays', num_rays,'-']
	])
	N.savetxt(savedir+'/result-formatted.csv', organised, fmt='%s', delimiter=',')
	efficiency_total=Qabs/Qtotal

	# per heliostat results, and
	# per receiver per heliostat results
	num_hst=int(num_hst)    
	heliostats=N.zeros((num_hst,28))

	for i in range(num_hst):
		l1=2+num_res+num_rec+i # the line number of the per heliostat result
		per_hst=rows[l1]

		hst_idx=re.findall("[-+]?\d*\.\d+|\d+", per_hst[0] ) 
		hst_area=per_hst[2]
		hst_sample=per_hst[3]
		hst_cos=per_hst[4]
		hst_shad=per_hst[6]

		heliostats[i,0]=hst_idx[0]
		heliostats[i,1]=hst_area
		heliostats[i,2]=hst_sample
		heliostats[i,3]=hst_cos
		heliostats[i,4]=hst_shad

		# per heliostat per receiver
		l2=2+num_res+num_rec+num_hst+i  
		per_hst=rows[l2]   
		hst_in=float(per_hst[2])+float(per_hst[22]) # front+back
		hst_in_mat=float(per_hst[8])+float(per_hst[28])
		hst_in_atm=float(per_hst[10])+float(per_hst[30])
		hst_abs=float(per_hst[12])+float(per_hst[32])
		hst_abs_mat=float(per_hst[18])+float(per_hst[38])
		hst_abs_atm=float(per_hst[20])+float(per_hst[40])
		  
		heliostats[i,5]=hst_in
		heliostats[i,6]=hst_in_mat
		heliostats[i,7]=hst_in_atm
		heliostats[i,8]=hst_abs
		heliostats[i,9]=hst_abs_mat
		heliostats[i,10]=hst_abs_atm

		# per heliostat per virtual target
		l3=2+num_res+num_rec+2*num_hst+i  
		per_hst=rows[l3] 
		hst_in=float(per_hst[2])+float(per_hst[22]) # front+back
		hst_in_mat=float(per_hst[8])+float(per_hst[28])
		hst_in_atm=float(per_hst[10])+float(per_hst[30])
		hst_abs=float(per_hst[12])+float(per_hst[32])
		hst_abs_mat=float(per_hst[18])+float(per_hst[38])
		hst_abs_atm=float(per_hst[20])+float(per_hst[40])
		  
		heliostats[i,11]=hst_in
		heliostats[i,12]=hst_in_mat
		heliostats[i,13]=hst_in_atm
		heliostats[i,14]=hst_abs
		heliostats[i,15]=hst_abs_mat
		heliostats[i,16]=hst_abs_atm


		hst_tot=float(hst_area)*1000.
		hst_cos=hst_tot*(1.-float(hst_cos))
		hst_shad=float(hst_shad)
		hst_abs=(hst_tot-hst_cos-hst_shad)*(1.-rho_mirror)

		hst_atm=float(heliostats[i,16])
		hst_spil=float(heliostats[i,11])
		hst_rec_abs=float(heliostats[i,8])
		hst_rec_refl=float(heliostats[i,5])-float(heliostats[i,8])
		hst_block=hst_tot-hst_cos-hst_shad-hst_abs-hst_atm-hst_spil-hst_rec_abs-hst_rec_refl

		heliostats[i,19]=hst_tot
		heliostats[i,20]=hst_cos
		heliostats[i,21]=hst_shad
		heliostats[i,22]=hst_abs
		heliostats[i,23]=hst_block
		heliostats[i,24]=hst_atm
		heliostats[i,25]=hst_spil
		heliostats[i,26]=hst_rec_refl
		heliostats[i,27]=hst_rec_abs

	idx=heliostats[:, 0].argsort()
	heliostats=heliostats[idx]
	performance_hst=heliostats[:, 19:]

	heliostats_title=N.array(['hst_idx', 'area', 'sample', 'cos', 'shade', 'incoming', 'in-mat-loss','in-atm-loss', 'absorbed', 'abs-mat-loss', 'abs-atm-loss', 'vir_incoming', 'vir_in-mat-loss','vir_in-atm-loss', 'vir_absorbed', 'vir_abs-mat-loss', 'vir_abs-atm-loss', '', '', 'total', 'cos', 'shad', 'hst_abs', 'block', 'atm', 'spil', 'rec_refl', 'rec_abs' ]) 

	heliostats_details=N.vstack((heliostats_title, heliostats))

	N.savetxt(savedir+'/heliostats-raw.csv', heliostats_details, fmt='%s', delimiter=',')


	return efficiency_total, performance_hst

if __name__=='__main__':
    eta,pf_hst = proces_raw_results(sys.argv[1], sys.argv[2], sys.argv[3])
    sys.stderr.write('\nTotal efficiency: %s\n'%(repr(eta),))


