// BusinessProcess costs resolution

'use strict';

var memoize               = require('memoizee/plain')
  , definePercentage      = require('dbjs-ext/number/percentage')
  , defineCurrency        = require('dbjs-ext/number/currency')
  , defineMultipleProcess = require('../lib/multiple-process')
  , defineCost            = require('../cost')
  , defineRegistrations   = require('./registrations')

  , definePaymentReceiptUploads;

module.exports = memoize(function (db/* options */) {
	var BusinessProcess = defineRegistrations(db, arguments[1])
	  , Percentage = definePercentage(db)
	  , MultipleProcess = defineMultipleProcess(db)
	  , Currency = defineCurrency(db)
	  , Cost = defineCost(db);

	BusinessProcess.prototype.defineProperties({
		costs: { type: MultipleProcess, nested: true }
	});
	BusinessProcess.prototype.costs.map._descriptorPrototype_.type = Cost;
	BusinessProcess.prototype.costs.defineProperties({
		// Applicable costs resolved out of requested registrations
		applicable: { type: Cost, value: function (_observe) {
			var result = [];
			_observe(this.master.registrations.requested).forEach(function (registration) {
				_observe(registration.costs).forEach(function (cost) { result.push(cost); });
			});
			return result;
		} },
		// Payable subset of applicable costs
		// More directly: all applicable costs that are non 0
		payable: { type: Cost, multiple: true, value: function (_observe) {
			var result = [];
			this.applicable.forEach(function (cost) {
				var isPayable = Boolean(cost._get ? _observe(cost._amount) : cost.amount);
				if (isPayable) result.push(cost);
			});
			return result;
		} },
		// Paid costs
		paid: { type: Cost, multiple: true, value: function (_observe) {
			var result = [];
			this.payable.forEach(function (cost) {
				if (_observe(cost._isPaid)) result.push(cost);
			});
			return result;
		} },
		// Electronic costs
		electronic: { type: Cost, multiple: true, value: function (_observe) {
			var result = [];
			this.payable.forEach(function (cost) {
				if (cost.isElectronic) result.push(cost);
			});
			return result;
		} },
		// Payment progress
		paymentProgress: { type: Percentage, value: function (_observe) {
			var valid = 0, total = 0, paymentReceiptUploads = this.master.paymentReceiptUploads;
			// Eventual online payments
			if (this.electronic.size) {
				++total;
				if (this.electronic.every(function (cost) { return _observe(cost._isPaid); })) {
					++valid;
				}
			}
			total += _observe(paymentReceiptUploads.applicable._size);
			valid += _observe(paymentReceiptUploads.uploaded._size);
			if (!total) return 1;
			return valid / total;
		} },
		// Total for all payable costs
		totalAmount: { type: Currency, value: function (_observe) {
			var total = 0;
			this.payable.forEach(function (cost) {
				var amount = cost._get ? _observe(cost._amount) : cost.amount;
				total += amount;
			});
			return total;
		} }
	});

	if (!BusinessProcess.prototype.paymentReceiptUploads) definePaymentReceiptUploads(db);
	return BusinessProcess;
}, { normalizer: require('memoizee/normalizers/get-1')() });

definePaymentReceiptUploads = require('./payment-receipt-uploads');

@@ -2637,24 +2637,501 @@
 tal;%0A%09%09%7D %7D,%0A
+%09%09// Payment weight%0A%09%09// Indicates number of step user needs to take to complete payment step in Part A%0A%09%09// e.g. one step per each payment receipt, and one step for one online payment%0A%09%09// If it's zero, that means we should not show payment step at all%0A%09%09paymentWeight: %7B type: Percentage, value: function (_observe) %7B%0A%09%09%09var weight = 0;%0A%09%09%09if (this.electronic.size) ++weight;%0A%09%09%09weight += _observe(this.mater.paymentReceiptUploads.applicable._size);%0A%09%09%09return weight;%0A%09%09%7D %7D,%0A
 %09%09// Total f

Introduce `paymentWeight` property