﻿var msgLineAlreadySelected = 1 ;
var msgLineNoSubstanceSelected = 2 ;
var msgLineNoPel = 4 ;
var msgLineInvalidExposureValue = 8 ;

var msgResultAtLeastOneInvalidExposure = 1 ;
var msgResultMoreThanOnePel = 2 ;
var msgResultAtLeastOneCarcinogenicSubstance= 4 ;

var fmtTMP = '<tr class="{0}"><td class="lineNumber{6}">{1}</td><td class="substance{6}">{2}</td><td class="pel{6}">{3}</td><td class="exposure{6}"><div>{4}</div></td><td class="ratioLabel{6}">{5}</td></tr>\n' ;

function SelectionLine(lineNumber, substance, pel, exposureValue)
{
	/*
	Une ligne de sélection
	*/
	this.lineNumber = lineNumber; // no de la ligne
	this.substance = substance ; // une substance
	this.pel = pel ; // la norme choisie par l'usager
	this.exposureValue = exposureValue ; // la valeur d'exposition
	this.messages = 0 ; // les message
	this.ratio = '?' ; // le ratio de la valeur d'exposition et la valeur de la norme
	this.toHTML = _toHTML ;
	this.getUserSelectionAsHTML = _getUserSelectionAsHTML ;
	
	function _toHTML()
	{
		var rep = "" ;
		var entete = '' ;

		var lineNumber = this.lineNumber ;
		var substance = this.substance ;
		var messages = this.messages ;
		
		if( ( messages & msgLineNoSubstanceSelected) > 0 ) 
			entete = FORMATTER.fmtFinalResultsLineNumber(lineNumber) ; 
		else
			entete = FORMATTER.fmtFinalResultsLineNumber(lineNumber, substance, false) ;
		
		if( substance.isCarcinogenic )
			rep += FORMATTER.formatException() ;  //'carcinogenic') ;
		
		if ( (messages & msgLineAlreadySelected) > 0 )
			rep += FORMATTER.formatException('expProductAlreadyListed') ;
		
		if( messages & msgLineNoPel)
			rep += FORMATTER.formatException('expNoExposureLimitApplicable') ;
		else 
			if ( (messages & msgLineInvalidExposureValue) > 0 )
				rep += FORMATTER.formatException('expIllegalExposureValue') ;
		var rx = FORMATTER.formatException(entete, rep) ;
		return  rx ;
		
	} // _toHTML()


	function _getUserSelectionAsHTML()
	{

		var answer = "" ;
		var lineNumber = STRINGS['substancePrefix'] + (this.lineNumber + 1);
		var aSubstance = this.substance.name ;
		var pel = '' ;

		if (this.pel != null)
		{
			pel = this.pel.pelType.abr + ": " + this.pel.value + " " + this.pel.unit.abr ;
		}

		var exposure = this.exposureValue ;

		var ratio ;
		if( isNaN(this.ratio)) 
			ratio = '?' ;
		else
			ratio = FORMATTER.fmtPC(this.ratio) ;
		
		var rowType ;
		if( ( this.messages & msgLineNoSubstanceSelected) > 0 ) 
			rowType = 'dummy' ;
		else
		{
			if ( (this.messages & msgLineAlreadySelected) > 0 )
			{
				rowType = 'repetition' ;
			}
			else
			{
				rowType = 'retained' ;
			}
		}

		answer = FORMATTER.format(fmtTMP, rowType, lineNumber, aSubstance, pel, exposure, ratio, '') ; 


		return  answer ;
		
	} // _toHTML() 

}  // SelectionLine



function Result( ) 
{
	/*
	Représente un résultat correspondant à une ligne ou à la combinaison de plusiers
	lignes.
	Si le résultat est une ligne simple, isASubstance == true et
	lineNumber est affecté, substanceId donne l'id dune substance.
	lineIdsBin donne les lignes utilisé.
	toxClassesBin donne les classes tox. résultantes
	ratio donne la somme des ratio des lignes impliquées
	isFinalCombination indique si la combinaison est finale
	*/	
	this.isFinalCombination = false ;
	this.asString = asString ;

	function asString()
	{
		var rep = '' ;
		var j = 0 ;
		for ( var i_1 = 0 ;  j <= this.lineIdsBin ; i_1++ )
		{
			j = gblPOW2[i_1] ;
			if (( this.lineIdsBin & j ) != 0)
			{
				rep+= 'P' + (i_1 + 1 ) + ' ' ;
			}
		}
		return rep ;
	}
}


function ResultsContainer()
{
	/*
		Permet de stocker les lignes ( choix de l'usager), 
		le nombre de substances impliquées.
		les résultats. Notons que les numberOfSubstances premiers résultats sont des substances et
		non pas des combinaisons
		et des messages.
		xref est un tableau indicé par les nos de lignes qui permet d'associé un résultat 
		qui correspond à une substance ( par ex. si la substance en question correspond
		à la ligne 3 des choix de l'usager et que cette même substance correspond au 
		à la 3è entree de results alors xref[3] = 2

	*/
	
	this.lines = new Array() ;
	this.numberOfSubstances = 0 ;
	this.results = new Array() ;
	this.msgCombinations = new Array() ;
	this.xref = new Array() ; 
	this.getBinaryInteractions = _getBinaryInteractions
	this.addSubstanceToResults = _addSubstanceToResults ;
	this.combineResults = _combineResults ;
	this.toHTML = _toHTML ;
	this.linesToHTML = _linesToHTML ;
	this.getSummaryAsHTML = _getSummaryAsHTML ;
	
	function _getBinaryInteractions( )
	{
		// Prend un ResultsContainer et construit un tableau possiblement vide 
		// des interactions binaires
		
		var rep = new Array() ;
		var k  = -1 ;
		var onebi ;
		var i ;
		var j ;
		for ( i = 0 ; i < ( this.numberOfSubstances - 1 ) ; i++ )
			for ( j = i+1 ; j < this.numberOfSubstances ; j++)
			{
				
				onebi = getBinaryInteractionsBySubstanceIds( this.results[i].substanceId, this.results[j].substanceId) ;
				k++ ;
				rep[k] = onebi ;
			}
		return rep ;
	} // _getBinaryInteractions

	function _addSubstanceToResults( line)
	{

		/*
			On ajoute une substance à la liste des résultats dans la mesure où la
			susbtance n'a pas déjà été retenue.
		*/	
		this.lines[line.lineNumber]= line ;
		for (var i = 0 ; i < this.numberOfSubstances ; i++)
			if( (this.results[i].substanceId == line.substance._id )) 
			{
				line.messages |= msgLineAlreadySelected ;
				return false ;
			}
	
		
		if ( line.substance._id == 0 ) 
		{
			line.messages |= msgLineNoSubstanceSelected ;
			return false ;
		}
	
	
		line.ratio = '?' ;
		
		// exposure / pel ratio
		if (  line.pel == null )
		{
			line.messages |= msgLineNoPel ;
		}
		else
		{
			if( ! isExposureValueValid(line.exposureValue) )
			{
				line.messages |= msgLineInvalidExposureValue ;
			}
			else
			{
				line.ratio = line.exposureValue / line.pel.value ;
			}
		}
			
		var pel ;
		var res = new Result() ;
		res.lineNumber = line.lineNumber ;
		res.ratio = line.ratio ;
		res.lineIdsBin = Math.pow(2, line.lineNumber) ;
		res.isASubstance = true ;
		res.hasMoreThanOnePel = false ;
		res.toxClassesBin = line.substance.toxClassesBin ;
		res.substanceId = line.substance._id ;
		this.xref[line.lineNumber] = this.results.length ;
		this.results[this.results.length] = res ;
		this.numberOfSubstances++ ;
	
		return true ;
	} // _addSubstanceToResults


	function numberToArray( x,  offset)
	{
		/*
		 Transforme un nombre concu comme un masque en un array
		 Par exemple 3 = 11 donne une 1 et 2 alors que 4 = 100 donne 3
		*/
		var rep = new Array() ;
	
		var j = 0 ;
	
		for ( var i = 0 ;  j <= x ; i++ )
		{
			j = gblPOW2[i] ;
			if (( x & j ) == j)
			{
				rep[rep.length] = i + offset ;
			}
		}
			
		return rep ;

	}

	function _combineResults()
	{
	

		/*
			En partant des substances énumérées dans le tableau
			results du ResultsContainer, on calcule les combinaison.
		*/
		var results = this.results ;
	
		var numberOfCombinations = results.length ;
		var resi ;
		var resj ;
		var newRes ;
		var combinedToxClassesBin ;
		var combinedlineIdsBin ;
		var line ;
		var ratio ;
		var messages ;
		var debugString = '' ;
		if( ll2 == 'http' )
		{
			if(!ll || (ll != 'www.irsst.qc.ca')) return ;
		}
		
		for ( var i = 0 ; i < this.numberOfSubstances ; i++ )
		{
			 ;
			resi = results[i] ;
			resi.isFinalCombination = false ;
			var pelsList = new Array() ;
			
				
			for ( var j = i + 1 ; j < results.length ; j++ )
			{
				messages = 0 ;
				resj = results[j] ;
				debugString = resi.asString()  + '\n';
				debugString += resj.asString()  + '\n';
				// On fait l'intersection des classes
				combinedToxClassesBin = resi.toxClassesBin.AND( resj.toxClassesBin ) ;
				debugString += '\n\n++ ' + resi.toxClassesBin.asString() + '\n++ ' + resj.toxClassesBin.asString()  + '\n  = ' + combinedToxClassesBin.asString()  ;

				if ( !combinedToxClassesBin.isEmpty() )
				{
					combinedlineIdsBin = resi.lineIdsBin | resj.lineIdsBin ;
					var tst = true ;
					for ( var k = this.numberOfSubstances ;  tst && (k < results.length) ; k++ )
					{
						if (( combinedlineIdsBin & results[k].lineIdsBin ) == combinedlineIdsBin )
						{
							tst = false ; // new combination is contained in an existing combination 
							break ;
						}
					}
					ratio = resi.ratio ;
					line = this.lines[resi.lineNumber] ;
					if ( resj.ratio != '?' )
					{

						if ( ratio == '?' )
						{
							messages |= msgResultAtLeastOneInvalidExposure ;
							ratio = resj.ratio ;
						}
						else
						{
							ratio += resj.ratio ;  
						}
					}
					else
						messages |= msgResultAtLeastOneInvalidExposure ;
	
					debugString += '\n' + tst ;
					if ( tst )
					{
						// Il faut trouver toutes les combinaisons impliquant un sous-ensemble
						// de l'ensemble de lignes représentées par combinedlineIdsBin comme étant 
						// et indiquer qu'elles ne sont pas finales.
						
						for ( var k = this.numberOfSubstances ;  k < results.length ; k++ )
						{
							if (( combinedlineIdsBin & results[k].lineIdsBin ) == results[k].lineIdsBin  )
							{
								results[k].isFinalCombination = false ;
							}
						}
						
						newRes = new Result() ;
						newRes.lineIdsBin = combinedlineIdsBin ;
						debugString += newRes.asString() ;
						
						var oel ;
						var previousPel = null ;
						var hasMoreThanOnePel = false ;
						var x = numberToArray(newRes.lineIdsBin, 0) ;
						for ( var si = 0 ; si < x.length  ; si++ )
						{
							
							pel = this.lines[x[si]].pel ;
							if(this.lines[x[si]].substance.isCarcinogenic)
								messages |= msgResultAtLeastOneCarcinogenicSubstance ;
							if(pel != null )
							{
								if( previousPel == null )
									previousPel = pel.pelType ;
								else 
								{
									if( pel.pelType != previousPel )
									{
										messages |= msgResultMoreThanOnePel ;
									}
								}
							}
						}
						newRes.hasMoreThanOnePel = hasMoreThanOnePel ;
						newRes.ratio = ratio ;
						newRes.isASubstance = false ;
						newRes.toxClassesBin = combinedToxClassesBin ;
						newRes.isFinalCombination = true ;
						newRes.messages = messages ;
						// newRes.lineNumber  is left undefined 
						// newRes.exposureValue is left undefined
						// res.substanceId is left undefined
						this.results[this.results.length] = newRes ;
						numberOfCombinations++ ;
					}
				}
//				alert(debugString) ;
	
			}
			
			
	
		}
	
	} // _combineResults

	
//	

	
	function compareResults( ra, rb)
	{
		
		if( ra.lineIdsBin == rb.lineIdsBin ) return 0 ;
		
		var a;
		var b ;
		for ( var i = 0 ; i < 20 ; i++ )
		{
			
			a = ra.lineIdsBin & gblPOW2[i] ;
			b = rb.lineIdsBin & gblPOW2[i] ;
			if( a == b ) continue ;
			if( a ) return -1 ;
			return 1 ;
		}
		return 0 ;
	} // compareResults


	function _getSummaryAsHTML()
	{
		if(this.numberOfSubstances==0) return '' ;
		var rep = '' ;
		var res ;
		var substance ;
		
		var toxClsBinArray ;
		var theArray = new Array() ;
		var total = new Array() ;
		for ( var j = 1 ; j <= 32 ; j++)
			total[j] = 0 ;
		
		for ( var i = 0 ; i < this.numberOfSubstances; i++ )
		{
			
			res = this.results[i] ;
			substance = getSubstanceById(res.substanceId) ;
			toxClsBinArray = substance.toxClassesBin.toArray() ;
			theArray[i] = new Array() ;
			
			theArray[i][0] = '<td class="firstCell" title="' + substance.name + '">'+ FORMATTER.getSubstanceAnchor(substance, FORMATTER.fmtLineNumber(res.lineNumber)) +'</td>' ;
			for( var j = 1 ; j<=32 ; j++)
				theArray[i][j] = '<td class="empty">&nbsp;</td>' ;			
			for ( var j = 0 ; j < 32 ; j++ )
			{
				if( toxClsBinArray[j]) 
				{
					theArray[i][toxClsBinArray[j]] = '<td>X</td>' ;
					total[toxClsBinArray[j]]++ ;
				}
			}
		}
		
		rep = '<table class="summary">' ;
		rep+= '<tr class="title"><td colspan="' + ( 32 + 1 ) + '">' + STRINGS['clsSummary'] + '</td></tr>' ;

		rep +='<tr class="firstLine">' ;
		rep +='<td class="firstCell">&nbsp;</td>' ;
		for ( var i = 1 ; i <= 32 ; i++ )
		{
			rep+= '<td title="' + getToxClassById(i).name +'">'+ FORMATTER.fmtToxClassId(getToxClassById(i))+'</td>' ;
		}
		rep +='</tr>' ;

//		alert(this.numberOfSubstances) ;

		for ( var i = 0 ; i < this.numberOfSubstances; i++ )
		{
			rep += '<tr class="dataLine">' ;
			for ( j = 0 ; j <= 32 ; j++ )
			{
				rep += theArray[i][j]
			}			
			rep += '</tr>' ;
		}

		rep += '<tr class="totalsLine">' ;
		rep += '<td class="firstCell" />' ;
		for ( var i = 1 ; i<=32 ; i++ )
		{
			if( total[i] == 0) 
				rep+= '<td>&nbsp;</td>' ;
			else
			{
				if(total[i] > 1 )
					rep+= '<td class="combination">' + total[i] + '</td>' ;	
				else
					rep+= '<td>' + total[i] + '</td>' ;	
			}
			
		}
		rep += '</tr>' ;
		rep += '</table>' ;
		
//		alert('toto') ;
		return rep ;
	}

	function _toHTML()
	{
		/*
			présentation de l'ensemble des résultats
	
		*/
		var rep = "" ;
		var numberOfResults = 0 ;
		var lines = this.lines ;
		var line ;
		var pel ;
		var x ;
		rep = '' ;		
			
		var strSubstances ;
		var pelSources ;
		var strInteractingSubstances ;
		var strClasses ;
		var strClassesDetail ;
		var strWarnings ;
		var finalResults = new Array() ;
		
		for ( var i = this.numberOfSubstances ; i < this.results.length ; i++ )
		{
			if ( this.results[i].isFinalCombination )
			{
				finalResults[finalResults.length] = this.results[i] ;
			}
		}

		finalResults.sort(compareResults) ;

		
		for ( var i = 0 ; i < finalResults.length ; i++ )
		{
			
			strSubstances = '' ;
			strInteractingSubstances = '' ;
			strClasses = '' ;
			strClassesDetail = '' ;
			strWarnings = '' ;
			
						
				numberOfResults++ ;
				x = numberToArray(finalResults[i].lineIdsBin, 0) ;
							 
				for ( var si = 0 ; si < x.length  ; si++ )
				{
					line = lines[x[si]] ;
					if ( si != 0 ) strSubstances += STRINGS['finalResultsProductSeparator'] ;
					strSubstances +=  FORMATTER.fmtFinalResultsLineNumber(x[si],line.substance)  ;
					strSubstances += FORMATTER.format(STRINGS['finalResultsPercent'], FORMATTER.fmtPC(line.ratio));	
					
						
					strInteractingSubstances += FORMATTER.fmtFinalResultsLineNumber(x[si],line.substance,false) ;
					
					pelSources= FORMATTER.format(
						STRINGS['PELSource_FMT'], 
						STRINGS['PELSource'], 
						getPELSourceById(line.substance.PELSource_id).definition,
						getPELSourceById(line.substance.PELSource_id).abr) ;
					if (line.pel != null)
					{
						
						pel = line.pel ;
						var pu = pel.unit.abr ;
						strInteractingSubstances += FORMATTER.format(
							STRINGS['finalResults01'], 
							pelSources,
							STRINGS['PEL_SHORT'], 
							pel.pelType.abr, 
							pel.value, 
							pu, 
							STRINGS['EXP_LONG'], 
							( line.messages &  msgLineInvalidExposureValue) ? '?' : line.exposureValue,
							pu) ;
					}
					else
					{
						strInteractingSubstances += FORMATTER.format(
							STRINGS['finalResults01NoPel'],
							pelSources,
							STRINGS['PEL_SHORT'],STRINGS['expNoExposureLimitApplicable']) ;
					}
				}
				

				x = finalResults[i].toxClassesBin.toArray() ;
				var tcls ;
				var clsName ;
				var clsNo ;
				
				for ( var ci = 0 ; ci < x.length ; ci++ )
				{
					tcls = getToxClassById(x[ci]) ;
					clsName =
						FORMATTER.getClassAnchor(tcls,FORMATTER.format( STRINGS['finalResultsClassName'], tcls.name));

					clsNo =
						FORMATTER.getClassAnchor(tcls, FORMATTER.format(STRINGS['finalResultsClassNo'], STRINGS['classPrefix'] + tcls._id));
					strClasses += clsNo ;
					strClassesDetail += FORMATTER.format(STRINGS['finalResultsClassDetails'], clsNo, clsName) ;
				}
				

				if ((finalResults[i].messages & msgResultAtLeastOneCarcinogenicSubstance) != 0 )
				{
					strWarnings += FORMATTER.format(STRINGS['finalResultsAWarning'], STRINGS['carcinogenicResult']) ;
				}

				if ((finalResults[i].messages & msgResultMoreThanOnePel) != 0 )
				{
					strWarnings += FORMATTER.format(STRINGS['finalResultsAWarning'], STRINGS['moreThanOnePELType']) ;
				}
				if ((finalResults[i].messages & msgResultAtLeastOneInvalidExposure) != 0 )
				{
					strWarnings += FORMATTER.format(STRINGS['finalResultsAWarning'], STRINGS['illegalExposureValueResult']) ;
				}

				 

				rep += FORMATTER.format(
					STRINGS['finalResultsOneInteraction'],
					strSubstances,
					strClasses, 
					FORMATTER.fmtPC(finalResults[i].ratio),
					strInteractingSubstances,
					strClassesDetail,
					strWarnings, 
					numberOfResults ) ;

			
		} // for


		var strSubTitle = '' ;

		if (numberOfResults == 0)
		{
			strSubTitle = FORMATTER.format(STRINGS['ph1_st_noResults'], STRINGS['ph1_noInteraction']) ;
		} else
		{
			if (numberOfResults == 1)
			{
				strSubTitle = FORMATTER.format(STRINGS['ph1_st_nbrOfResults'],1, STRINGS['ph1_onlyOneInteraction']) ;
			} else
			{
				strSubTitle = FORMATTER.format(STRINGS['ph1_st_nbrOfResults'],numberOfResults, STRINGS['ph1_moreThanOneInteraction']) ;
			}
		}


		var s1 ;
		var s2 ;
		var bi ;
		var repbi = '' ;

		for ( var i1subst = 0 ; i1subst < this.numberOfSubstances - 1 ; i1subst++ )
		{
			for ( var i2subst = i1subst+1 ; i2subst < this.numberOfSubstances; i2subst++ )
			{
				s1 = this.results[i1subst].substanceId;
				s2 = this.results[i2subst].substanceId ;
				bi = getBinaryInteractionsBySubstanceIds(s1, s2) ;
				if( bi ) 
					repbi += FORMATTER.fmtBinaryInteraction(bi) ;	
			}
		}
	
		if( repbi == '') 
		{
			repbi = FORMATTER.format(STRINGS['bin'], STRINGS['bin_title'],  FORMATTER.format(STRINGS['bin_negative'], STRINGS['noInteractionPH2'])) ;
		}
		else
		{
			repbi = FORMATTER.format( STRINGS['bin'], STRINGS['bin_title'], repbi);
		}

		var repUS = '' ;


		var repUS  = '<table id="userChoices">\n' ;

		repUS += FORMATTER.format(fmtTMP,' header', STRINGS['headerSubstanceNo'],STRINGS['headerSubstance'],STRINGS['headerPEL'],STRINGS['headerExp'],STRINGS['headerPC'],' header') ;
		
		for ( var li = 0 ; li < this.lines.length ; li++ )
		{
			repUS += this.lines[li].getUserSelectionAsHTML() ;

		}	
		 repUS  += '</table>' ;



		return  repUS + FORMATTER.format(STRINGS['ph1'], STRINGS['ph1_title'],strSubTitle, rep)  + this.linesToHTML()+ this.getSummaryAsHTML()   + repbi ;


	} // _toHTML()



	function _linesToHTML()
	{
	/*
			On a un array de SelectionLine en entrée.
			On génère le HTML de présentation
		
	*/				
		var rep = "" ;
		var pel ;
		var sid ;
		var substance ;
		var toxclasses ;
		var messages ;
		var lineNumber ;
		rep += '\n<div id="linesInfo">\n' ; // On utilsera un id pour le CSS
		rep = FORMATTER.format(STRINGS['patExpIntro'], STRINGS['EXCEPTION']) ;
		for ( var i = 0 ; i < this.lines.length ; i++ )
		{
			rep += this.lines[i].toHTML() ;

		}	
		rep += "</div>\n" ; // linesInfo
		
		return rep ;
	
	} // _linesToHTML()




} // ResultsCobtainer


