var EventEmitter = require('events');
var libob = require('libobject');
var Load = require('./load');

module.exports = function Parse (scope, emitter, instance, event, options) {

    instance.parsed[event] = instance.parsed[event] || new EventEmitter();

    if (!scope.get(instance.parsed[event], emitter, 'event')) {
        process.nextTick(parse, scope, instance.parsed[event], instance, event, options);
    }

    return emitter;
};

function parse (scope, sequence, instance, event, options) {

    if (!instance.flow || !instance.flow[event]) {
        return sequence.emit('error', new Error('Flow.parse: Event not found on instance.'));
    }

    if (!instance.flow[event].d) {
        return sequence.emit('error', new Error('Flow.parse: No data handlers.'));
    }

    var parsedEvent = parseEvent(scope, instance, instance.flow[event].d);
    var count = 0;

    if (parsedEvent.l.length > 0) {
        sequence.on('_flow_load', function (instance) {
            if (++count === parsedEvent.l.length) {
                parseSequence(scope, sequence, parsedEvent.s);
            }
        });

        parsedEvent.l.forEach(function (instName) {
            Load(scope, sequence, instName, options);
        });

    } else {
        parseSequence(scope, sequence, parsedEvent.s);
    }
}

function parseEvent (scope, instance, config) {

    var instances = {};
    var sequences = [];
    var pointer = 0;

    config.forEach(function (handler) {

        // resolve handler
        var path = handler;
        var args = {};

        if (handler.constructor === Array) {
            path = handler[0];
            args = handler[1] || {};
        }

        var type = path[0];
        path = path.substr(1);

        if (type === ':' || type === '.') {

            path = scope.path(path, instance.name);

            if (!scope.cache[path[0]] || !scope.cache[path[0]].ready) {
                instances[path[0]] = 1;
            }

            sequences[pointer] = sequences[pointer] || {};
            sequences[pointer].s = sequences[pointer].s || [];
            sequences[pointer].s.push([path, args, instance.inst, (type === '.')]);
            return;
        }
        
        if (type === '>' || type === '|') {

            var net = path[0];
            path = scope.path(path.substr(1), instance.name);

            if (!scope.cache[path[0]] || !scope.cache[path[0]].ready) {
                instances[path[0]] = 1;
            }

            sequences.push({
                t: net,
                n: type,
                p: path,
                a: args
            });

            ++pointer;

            return; 
        }

        sequence.emit('error', new Error('Flow.parse: Invalid handler type:', type));
    });

    return {
        l: Object.keys(instances),
        s: sequences
    };
}

// update sequences with method refs
function parseSequence (scope, event, sequences) {

    for (var i = 0, l = sequences.length, sequence; i < l; ++i) {
        sequence = sequences[i];

        // sequence path
        if (sequence.p) {
            sequence.p[0] = scope.cache[sequence.p[0]].inst;
            if (sequence.t === '*' && !(sequence.p[1] = libob.path(sequence.p[1], sequence.p[0]))) {
                return event.emit('error', new Error('Flow.parse: Method "' + sequence[1] + '" not found.'));
            }
        }

        // sequence handlers
        if (sequence.s) {
            sequence.s.forEach(function (value, index) {

                value[0][0] = scope.cache[value[0][0]].inst;

                if (!(value[0] = libob.path(value[0][1], value[0][0]))) {
                    return event.emit('error', new Error('Flow.parse: Method on instance "' + value[0]._name + '" not found.'));
                }
            });
        }
    }

    event.s = sequences;
    event.ready = true;
    event.emit('ready', event);
}

@@ -1708,89 +1708,8 @@
 th =
- path.substr(1);%0A%0A        if (type === ':' %7C%7C type === '.') %7B%0A%0A            path =
  sco
@@ -1720,16 +1720,26 @@
 ath(path
+.substr(1)
 , instan
@@ -1749,36 +1749,32 @@
 name);%0A%0A        
-  
-  
 if (!scope.cache
@@ -1821,36 +1821,32 @@
 ) %7B%0A            
-    
 instances%5Bpath%5B0
@@ -1853,39 +1853,137 @@
 %5D%5D = 1;%0A        
+%7D%0A%0A
     
-%7D%0A%0A
+    switch (type) %7B%0A%0A            // data handlers%0A            case ':':%0A            case '.':%0A    
             sequ
@@ -2029,32 +2029,36 @@
 %7B%7D;%0A            
+   
+ 
 sequences%5Bpointe
@@ -2088,24 +2088,28 @@
 r%5D.s %7C%7C %5B%5D;%0A
+    
             
@@ -2196,16 +2196,20 @@
     
+    
 return;%0A
     
@@ -2208,293 +2208,88 @@
 rn;%0A
-        %7D%0A        %0A        if (type === '%3E' %7C%7C type === '%7C') %7B%0A%0A            var net = path%5B0%5D;%0A            path = scope.path(path.substr(1), instance.name);%0A%0A            if (!scope.cache%5Bpath%5B0%5D%5D %7C%7C !scope.cache%5Bpath%5B0%5D%5D.ready) %7B%0A                instances%5Bpath%5B0%5D%5D = 1;%0A            %7D%0A%0A
+%0A            // stream handlers%0A            case '%3E':%0A            case '*':%0A    
     
@@ -2328,21 +2328,8 @@
     
-     t: net,%0A
     
@@ -2337,24 +2337,17 @@
     
-       n
+t
 : type,%0A
     
@@ -2342,16 +2342,20 @@
 : type,%0A
+    
         
@@ -2387,16 +2387,20 @@
         
+   
+ 
 a: args%0A
@@ -2403,32 +2403,36 @@
 rgs%0A            
+    
 %7D);%0A%0A           
@@ -2432,16 +2432,20 @@
         
+   
+ 
 ++pointe
@@ -2447,17 +2447,20 @@
 ointer;%0A
-%0A
+    
         
@@ -2470,17 +2470,16 @@
  return;
- 
 %0A       

remove next options in flow config