package com.cogix.vwf;
import java.text.*;

class WeightedScore extends Validator {

	//	WeightedScore targetquestion[.decimalplaces],{sum|average},questionlist...
	//	Calculates the sum or average of the questions listed, 
	//		showing 'decimalplaces' after the result's decimal point
	//		If .decimalplaces omitted, rounds to nearest integer and omits the decimal point.
	
	//	Each question on the list can indicate a weight to multiply the question by,
	//		using the syntax question*weight with or without a decimal point,
	//		e.g., question*2 or question *.4 or question*1.03 or question*.30

    //  Each question on the list can refer to the answer value, or to the Extra value
    //      associated with the answer. To refer to the answer value, just use the question name.
    //      To refer to its Nth extra value, follow the question name with [N], eg: income[0].

	//	Examples.	Assuming that questions smoke, drink, and exercise
	//				have values between 1 and 5, then:
	
	//		WeightedScore targetquestion,sum,smoke*.40,drink*.40,exercise*.20
	//			gives scores between 1 and 5
	//		WeightedScore targetquestion.2,average,smoke*4,drink*4,exercise*2
	//			gives scores between 3.33 and 16.67

    boolean onPageReceived (RequestParams reqx, String questionname, String spec) {
        //
        String [] s = Misc.cogixParse (spec, true);
        if ( s == null || s.length < 3 || s[0].length () < 1 || s[1].length () < 1 || s[2].length () < 1 ) {
            //	WriteLog automatically includes the poll ID and writes to the Poll's log
            WriteLog ( "330E","WeightedScore arguments missing");
            return false;
        }
        String targetquestion = s[0];
        int decplaces = 0;
        int kdecperiod = targetquestion.indexOf ('.');
        if ( kdecperiod > 0 ) {
            String decimals = targetquestion.substring ( kdecperiod + 1 );
            targetquestion = targetquestion.substring ( 0, kdecperiod );
            try {
                decplaces = Integer.parseInt (decimals);
            }
            catch ( NumberFormatException nfe) {
                WriteLog ( "330E","WeightedScore decimal places not a number: " + s [0] ) ;
                return false;
            }
        }
        //	Turn on tallying for targetquestion
        String msg = setTallying ( targetquestion );
        if ( msg != null ) {
            WriteLog ( "330E","WeightedScore " + msg );
            return false;
        }

        boolean bSum = true;
        boolean bAverage = false;
        if ( s.length >= 2 ) {
            if ( "average".equals ( s[1] ) ) {
                bAverage = true; bSum = false;
            }
        }
        //	Go trough all questions and calculate score
        double fscore = 0;
        int nQuestions = 0;
        for ( int j = 2 ; j < s.length ; j ++ ) {
            String qtoinclude = null;
            String weight = null;
            double fweight = 1.0;
            String elmt = s [j];	//	qname or qname*2 or qname*.6
            int times = elmt.indexOf ('*');
            if ( times == 0 ) {	//	bad syntax: * at the beginning
                WriteLog ( "330E","WeightedScore question name missing: " + elmt ) ;
                return false;
            }
            else if ( times < 0 ) {	//	no weight
                qtoinclude = elmt;
            }
            else if ( times >= elmt.length()-1 ) {	//	bad syntax: * at the end
                WriteLog ( "330E","WeightedScore weight missing: " + elmt ) ;
                return false;
            }
            else {	//	questionname*weight
                qtoinclude = elmt.substring (0,times);
                weight = elmt.substring ( times + 1 ) ;
                try {
                    fweight = Double.parseDouble ( weight );
                }
                catch ( NumberFormatException nfe ) {
                    WriteLog ( "330E","WeightedScore weight not numeric: " + elmt ) ;
                    return false;
                }
            }
            //  3.9 Add [N] syntax to use extra value N
            int nExtra = -1;
            String sExtra = null;
            int iLB = qtoinclude.indexOf ('[');
            if ( iLB >= 0 ) {
                if ( iLB == 0 ) {
                    //  error $$$$
                    WriteLog ( "330E","$$$: " + "[" ) ;
                    return false;
                }

                int iRB = qtoinclude.indexOf (']',iLB);
                if ( iRB <= 0 ) {
                    //  error $$$$
                    WriteLog ( "330E","$$$: " + "[" ) ;
                    return false;
                }
                sExtra = qtoinclude.substring (iLB+1,iRB);
                try {
                    nExtra = Integer.parseInt(sExtra);
                    if ( nExtra < 0 )
                        throw new NumberFormatException ();
                } catch ( NumberFormatException nfe ) {
                    //  error $$$$
                    WriteLog ( "330E","$$$: " + elmt ) ;
                    return false;
                }
                qtoinclude = qtoinclude.substring(0,iLB);
            }

            String answer = getParamValue (reqx,qtoinclude);
            int questionValue = 0;
            if ( Misc.isEmpty ( answer ) )
                continue;	//	ignore not answered
            try {
                if ( nExtra < 0 ) {
                    questionValue = Integer.parseInt(answer);
                }
                else {
                    //  definition.getAnswerText with 3 arguments returns the sExtra extra value
                    definition def = getDefinition();
                    String questionval = def.getAnswerText (qtoinclude,answer,sExtra);
                    questionValue = Integer.parseInt (questionval);
                }
                fscore = fscore + questionValue * fweight ;
                nQuestions ++ ;
            }
            catch ( NumberFormatException nfe ) {
                WriteLog ( "330E","WeightedScore question value not numeric, ignored."
                        + " Question: " + qtoinclude + ", value: " + answer
                        + ( nExtra >= 0 ? ( ", extra: " + sExtra ) : "" ) ) ;
                continue;
            }
        }
        if ( bAverage && nQuestions > 0 )
            fscore = fscore / nQuestions;
        //	set value to empty if nothing was calculated
        String setvalue = "" ;
        if ( nQuestions > 0 ) {
            NumberFormat nf = NumberFormat.getInstance();
            nf.setMaximumFractionDigits ( decplaces );
            nf.setGroupingUsed(false);
            setvalue = nf.format (fscore);
        }
        setParameterValue ( targetquestion, setvalue );
        setValid (true);
        return true;
    }

	String checkArguments (String questionname, String spec) {
		//
		String [] s = Misc.cogixParse (spec, true);
		if ( s == null || s.length < 3 || s[0].length () < 1 || s[1].length () < 1 || s[2].length () < 1 ) {
			return "WeightedScore arguments missing in question " + questionname ;
			}
        String targetquestion = s[0];
		int decplaces = 0;
		int kdecperiod = targetquestion.indexOf ('.');
		if ( kdecperiod > 0 ) 
			targetquestion = targetquestion.substring ( 0, kdecperiod );
		//	Turn on tallying for targetquestion; if error, returns msg
		return setTallying ( targetquestion );
    	}		
	}
