import R from 'ramda'
import React from 'react'
import { anyNull, val } from './traverse-common-functions'
import { Node } from './mecanismViews/common'
import {
	makeJsx,
	evaluateNode,
	rewriteNode,
	evaluateArray,
	evaluateArrayWithFilter,
	evaluateObject,
	parseObject,
	collectNodeMissing
} from './evaluation'
import {
	findRuleByName,
	disambiguateRuleReference,
	findRuleByDottedName
} from './rules'

import 'react-virtualized/styles.css'
import { Table, Column } from 'react-virtualized'
import taux_versement_transport from 'Règles/rémunération-travail/cotisations/ok/liste-taux.json'
import Somme from './mecanismViews/Somme'
import uniroot from './uniroot'
import {clearDict} from 'Engine/traverse'


let constantNode = constant => ({
	nodeValue: constant,
	jsx: nodeValue => <span className="value">{nodeValue}</span>
})

let decompose = (recurse, k, v) => {
	let subProps = R.dissoc('composantes')(v),
		explanation = v.composantes.map(c => ({
			...recurse(
				R.objOf(k, {
					...subProps,
					...R.dissoc('attributs')(c)
				})
			),
			composante: c.nom ? { nom: c.nom } : c.attributs
		}))

	let jsx = (nodeValue, explanation) => (
		<Node
			classes="mecanism composantes"
			name="composantes"
			value={nodeValue}
			child={
				<ul>
					{explanation.map((c, i) => [
						<li className="composante" key={JSON.stringify(c.composante)}>
							<ul className="composanteAttributes">
								{R.toPairs(c.composante).map(([k, v]) => (
									<li key={k}>
										<span>{k}: </span>
										<span>{v}</span>
									</li>
								))}
							</ul>
							<div className="content">{makeJsx(c)}</div>
						</li>,
						i < explanation.length - 1 && (
							<li key="+" className="composantesSymbol">
								<i className="fa fa-plus-circle" aria-hidden="true" />
							</li>
						)
					])}
				</ul>
			}
		/>
	)

	let filter = situationGate => c =>
		!situationGate('sys.filter') ||
		!c.composante ||
		!c.composante['dû par'] ||
		c.composante['dû par'] == situationGate('sys.filter')

	return {
		explanation,
		jsx,
		evaluate: evaluateArrayWithFilter(filter, R.add, 0),
		category: 'mecanism',
		name: 'composantes',
		type: 'numeric'
	}
}

let devariate = (recurse, k, v) => {
	let subProps = R.dissoc('variations')(v),
		explanation = v.variations.map(c => ({
			...recurse(
				R.objOf(k, {
					...subProps,
					...R.dissoc('si')(c)
				})
			),
			condition: recurse(c.si)
		}))

	let evaluate = (cache, situationGate, parsedRules, node) => {
		let evaluateOne = child => {
			let condition = evaluateNode(cache, situationGate, parsedRules, child.condition)
			return {
				...evaluateNode(cache, situationGate, parsedRules, child),
				condition
			}
		}

		let explanation = R.map(evaluateOne, node.explanation),
			choice = R.find(node => node.condition.nodeValue, explanation),
			nodeValue = choice ? choice.nodeValue : null

		let collectMissing = node => {
			let choice = R.find(node => node.condition.nodeValue, node.explanation),
				leftMissing = choice
					? []
					: R.uniq(
						R.chain(
							collectNodeMissing,
							R.pluck('condition', node.explanation)
						)
					),
				rightMissing = choice
					? collectNodeMissing(choice)
					: R.chain(collectNodeMissing, node.explanation)
			return R.concat(leftMissing, rightMissing)
		}

		return rewriteNode(node, nodeValue, explanation, collectMissing)
	}

	// TODO - find an appropriate representation
	let jsx = (nodeValue, explanation) => (
		<Node
			classes="mecanism variations"
			name="variations"
			value={nodeValue}
			child={
				<ul>
					{explanation.map(c =>
						<li className="variation" key={JSON.stringify(c.condition)}>
							<div className="condition">
								{makeJsx(c.condition)}
								<div className="content">{makeJsx(c)}</div>
							</div>
						</li>
					)}
				</ul>
			}
		/>
	)

	return {
		explanation,
		evaluate,
		jsx,
		category: 'mecanism',
		name: 'variations',
		type: 'numeric'
	}
}

export let mecanismOneOf = (recurse, k, v) => {
	if (!R.is(Array, v)) throw 'should be array'

	let explanation = R.map(recurse, v)

	let jsx = (nodeValue, explanation) => (
		<Node
			classes="mecanism conditions list"
			name="une de ces conditions"
			value={nodeValue}
			child={
				<ul>
					{explanation.map(item => (
						<li key={item.name || item.text}>{makeJsx(item)}</li>
					))}
				</ul>
			}
		/>
	)

	let evaluate = (cache, situationGate, parsedRules, node) => {
		let evaluateOne = child => evaluateNode(cache, situationGate, parsedRules, child),
			explanation = R.map(evaluateOne, node.explanation),
			values = R.pluck('nodeValue', explanation),
			nodeValue = R.any(R.equals(true), values)
				? true
				: R.any(R.equals(null), values) ? null : false

		let collectMissing = node =>
			node.nodeValue == null
				? R.chain(collectNodeMissing, node.explanation)
				: []
		return rewriteNode(node, nodeValue, explanation, collectMissing)
	}

	return {
		evaluate,
		jsx,
		explanation,
		category: 'mecanism',
		name: 'une de ces conditions',
		type: 'boolean'
	}
}

export let mecanismAllOf = (recurse, k, v) => {
	if (!R.is(Array, v)) throw 'should be array'

	let explanation = R.map(recurse, v)

	let jsx = (nodeValue, explanation) => (
		<Node
			classes="mecanism conditions list"
			name="toutes ces conditions"
			value={nodeValue}
			child={
				<ul>
					{explanation.map(item => (
						<li key={item.name || item.text}>{makeJsx(item)}</li>
					))}
				</ul>
			}
		/>
	)


	let evaluate = (cache, situationGate, parsedRules, node) => {
		let evaluateOne = child => evaluateNode(cache, situationGate, parsedRules, child),
			explanation = R.map(evaluateOne, node.explanation),
			values = R.pluck('nodeValue', explanation),
			nodeValue = R.any(R.equals(false), values)
				? false // court-circuit
				: R.any(R.equals(null), values) ? null : true

		let collectMissing = node =>
			node.nodeValue == null
				? R.chain(collectNodeMissing, node.explanation)
				: []
		return rewriteNode(node, nodeValue, explanation, collectMissing)
	}

	return {
		evaluate: evaluate,
		jsx,
		explanation,
		category: 'mecanism',
		name: 'toutes ces conditions',
		type: 'boolean'
	}
}

export let mecanismNumericalSwitch = (recurse, k, v) => {
	// Si "l'aiguillage" est une constante ou une référence directe à une variable;
	// l'utilité de ce cas correspond à un appel récursif au mécanisme
	if (R.is(String, v)) return recurse(v)

	if (!R.is(Object, v) || R.keys(v).length == 0) {
		throw 'Le mécanisme "aiguillage numérique" et ses sous-logiques doivent contenir au moins une proposition'
	}

	// les termes sont les couples (condition, conséquence) de l'aiguillage numérique
	let terms = R.toPairs(v)

	// la conséquence peut être un 'string' ou un autre aiguillage numérique
	let parseCondition = ([condition, consequence]) => {
		let conditionNode = recurse(condition), // can be a 'comparison', a 'variable', TODO a 'negation'
			consequenceNode = mecanismNumericalSwitch(recurse, condition, consequence)

		let evaluate = (cache, situationGate, parsedRules, node) => {
			let collectMissing = node => {
				let missingOnTheLeft = collectNodeMissing(node.explanation.condition),
					investigate = node.explanation.condition.nodeValue !== false,
					missingOnTheRight = investigate
						? collectNodeMissing(node.explanation.consequence)
						: []
				return R.concat(missingOnTheLeft, missingOnTheRight)
			}

			let explanation = R.evolve(
				{
					condition: R.curry(evaluateNode)(cache, situationGate, parsedRules),
					consequence: R.curry(evaluateNode)(cache, situationGate, parsedRules)
				},
				node.explanation
			)

			return {
				...node,
				collectMissing,
				explanation,
				nodeValue: explanation.consequence.nodeValue,
				condValue: explanation.condition.nodeValue
			}
		}

		let jsx = (nodeValue, { condition, consequence }) => (
			<div className="condition">
				{makeJsx(condition)}
				<div>{makeJsx(consequence)}</div>
			</div>
		)

		return {
			evaluate,
			jsx,
			explanation: { condition: conditionNode, consequence: consequenceNode },
			category: 'condition',
			text: condition,
			condition: conditionNode,
			type: 'boolean'
		}
	}

	let evaluateTerms = (cache, situationGate, parsedRules, node) => {
		let evaluateOne = child => evaluateNode(cache, situationGate, parsedRules, child),
			explanation = R.map(evaluateOne, node.explanation),
			nonFalsyTerms = R.filter(node => node.condValue !== false, explanation),
			getFirst = prop => R.pipe(R.head, R.prop(prop))(nonFalsyTerms),
			nodeValue =
				// voilà le "numérique" dans le nom de ce mécanisme : il renvoie zéro si aucune condition n'est vérifiée
				R.isEmpty(nonFalsyTerms)
					? 0
					: // c'est un 'null', on renvoie null car des variables sont manquantes
					getFirst('condValue') == null
						? null
						: // c'est un true, on renvoie la valeur de la conséquence
						getFirst('nodeValue')

		let collectMissing = node => {
			let choice = R.find(node => node.condValue, node.explanation)
			return choice
				? collectNodeMissing(choice)
				: R.chain(collectNodeMissing, node.explanation)
		}

		return rewriteNode(node, nodeValue, explanation, collectMissing)
	}

	let explanation = R.map(parseCondition, terms)

	let jsx = (nodeValue, explanation) => (
		<Node
			classes="mecanism numericalSwitch list"
			name="aiguillage numérique"
			value={nodeValue}
			child={
				<ul>
					{explanation.map(item => (
						<li key={item.name || item.text}>{makeJsx(item)}</li>
					))}
				</ul>
			}
		/>
	)

	return {
		evaluate: evaluateTerms,
		jsx,
		explanation,
		category: 'mecanism',
		name: 'aiguillage numérique',
		type: 'boolean || numeric' // lol !
	}
}


export let findInversion = (situationGate, rules, v, dottedName) => {
	let inversions = v.avec
	if (!inversions)
		throw 'Une formule d\'inversion doit préciser _avec_ quoi on peut inverser la variable'
	/*
	Quelle variable d'inversion possible a sa valeur renseignée dans la situation courante ?
	Ex. s'il nous est demandé de calculer le salaire de base, est-ce qu'un candidat à l'inversion, comme
	le salaire net, a été renseigné ?
	*/
	let fixedObjective = inversions
		.map(i => disambiguateRuleReference(rules, rules.find(R.propEq('dottedName', dottedName)), i))
		.find(name => situationGate(name) != undefined)

	if (fixedObjective == null) return {inversionChoiceNeeded: true}
	//par exemple, fixedObjective = 'salaire net', et v('salaire net') == 2000
	return {
		fixedObjective,
		fixedObjectiveValue: situationGate(fixedObjective),
		fixedObjectiveRule: findRuleByDottedName(rules, fixedObjective)
	}
}


let doInversion = (situationGate, parsedRules, v, dottedName) => {
	let inversion = findInversion(situationGate, parsedRules, v, dottedName)

	if (inversion.inversionChoiceNeeded) return {
		inversionMissingVariables: [dottedName],
		nodeValue: null
	}
	let { fixedObjectiveValue, fixedObjectiveRule } = inversion
	let inversionCache = {}
	let fx = x => {
		inversionCache = {}
		return evaluateNode(inversionCache, // with an empty cache
			n => dottedName === n ? x : situationGate(n),
			parsedRules,
			fixedObjectiveRule
		).nodeValue
	}

	// si fx renvoie null pour une valeur numérique standard, disons 1000, on peut
	// considérer que l'inversion est impossible du fait de variables manquantes
	// TODO fx peut être null pour certains x, et valide pour d'autres : on peut implémenter ici le court-circuit
	if (fx(1000) == null)
		return {
			nodeValue: null,
			inversionMissingVariables: collectNodeMissing(
				evaluateNode({},
					n =>
						dottedName === n ? 1000 : situationGate(n),
					parsedRules,
					fixedObjectiveRule
				)
			)
		}

	let tolerancePercentage = 0.00001,
		// cette fonction détermine la racine d'une fonction sans faire trop d'itérations
		nodeValue = uniroot(
			x => fx(x) - fixedObjectiveValue,
			0,
			1000000000,
			tolerancePercentage * fixedObjectiveValue,
			100
		)

	return {
		nodeValue,
		inversionMissingVariables: [],
		inversionCache
	}
}


export let mecanismInversion = dottedName => (recurse, k, v) => {

	let evaluate = (cache, situationGate, parsedRules, node) => {
		let inversion =
			// avoid the inversion loop !
			situationGate(dottedName) == undefined &&
			doInversion(situationGate, parsedRules, v, dottedName)
		let
			collectMissing = () => inversion.inversionMissingVariables,
			nodeValue = inversion.nodeValue

		let evaluatedNode = rewriteNode(node, nodeValue, null, collectMissing)
		// rewrite the simulation cache with the definitive inversion values

		R.toPairs(inversion.inversionCache).map(([k,v])=>cache[k] = v)
		return evaluatedNode
	}

	return {
		evaluate,
		jsx: (nodeValue) => (
			<Node
				classes="mecanism inversion"
				name="inversion"
				value={nodeValue}
				child={<div>
					<div>avec</div>
					<ul>{v.avec.map(recurse).map(el => <li key={el.name}>{makeJsx(el)}</li>)}</ul>
				</div>} />
		),
		category: 'mecanism',
		name: 'inversion',
		type: 'numeric'
	}
}

export let mecanismSum = (recurse, k, v) => {
	let explanation = v.map(recurse)

	let evaluate = evaluateArray(R.add, 0)

	return {
		evaluate,
		jsx: (nodeValue, explanation) => (
			<Somme nodeValue={nodeValue} explanation={explanation} />
		),
		explanation,
		category: 'mecanism',
		name: 'somme',
		type: 'numeric'
	}
}

export let mecanismProduct = (recurse, k, v) => {
	if (v.composantes) {
		//mécanisme de composantes. Voir known-mecanisms.md/composantes
		return decompose(recurse, k, v)
	}
	if (v.variations) {
		return devariate(recurse, k, v)
	}

	let objectShape = {
		assiette: false,
		taux: constantNode(1),
		facteur: constantNode(1),
		plafond: constantNode(Infinity)
	}
	let effect = ({ assiette, taux, facteur, plafond }) => {
		let mult = (base, rate, facteur, plafond) =>
			Math.min(base, plafond) * rate * facteur
		return val(taux) === 0 ||
			val(taux) === false ||
			val(assiette) === 0 ||
			val(facteur) === 0
			? 0
			: anyNull([taux, assiette, facteur, plafond])
				? null
				: mult(val(assiette), val(taux), val(facteur), val(plafond))
	}

	let explanation = parseObject(recurse, objectShape, v),
		evaluate = evaluateObject(objectShape, effect)

	let jsx = (nodeValue, explanation) => (
		<Node
			classes="mecanism multiplication"
			name="multiplication"
			value={nodeValue}
			child={
				<ul className="properties">
					<li key="assiette">
						<span className="key">assiette: </span>
						<span className="value">{makeJsx(explanation.assiette)}</span>
					</li>
					{(explanation.taux.nodeValue != 1 ||
						explanation.taux.category == 'calcExpression') && (
							<li key="taux">
								<span className="key">taux: </span>
								<span className="value">{makeJsx(explanation.taux)}</span>
							</li>
						)}
					{(explanation.facteur.nodeValue != 1 ||
						explanation.taux.category == 'calcExpression') && (
							<li key="facteur">
								<span className="key">facteur: </span>
								<span className="value">{makeJsx(explanation.facteur)}</span>
							</li>
						)}
					{explanation.plafond.nodeValue != Infinity && (
						<li key="plafond">
							<span className="key">plafond: </span>
							<span className="value">{makeJsx(explanation.plafond)}</span>
						</li>
					)}
				</ul>
			}
		/>
	)

	return {
		evaluate,
		jsx,
		explanation,
		category: 'mecanism',
		name: 'multiplication',
		type: 'numeric'
	}
}

export let mecanismScale = (recurse, k, v) => {
	// Sous entendu : barème en taux marginaux.
	// A étendre (avec une propriété type ?) quand les règles en contiendront d'autres.
	if (v.composantes) {
		//mécanisme de composantes. Voir known-mecanisms.md/composantes
		return decompose(recurse, k, v)
	}
	if (v.variations) {
		return devariate(recurse, k, v)
	}

	/* on réécrit en plus bas niveau les tranches :
	`en-dessous de: 1`
	devient
	```
	de: 0
	à: 1
	```
	*/
	let tranches = v['tranches'].map(
		t =>
			R.has('en-dessous de')(t)
				? { de: 0, à: t['en-dessous de'], taux: t.taux }
				: R.has('au-dessus de')(t)
					? { de: t['au-dessus de'], à: Infinity, taux: t.taux }
					: t
	).map(R.evolve({taux: recurse}))

	let objectShape = {
		assiette: false,
		'multiplicateur des tranches': constantNode(1)
	}

	let effect = ({
		assiette,
		'multiplicateur des tranches': multiplicateur,
		tranches
	}) => {
		// TODO traiter la récursion 'de', 'à', 'taux' pour qu'ils puissent contenir des calculs
		// ou pour les cas où toutes les tranches n'ont pas un multiplicateur commun (ex. plafond
		// sécurité sociale). Il faudra alors vérifier leur nullité comme ça :
		/*
			nulled = assiette.nodeValue == null || R.any(
				R.pipe(
					R.values, R.map(val), R.any(R.equals(null))
				)
			)(tranches),
		*/
		// nulled = anyNull([assiette, multiplicateur]),
		let nulled = val(assiette) == null || val(multiplicateur) == null

		return nulled
			? null
			: tranches.reduce(
				(memo, { de: min, à: max, taux }) =>
					val(assiette) < min * val(multiplicateur)
						? memo + 0
						: memo +
								(Math.min(val(assiette), max * val(multiplicateur)) -
									min * val(multiplicateur)) *
									taux.nodeValue,
				0
			)
	}

	let explanation = {
			...parseObject(recurse, objectShape, v),
			tranches
		},
		evaluate = evaluateObject(objectShape, effect)

	let jsx = (nodeValue, explanation) => (
		<Node
			classes="mecanism barème"
			name="barème"
			value={nodeValue}
			child={
				<ul className="properties">
					<li key="assiette">
						<span className="key">assiette: </span>
						<span className="value">{makeJsx(explanation.assiette)}</span>
					</li>
					<li key="multiplicateur">
						<span className="key">multiplicateur des tranches: </span>
						<span className="value">
							{makeJsx(explanation['multiplicateur des tranches'])}
						</span>
					</li>
					<table className="tranches">
						<thead>
							<tr>
								<th>Tranches de l'assiette</th>
								<th>Taux</th>
							</tr>
							{explanation.tranches.map(
								({
									'en-dessous de': maxOnly,
									'au-dessus de': minOnly,
									de: min,
									à: max,
									taux
								}) => (
									<tr
										key={min || minOnly || 0}
										style={{
											fontWeight:
												explanation.assiette.nodeValue *
													explanation['multiplicateur des tranches'].nodeValue >
												min
													? ' bold'
													: ''
										}}
									>
										<td key="tranche">
											{maxOnly
												? 'En dessous de ' + maxOnly
												: minOnly
													? 'Au dessus de ' + minOnly
													: `De ${min} à ${max}`}
										</td>
										<td key="taux"> {makeJsx(taux)} </td>
									</tr>
								)
							)}
						</thead>
					</table>
				</ul>
			}
		/>
	)

	return {
		evaluate,
		jsx,
		explanation,
		category: 'mecanism',
		name: 'barème',
		barème: 'en taux marginaux',
		type: 'numeric'
	}
}

export let mecanismMax = (recurse, k, v) => {
	let explanation = v.map(recurse)

	let evaluate = evaluateArray(R.max, Number.NEGATIVE_INFINITY)

	let jsx = (nodeValue, explanation) => (
		<Node
			classes="mecanism list maximum"
			name="le maximum de"
			value={nodeValue}
			child={
				<ul>
					{explanation.map((item, i) => (
						<li key={i}>
							<div className="description">{v[i].description}</div>
							{makeJsx(item)}
						</li>
					))}
				</ul>
			}
		/>
	)

	return {
		evaluate,
		jsx,
		explanation,
		type: 'numeric',
		category: 'mecanism',
		name: 'le maximum de'
	}
}

export let mecanismMin = (recurse, k, v) => {
	let explanation = v.map(recurse)

	let evaluate = evaluateArray(R.min, Infinity)

	let jsx = (nodeValue, explanation) => (
		<Node
			classes="mecanism list minimum"
			name="le minimum de"
			value={nodeValue}
			child={
				<ul>
					{explanation.map((item, i) => (
						<li key={i}>
							<div className="description">{v[i].description}</div>
							{makeJsx(item)}
						</li>
					))}
				</ul>
			}
		/>
	)

	return {
		evaluate,
		jsx,
		explanation,
		type: 'numeric',
		category: 'mecanism',
		name: 'le minimum de'
	}
}

export let mecanismComplement = (recurse, k, v) => {
	if (v.composantes) {
		//mécanisme de composantes. Voir known-mecanisms.md/composantes
		return decompose(recurse, k, v)
	}

	let objectShape = { cible: false, montant: false }
	let effect = ({ cible, montant }) => {
		let nulled = val(cible) == null
		return nulled
			? null
			: R.subtract(val(montant), R.min(val(cible), val(montant)))
	}
	let explanation = parseObject(recurse, objectShape, v)

	return {
		evaluate: evaluateObject(objectShape, effect),
		explanation,
		type: 'numeric',
		category: 'mecanism',
		name: 'complément pour atteindre',
		jsx: (nodeValue, explanation) => (
			<Node
				classes="mecanism list complement"
				name="complément"
				value={nodeValue}
				child={
					<ul className="properties">
						<li key="cible">
							<span className="key">cible: </span>
							<span className="value">{makeJsx(explanation.cible)}</span>
						</li>
						<li key="mini">
							<span className="key">montant à atteindre: </span>
							<span className="value">{makeJsx(explanation.montant)}</span>
						</li>
					</ul>
				}
			/>
		)
	}
}

export let mecanismSelection = (recurse, k, v) => {
	if (v.composantes) {
		//mécanisme de composantes. Voir known-mecanisms.md/composantes
		return decompose(recurse, k, v)
	}

	let dataSourceName = v['données']
	let dataSearchField = v['dans']
	let dataTargetName = v['renvoie']
	let explanation = recurse(v['cherche'])

	let evaluate = (cache, situationGate, parsedRules, node) => {
		let collectMissing = node => collectNodeMissing(node.explanation),
			explanation = evaluateNode(cache, situationGate, parsedRules, node.explanation),
			dataSource = findRuleByName(parsedRules, dataSourceName),
			data = dataSource ? dataSource['data'] : null,
			dataKey = explanation.nodeValue,
			dataItems =
				data && dataKey && dataSearchField
					? R.filter(item => item[dataSearchField] == dataKey, data)
					: null,
			dataItemValues =
				dataItems && !R.isEmpty(dataItems) ? R.values(dataItems) : null,
			// TODO - over-specific! transform the JSON instead
			dataItemSubValues =
				dataItemValues && dataItemValues[0][dataTargetName]
					? dataItemValues[0][dataTargetName]['taux']
					: null,
			sortedSubValues = dataItemSubValues
				? R.sortBy(pair => pair[0], R.toPairs(dataItemSubValues))
				: null,
			// return 0 if we found a match for the lookup but not for the specific field,
			// so that component sums don't sum to null
			nodeValue = dataItems
				? sortedSubValues
					? Number.parseFloat(R.last(sortedSubValues)[1]) / 100
					: 0
				: null
		return rewriteNode(node, nodeValue, explanation, collectMissing)
	}

	let indexOf = explanation =>
		explanation.nodeValue
			? R.findIndex(
				x => x['nomLaposte'] == explanation.nodeValue,
				taux_versement_transport
			)
			: 0
	let indexOffset = 8

	let jsx = (nodeValue, explanation) => (
		<Node
			classes="mecanism"
			name="sélection"
			value={nodeValue}
			child={
				<Table
					width={300}
					height={300}
					headerHeight={20}
					rowHeight={30}
					rowCount={taux_versement_transport.length}
					scrollToIndex={indexOf(explanation) + indexOffset}
					rowStyle={({ index }) =>
						index == indexOf(explanation) ? { fontWeight: 'bold' } : {}}
					rowGetter={({ index }) => {
						// transformation de données un peu crade du fichier taux.json qui gagnerait à être un CSV
						let line = taux_versement_transport[index],
							getLastTaux = dataTargetName => {
								let lastTaux = R.values(R.path([dataTargetName, 'taux'], line))
								return (lastTaux && lastTaux.length && lastTaux[0]) || 0
							}
						return {
							nom: line['nomLaposte'],
							taux: getLastTaux(dataTargetName)
						}
					}}
				>
					<Column label="Nom de commune" dataKey="nom" width={200} />
					<Column width={100} label={'Taux ' + dataTargetName} dataKey="taux" />
				</Table>
			}
		/>
	)

	return {
		evaluate,
		explanation,
		jsx
	}
}

export let mecanismError = (recurse, k, v) => {
	throw 'Le mécanisme \'' + k + '\' est inconnu !' + v
}