var TollsTaxCalculator = function(sJson, iBase) {
    var priv = {
        iTaxPaidBy : 0,
        aBetAdjusterValue : eval('('+sJson+")"),
        aBetAdjuster : [],
        toFixed : function(n, d) {
            d = d || 0;
            var f = Math.pow(10, d);
            n = Math.round(n * f) / f;
            if(n>=0) n += Math.pow(10, - (d + 1));
            else n -= Math.pow(10, - (d + 1));
            n += '';
            return d == 0 ? n.substring(0, n.indexOf('.')) :
                            n.substring(0, n.indexOf('.') + d + 1);
        },
        fnCalculatePercentage : function(oBetAdjusterValue, minOdds) {
            return function(iNrOfBets, aSystemOdds) {
                for(var i = 0; i < aSystemOdds.length; i++) {
                    if(parseFloat(priv.toFixed(aSystemOdds[i],2)) < minOdds) iNrOfBets--;
                }
                return oBetAdjusterValue.percentOnTips[
                            iNrOfBets > 15
                            ? 15
                            : ( iNrOfBets < 1
                                ? 1
                                : iNrOfBets
                               ) - 1
                        ];
            }
        },        
        fnCombiBonus : function(oBetAdjusterValue) {
            return function(oResult, iNrOfBets, aSystemOdds) {
                priv.calculateAndAdd(
                    oResult,
                    TollsTaxCalculator.constants.TransactionTypes.COMBINATION_BONUS,
                    oResult.orig,
                    priv.fnCalculatePercentage(oBetAdjusterValue, oBetAdjusterValue.minOdds || 0)(iNrOfBets, aSystemOdds)
                );
            };
        },
        fnCombiCharge : function(oBetAdjusterValue) {
            return function(oResult, iNrOfBets) {
                priv.calculateAndAdd(
                    oResult,
                    TollsTaxCalculator.constants.TransactionTypes.COMBINATION_TOLLS,
                    oResult.orig,
                    priv.fnCalculatePercentage(oBetAdjusterValue, 0)(iNrOfBets, [])
                );
            };
        },
        fnCalcPercentage : function(calculationBase, fPercentage) {
            return parseFloat(priv.toFixed( (calculationBase * parseFloat(priv.toFixed(fPercentage, 3)) ) / 100, 2));
        },
        fnCombiTax : function(oBetAdjusterValue) {
            return function(oResult) {
                var tax = oBetAdjusterValue.tax,
                    otherShare = 100 - oBetAdjusterValue.clientShare,
                    taxCalculationBase = oResult.result;
                var taxValue = priv.fnCalcPercentage(taxCalculationBase, tax),
                    otherShareValue = priv.fnCalcPercentage(taxValue, otherShare),
                    otherPercentage = tax * otherShare / 100;
                if (otherShare > 0) priv.calculateAndAdd(
                    oResult,
                    TollsTaxCalculator.constants.TransactionTypes.COMBINATION_TAX_PARTNER,
                    otherShareValue,
                    otherPercentage,
                    true
                );
                if (otherShare < 100) priv.calculateAndAdd(
                    oResult,
                    TollsTaxCalculator.constants.TransactionTypes.COMBINATION_TAX_CUSTOMER,
                    taxValue - otherShareValue,
                    tax - otherPercentage,
                    true
                );

            };
        },
        adjusterFactory : function(oBetAdjusterValue) {
            var javaClassName = oBetAdjusterValue.javaClass;
            switch (javaClassName.substr(javaClassName.indexOf("$"))) {
                case TollsTaxCalculator.constants.JavaClassSuffix.Bonus:  return priv.fnCombiBonus(oBetAdjusterValue);
                case TollsTaxCalculator.constants.JavaClassSuffix.Charge: return priv.fnCombiCharge(oBetAdjusterValue);
                case TollsTaxCalculator.constants.JavaClassSuffix.Tax:    return priv.fnCombiTax(oBetAdjusterValue);
            }
        },
        sign : function(fNewValue) {
            return (iBase == TollsTaxCalculator.constants.CombinationBillingCalcBaseType.PROFIT) ? fNewValue * -1 : fNewValue;
        },
        calculateAndAdd : function(oResult, iTransactionType, calculationBase, fPercentage, bCalculationBaseIsResult) {
            if(!fPercentage) return;
            fPercentage = parseFloat(priv.toFixed(fPercentage, 3));
            var fChange = bCalculationBaseIsResult ?
                            calculationBase :
                            priv.fnCalcPercentage(calculationBase, fPercentage);
            var transactionTypes = TollsTaxCalculator.constants.TransactionTypes;
            oResult.values[iTransactionType] = fPercentage.toString();
            switch(iTransactionType) {
                case transactionTypes.COMBINATION_TOLLS:
                case transactionTypes.COMBINATION_TAX_CUSTOMER:
                    oResult.result += parseFloat(oResult.results[iTransactionType] = priv.toFixed(priv.sign(fChange), 2));
                    break;
                case transactionTypes.COMBINATION_BONUS:
                    oResult.result += parseFloat(oResult.results[iTransactionType] = priv.toFixed(priv.sign(fChange * -1), 2));
                    break;
                case transactionTypes.COMBINATION_TAX_PARTNER:
                    oResult.results[iTransactionType] = priv.toFixed(fChange, 2);
                    break;
            }
        }
    }

    for(var i=0; i<priv.aBetAdjusterValue.length; i++) {
        priv.aBetAdjuster[i] = priv.adjusterFactory(priv.aBetAdjusterValue[i]);
        if (priv.aBetAdjusterValue[i].javaClass.indexOf(TollsTaxCalculator.constants.JavaClassSuffix.Tax) != -1) {
            priv.iTaxPaidBy = priv.aBetAdjusterValue[i].taxPaidBy;
        }
    }
    this.calculate = function(fValue, iNrOfBets, aSystemOdds) {
        var oResult = new TollsTaxCalculator.Result(parseFloat(fValue), priv.iTaxPaidBy);
        for(var i=0; i<priv.aBetAdjusterValue.length; i++) {
            priv.aBetAdjuster[i](oResult, parseInt(iNrOfBets), aSystemOdds || []);
        }
        oResult.result = priv.toFixed(oResult.result, 2);
        return oResult;
    };
    return this;
}
TollsTaxCalculator.constants = {
    CombinationBillingCalcBaseType : {
        STAKE : 1 ,
        PROFIT : 2
    },
    TransactionTypes : {
        COMBINATION_TOLLS : 210,
        COMBINATION_BONUS : 211,
        COMBINATION_TAX_CUSTOMER : 212,
        COMBINATION_TAX_PARTNER : 213
    },
    JavaClassSuffix : {
        Bonus  : '$CombiBonus',
        Charge : '$CombiCharge',
        Tax    : '$CombiTax'
    }
}
TollsTaxCalculator.Result = function(fValue, iTaxPaidBy) {
    this.orig = parseFloat(fValue);
    this.result = parseFloat(fValue);
    this.results = {};
    this.values  = {};
    this.taxPaidBy = iTaxPaidBy;
}