var cheerio = require('cheerio');
var url = require('url');
var Entities = require('html-entities').AllHtmlEntities;
var entities = new Entities();
var helpers = require('./helpers');
var async = require('async');

// helper to access nested objects with string literals as object key. Example -> Object.byString(someObj, 'part3[0].name');
Object.byString = helpers.byString;

exports = module.exports =  function (feed, posts, callback) {
    var valid = true;
    var ranking = 0;
    var entries = [];

    async.eachSeries(posts,
        function(post, callback) {
            var entry = {
                _source: feed.name,
                _origin: post.meta.link,
                _host: url.parse(post.meta.link).host,
                _ranking: ranking++
            };

            feed.template.elements.forEach(function (element) {
                var holder;

                if (element.required) {
                    valid = false;
                }

                element.items.forEach(function (item) {
                    var active = false;
                    // get the entry element
                    if (item.scrape) {
                        var $ = cheerio.load(Object.byString(post, item.selector));
                        holder = $(item.scrape.selector).attr(item.scrape.attribute);
                    }
                    else if (item.decode) {
                        holder = entities.decode(Object.byString(post, item.selector) || '');
                    }
                    else {
                        holder = Object.byString(post, item.selector);
                    }

                    // set item if it has been found
                    if (holder && !entry[element.name]) {
                        entry[element.name] = holder;
                        active = true;
                    }
                });

                // add fallback if supplied
                if (element.fallback && !entry[element.name]) {
                    entry[element.name] = element.fallback;
                }

                if (entry[element.name] && (element.type == 'url')) {
                    entry[element.name] = helpers.fixRelativePath(entry[element.name], entry.source);
                }

                // check if item is required for entry to be valid, and then check if item is set
                if (element.required && entry[element.name]) {
                    valid = true;
                }
            });

            entry = valid ? entry : null;
            entries.push(entry);
            callback();
        },
        function(err, results) {
            callback(err, entries);
        });
};

@@ -442,24 +442,29 @@
    var valid
+Entry
  = true;%0A   
@@ -874,102 +874,8 @@
 r;%0A%0A
-                if (element.required) %7B%0A                    valid = false;%0A                %7D%0A%0A
     
@@ -2246,16 +2246,179 @@
  is set%0A
+                // validEntry cascades through every item, so that all required properties must be valid%0A                // to get make validEntry true at the end%0A
         
@@ -2449,16 +2449,17 @@
 ired && 
+!
 entry%5Bel
@@ -2498,18 +2498,102 @@
    valid
- =
+Entry = false;%0A                %7D else %7B%0A                    validEntry = validEntry &&
  true;%0A 
@@ -2618,32 +2618,32 @@
            %7D);%0A%0A
-
             entr
@@ -2651,16 +2651,21 @@
  = valid
+Entry
  ? entry

make requiring fields work as expected