<!DOCTYPE html>
<html>

  <head>
    <link rel="stylesheet" href="style.css">
  </head>

  <body>
    <h1>Lodash Playground</h1>
    
    <div id="results"></div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.js"></script>
    <script src="script.js"></script>
  </body>

</html>
// Generic code to display resuts

var results = document.getElementById('results');
function showHTML(html)
{
  results.insertAdjacentHTML('beforeend', html);
}
function show(text)
{
  showHTML("<p>" + text + "<p>");
}
function showObject(obj)
{
  show("<p>" + JSON.stringify(obj) + "<p>");
}


// The real code

var dest = { name: 'Foo', age: 25, driver: true, 
    id: { driverLicense: '88-65', ssn: '1-54-455', other: 'mango' }  };
var src1 = { name: 'Bar', driver: false, address: 'Here and there', 
    id: { driverLicense: undefined, ssn: '2-44-985', pwd: '123' }  };
var src2 = { name: 'Moo', maried: true, age: undefined, address: 'Somewhere', 
    id: { driverLicense: '11-75', ssn: undefined, warcry: 'Kowabunga' } };

var d1 = _.cloneDeep(dest);
var d2 = _.cloneDeep(dest);
var d3 = _.cloneDeep(dest);

/*
showHTML("<h2>Comparison of functions overriding properties</h2>");
showHTML("<h3>Data</h3>");
showHTML("<h4>dest</h4>");
showObject(dest);
showHTML("<h4>src1</h4>");
showObject(src1);
showHTML("<h4>src2</h4><p><i>src2.age = undefined & src2.id.ssn = undefined</i></p>");
showObject(src2);

showHTML("<h3>Results</h3>");

showHTML("<h4>_.assign(dest, src1, src2)</h4><p><i>assign (alias extend) overwrites all properties with successive values, including source properties set to undefined</i></p>");
showObject(_.assign(dest, src1, src2));

showHTML("<h4>_.merge(dest, src1, src2)</h4><p><i>merge overwrites deeply all properties with successive values, except undefined source properties</i></p>");
showObject(_.merge(d1, src1, src2));

showHTML("<h4>_.defaults(dest, src1, src2)</h4><p><i>defaults assigns properties which are undefined: no overwriting of existing properties</i></p>");
showObject(_.defaults(d2, src1, src2));

showHTML("<h4>_.defaultsDeep(dest, src1, src2)</h4><p><i>defaultsDeep assigns deeply properties which are undefined: no overwriting of existing properties</i></p>");
showObject(_.defaultsDeep(d3, src1, src2));
//*/

//==========

showHTML("<h2>Other tests</h2>");

var arr = _.range(500);
var filter = function(item) 
{
//    console.log('filtering ' + item);
    return item % 2;
};
//_(arr).filter(filter).drop(2).take(5).value();

showObject(_(arr).filter(filter).take(5 + 2).drop(2).value());

showObject(_.has(dest, 'id.ssn'));
showObject(_.has(d2, 'id.warcry'));
showObject(_.has(src2, 'id.warcry'));
showObject(_.has(src2, 'id.ssn'));

var o1 = { id: '1' }, o2 = { id: '2' }, o3 = { id: '3' };
var ao = [ o1, o2, o3 ];
showObject(ao);
_.remove(ao, o2);
showObject(ao);

var f1 = function() { show('F1'); };
var f2 = function() { show('F2'); };
var af = [ f1, f2 ];
_.forEach(af, Object.prototype.call);

f1 = function(p) { return 'F1(' + p + ')'; };
f2 = function(p) { return 'F2(' + p + ')'; };
var flowRightArray = _.spread(_.flowRight);
var composed = flowRightArray([ f1, f2 ]);
show(composed('Value'));

var someObject = { f1: f1, f2: f2, other: 'not a function' };
var cleanObject = _.pick(someObject, _.isFunction);
showObject(cleanObject); // Empty as it shows only non-function properties...
showObject(_.functions(cleanObject)); // And shows the list of functions
var empty = _.mapValues(cleanObject);
showObject(_.keys(empty));

//==========

showHTML("<h2>Chaining</h2>");

function twoParams(p1, p2)
{
    if (_.isUndefined(p1))
    {
        if (_.isUndefined(p2))
        {
            return "No defined parameters";
        }
        return "Only p2: " + p2;
    }
    else
    {
        if (_.isUndefined(p2))
        {
            return "Only p1: " + p1;
        }
    }
    return "With p1: " + p1 + " and p2: " + p2;
}
var lastR = _(twoParams).ary(1).rearg([1, 0]).value();
var lastS = _(twoParams).ary(1).spread().value();

show("<h3>raw twoParams</h3>");
show(twoParams());
show(twoParams("Foo"));
show(twoParams("Bar", "Baz"));
show(twoParams(undefined, "Moo"));

show("<h3>rearg and ary</h3>");
show(lastR("Foo", undefined));
show(lastR("Bar", "Baz"));
show(lastR(undefined, "Moo"));

show("<h3>spead and ary</h3>");
show(lastS(["Foo", undefined]));
show(lastS(["Bar", "Baz"]));
show(lastS([undefined, "Moo"]));


//==========

showHTML("<h2>Cloning</h2>");

var list = [ { id: 'one', name: 'The One' }, { id: 'two', name: 'Tea for Two' } ];
var cloneList = _.clone(list);
cloneList[1].name = 'Two Too';
showObject(list);
_.remove(cloneList);
showObject(cloneList);

//==========

showHTML("<h2>Extracting</h2>");

var list = 
[ 
  { src: 'one', gr: 'HRS', pis: [ 'a', 'b', 'c' ] }, 
  { src: 'two', gr: 'MIN', pis: [ 'A', 'B', 'C', 'D' ] } ,
  { src: 'two', gr: 'HRS', pis: [ 'X', 'Y' ] } 
];

showObject(list);

//extracted = _.flatten(_.map(list, function(o) { return o.data; }));
// extracted = _(list).map(function(o) { return o.data; }).flatten().value();
var extractedRaw = _.reduce(list, function(accItems, item)
{
  accItems.push(_.reduce(item.pis, function(accPis, pi)
  {
    accPis.push({ pi: pi, src: item.src, gr: item.gr });
    
    return accPis;
  }, []));
  
  return accItems;
}, []);
var extracted = _.flatten(extractedRaw);


showObject(extracted);

//==========

showHTML("<h2>Enrich</h2>");


var listStuff = function(dataId, limit, offset)
{
    return {
        type: 'LIST_STUFF',
        payload:
        {
            id: dataId,
            paging:
            {
                limit: limit,
                offset: offset
            }
        }
    };
};
var listStuffSimpler = function(dataId)
{
    return {
        type: 'LIST_STUFF',
        payload:
        {
            id: dataId
        }
    };
};

var doForA = function(actionGenerator, callerId)
{
    return function()
    {
        var actionF = _.spread(actionGenerator);
        console.log(actionF);
        var action = _.extend(actionF(arguments), { origin: callerId });
        return action;
    };
};

var doFor = function(actionGenerator, callerId)
{
    return function()
    {
        var action = actionGenerator.apply(null, arguments);
        action.origin = callerId;
        return action;
    };
};

var forId = function(callerId)
{
  var makeAction = function(actionGenerator) 
  {
    var withParams = function() 
    {
      var action = actionGenerator.apply(null, arguments);
      action.origin = callerId;
      return action;
    };
    
    var f =
    {
      withParams: withParams
    };
    return f;
  };
  
  var f = 
  { 
    makeAction: makeAction
  };
  return f;
};

var createAction = function(actionGenerator)
{
    var builder =
    {
        action: { payload: {} },

        forId: function(callerId)
        {
            this.action.origin = callerId;
            return this;
        },
        withPaging: function(limit, offset)
        {
            this.action.payload.paging = { limit: limit, offset: offset };
            return this;
        },

        // Final method
        withParams: function()
        {
            var rawAction = actionGenerator.apply(null, arguments);
            _.merge(rawAction, this.action);
            return rawAction;
        }
    };
    return builder;
};

var actionA = doFor(listStuff, 'some id')('id for request', 100, 5);
showObject(actionA);
var actionB = forId('some id').makeAction(listStuff).withParams('id for request', 100, 5);
showObject(actionB);
var actionC = createAction(listStuffSimpler).forId('some id').withPaging(100, 5).withParams('id for request');
showObject(actionC);

//==========
/*
showHTML("<h2>And now for something completely different: moment.js</h2>");

show(moment('2012-1').format('MMMM'));

show(moment('2012').format());
show(moment('2012-10').format());
show(moment('2012-10-11').format());
show(moment('2012-10-11 13').format());
show(moment('2012-10-11 13:44').format());
show(moment('2012-10-11 13:48:55').format());
show(moment('2012-G-11 13:48:55').format());
show(moment('2012-G-11 13:48:55'));
show(moment('2012-G-11 13:48:55').valueOf());
*/


/* Styles go here */