'use strict';

var df = require('datafixture.js');
var _ = require('lodash');

var WHITESPACE = /\s/;
var NEWLINE = /\n/g;
var GUID = /.*-.*-.*-.*/;
var DECIMAL = /\d*$/;

function value(value) {
    return function () {
        return value;
    };
}

function stringConverter(stringValue) {
    var hasWhitespace = stringValue.match(WHITESPACE);
    var hasNewLine = stringValue.match(NEWLINE);
    if (hasWhitespace && !hasNewLine) {
        return 'lorem:1...' + (hasWhitespace.length + 1);
    } else if (hasWhitespace && hasNewLine) {
        return 'plorem:' + (hasNewLine.length + 1);
    } else if (stringValue.length === 0) {
        return 'lorem:0...1';
    }
    return stringValue.match(GUID) ? 'GUID' : 'lorem:1';
}

function arrayConverter(arrayValue) {
    return function () {
        return _.map(arrayValue, convert);
    };
}

function numberConverter(numberValue) {
    if (numberValue === Infinity) {
        return value(Infinity);
    }
    if (numberValue === -Infinity) {
        return value(-Infinity);
    }
    if (_.isNaN(numberValue)) {
        return value(NaN);
    }
    var mainRange = numberValue <= 0 ? Math.floor(numberValue) + '...0' : '1...' + Math.ceil(numberValue);
    return mainRange + (numberValue % 1 === 0 ? '' : ':' + DECIMAL.exec(numberValue)[0].length);
}

function FallbackConverterBuilder(fallbacks) {
    return {
        thenMatch: function (predicate, converter) {
            return new FallbackConverterBuilder(_.compact(fallbacks).concat([[predicate, converter]]));
        },
        buildWithDefault: function (defaultConverter) {
            return function (value) {
                var converterToUse = _.find(fallbacks, function(conditionAndConverter) {
                    return conditionAndConverter[0](value);
                });
                return (converterToUse[1] || defaultConverter)(value);
            };
        }
    }
}

function booleanConverter() {
    return function () {
        return df.getRandom(0, 1) === 0;
    };
}

function objectConverter(objectValue) {
    if (_.isDate(objectValue)) {
        return function () {
            return new Date();
        };
    }

    return  _.reduce(objectValue, function (memo, value, name) {
        memo[name] = convert(value);
        return memo;
    }, {});
}

var convert = new FallbackConverterBuilder()
    .thenMatch(_.isNull, value(undefined))
    .thenMatch(_.isUndefined, value(undefined))
    .thenMatch(_.isBoolean, booleanConverter)
    .thenMatch(_.isString, stringConverter)
    .thenMatch(_.isArray, arrayConverter)
    .thenMatch(_.isNumber, numberConverter)
    .thenMatch(_.isObject, objectConverter)
    .buildWithDefault(function(value) {
        throw new Error('no converter found for ' + JSON.stringify(value));
    });

module.exports = convert;
@@ -845,470 +845,8 @@
 %0A%7D%0A%0A
-function numberConverter(numberValue) %7B%0A    if (numberValue === Infinity) %7B%0A        return value(Infinity);%0A    %7D%0A    if (numberValue === -Infinity) %7B%0A        return value(-Infinity);%0A    %7D%0A    if (_.isNaN(numberValue)) %7B%0A        return value(NaN);%0A    %7D%0A    var mainRange = numberValue %3C= 0 ? Math.floor(numberValue) + '...0' : '1...' + Math.ceil(numberValue);%0A    return mainRange + (numberValue %25 1 === 0 ? '' : ':' + DECIMAL.exec(numberValue)%5B0%5D.length);%0A%7D%0A%0A
 func
@@ -884,24 +884,24 @@
 allbacks) %7B%0A
+
     return %7B
@@ -1374,14 +1374,30 @@
 oUse
+ ? converterToUse
 %5B1%5D 
-%7C%7C
+:
  def
@@ -1845,19 +1845,505 @@
 %7D, %7B%7D);%0A
-
 %7D%0A%0A
+var numberConverter = new FallbackConverterBuilder()%0A    .thenMatch(_.partial(_.isEqual, Infinity), value(Infinity))%0A    .thenMatch(_.partial(_.isEqual, -Infinity), value(-Infinity))%0A    .thenMatch(_.isNaN, value(NaN))%0A    .buildWithDefault(function(numberValue) %7B%0A        var mainRange = numberValue %3C= 0 ? Math.floor(numberValue) + '...0' : '1...' + Math.ceil(numberValue);%0A        return mainRange + (numberValue %25 1 === 0 ? '' : ':' + DECIMAL.exec(numberValue)%5B0%5D.length);%0A    %7D);%0A%0A
 var conv

refactor to use fallbacks instead of a giga-if-else