'use strict';

var _ = require('underscore');
var errors = require('../../errors');



function is_runaway(read_node, g) {

    function node_type(node) {
        // temp while grammar refactor is in progress; once complete we should be
        // able to always look up .name
        return node.name || node.type;
    }

    function multiple_inputs(node) {
        return g.node_get_inputs(node).length > 1;
    }
    // historical read
    if (g.node_get_option(read_node, 'to') || g.node_get_option(read_node, 'last')) {
        return;
    }

    var outs;
    var next_node = read_node;
    while (true) {
        outs = g.node_get_outputs(next_node);

        // Keeping things simple for now and only considering linear topologies
        // (which means we won't flag all possible runaways)
        if (outs.length !== 1 || _.any(outs, multiple_inputs)) {
            return;
        }

        next_node = outs[0];

        switch (node_type(next_node)) {
            case 'batch':
                return;
            case 'tail':
                throw errors.compileError('RUNAWAY-PROGRAM', {extra: 'Add a -to option to read?'});
            case 'ReduceProc':
                if (!g.node_has_option(next_node, 'every')) {
                    throw errors.compileError('RUNAWAY-PROGRAM', {extra: 'Add a -to option to read or a -every option to reduce?'});
                }
                break;
            case 'SortProc':
                throw errors.compileError('RUNAWAY-PROGRAM', {extra: 'Add a -to option to read?'});
            default:
                break;
        }
    }
}

function check_runaways(g) {
    var reads = _.where(g.get_roots(), {type: 'ReadProc', name: 'read'});
    _.each(reads, function(node) {is_runaway(node, g);});
}

module.exports = check_runaways;

@@ -78,18 +78,16 @@
 ors');%0A%0A
-%0A%0A
 function
@@ -89,18 +89,17 @@
 ction is
-_r
+R
 unaway(r
@@ -105,16 +105,19 @@
 read
-_n
+N
 ode, g
+raph
 ) %7B%0A
@@ -130,26 +130,25 @@
 unction node
-_t
+T
 ype(node) %7B%0A
@@ -332,26 +332,25 @@
 ion multiple
-_i
+I
 nputs(node) 
@@ -367,16 +367,20 @@
 return g
+raph
 .node_ge
@@ -444,16 +444,20 @@
    if (g
+raph
 .node_ge
@@ -465,26 +465,25 @@
 _option(read
-_n
+N
 ode, 'to') %7C
@@ -485,16 +485,20 @@
 o') %7C%7C g
+raph
 .node_ge
@@ -510,18 +510,17 @@
 ion(read
-_n
+N
 ode, 'la
@@ -572,26 +572,25 @@
     var next
-_n
+N
 ode = read_n
@@ -587,18 +587,17 @@
 e = read
-_n
+N
 ode;%0A   
@@ -628,16 +628,20 @@
 outs = g
+raph
 .node_ge
@@ -650,26 +650,25 @@
 outputs(next
-_n
+N
 ode);%0A%0A     
@@ -856,18 +856,17 @@
 multiple
-_i
+I
 nputs)) 
@@ -910,18 +910,17 @@
     next
-_n
+N
 ode = ou
@@ -951,18 +951,17 @@
 node
-_t
+T
 ype(next
 _nod
@@ -956,18 +956,17 @@
 ype(next
-_n
+N
 ode)) %7B%0A
@@ -1094,32 +1094,53 @@
 AWAY-PROGRAM', %7B
+%0A                    
 extra: 'Add a -t
@@ -1149,32 +1149,49 @@
 option to read?'
+%0A                
 %7D);%0A            
@@ -1231,16 +1231,20 @@
   if (!g
+raph
 .node_ha
@@ -1260,10 +1260,9 @@
 next
-_n
+N
 ode,
@@ -1332,32 +1332,57 @@
 AWAY-PROGRAM', %7B
+%0A                        
 extra: 'Add a -t
@@ -1428,16 +1428,37 @@
 reduce?'
+%0A                    
 %7D);%0A    
@@ -1585,16 +1585,37 @@
 GRAM', %7B
+%0A                    
 extra: '
@@ -1640,16 +1640,33 @@
 o read?'
+%0A                
 %7D);%0A    
@@ -1734,26 +1734,25 @@
 nction check
-_r
+R
 unaways(g) %7B
@@ -1748,16 +1748,20 @@
 naways(g
+raph
 ) %7B%0A    
@@ -1781,16 +1781,20 @@
 .where(g
+raph
 .get_roo
@@ -1800,16 +1800,25 @@
 ots(), %7B
+%0A        
 type: 'R
@@ -1826,16 +1826,24 @@
 adProc',
+%0A       
  name: '
@@ -1847,20 +1847,26 @@
 : 'read'
+%0A    
 %7D);%0A
+%0A
     _.ea
@@ -1893,18 +1893,17 @@
 ode) %7Bis
-_r
+R
 unaway(n
@@ -1908,16 +1908,20 @@
 (node, g
+raph
 );%7D);%0A%7D%0A
@@ -1943,18 +1943,17 @@
  = check
-_r
+R
 unaways;

clean up runaway detector code