/**
 * Copyright 2014 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/
 
var should = require("should");
var sinon = require("sinon");
var when = require("when");
var flows = require("../../../red/nodes/flows");
var RedNode = require("../../../red/nodes/Node");
var RED = require("../../../red/nodes");
var events = require("../../../red/events");
var typeRegistry = require("../../../red/nodes/registry");


var settings = {
    available: function() { return false; }
}

function loadFlows(testFlows, cb) {
    var storage = {
        getFlows: function() {
            return when.resolve(testFlows);
        },
        getCredentials: function() {
            return when.resolve({});
        }
    };
    RED.init(settings, storage);
    flows.load().then(function() {
        should.deepEqual(testFlows, flows.getFlows());
        cb();
    });
}

describe('flows', function() {

    afterEach(function(done) {
        flows.stopFlows().then(function() {
            loadFlows([],done);
        });
    });

    describe('#load',function() {

        it('should load nothing when storage is empty',function(done) {
            loadFlows([], done);
        });

        it('should load and start an empty tab flow',function(done) {
            loadFlows([{"type":"tab","id":"tab1","label":"Sheet 1"}], function() {});
            events.once('nodes-started', function() { done(); });
        });

        it('should load and start a registered node type', function(done) {
            RED.registerType('debug', function() {});
            var typeRegistryGet = sinon.stub(typeRegistry,"get",function(nt) {
                return RedNode;
            });
            loadFlows([{"id":"n1","type":"debug"}], function() { });
            events.once('nodes-started', function() {
                typeRegistryGet.restore();
                done();
            });
        });

        it('should load and start when node type is registered', function(done) {
            var typeRegistryGet = sinon.stub(typeRegistry,"get");
            typeRegistryGet.onCall(0).returns(null);
            typeRegistryGet.returns(RedNode);
            loadFlows([{"id":"n2","type":"inject"}], function() {
                events.emit('type-registered','inject');
            });
            events.once('nodes-started', function() {
                typeRegistryGet.restore();
                done();
            });
        });
        
        it('should not instantiate nodes of an unused subflow', function(done) {
            RED.registerType('abc', function() {});
            var typeRegistryGet = sinon.stub(typeRegistry,"get",function(nt) {
                return RedNode;
            });
            loadFlows([{"id":"n1","type":"subflow",inputs:[],outputs:[],wires:[]},
                       {"id":"n2","type":"abc","z":"n1",wires:[]}
                      ],function() { });
            events.once('nodes-started', function() {
                (flows.get("n2") == null).should.be.true;
                var ncount = 0
                flows.eachNode(function(n) {
                    ncount++;
                });
                ncount.should.equal(0);
                typeRegistryGet.restore();
                done();
            });
        });
        it('should instantiate nodes of an used subflow with new IDs', function(done) {
            RED.registerType('abc', function() {});
            var typeRegistryGet = sinon.stub(typeRegistry,"get",function(nt) {
                return RedNode;
            });
            loadFlows([{"id":"n1","type":"subflow",inputs:[],outputs:[]},
                       {"id":"n2","type":"abc","z":"n1","name":"def",wires:[]},
                       {"id":"n3","type":"subflow:n1"}
                      ], function() { });
            events.once('nodes-started', function() {
                // n2 should not get instantiated with that id
                (flows.get("n2") == null).should.be.true;
                var ncount = 0
                var nodes = [];
                flows.eachNode(function(n) {
                    nodes.push(n);
                });
                nodes.should.have.lengthOf(2);
                
                // Assume the nodes are instantiated in this order - not
                // a requirement, but makes the test easier to write.
                nodes[0].should.have.property("id","n3");
                nodes[0].should.have.property("type","subflow:n1");
                nodes[1].should.not.have.property("id","n2");
                nodes[1].should.have.property("name","def");
                
                // TODO: verify instance wiring is correct
                typeRegistryGet.restore();
                done();
            });
        });
    });

    describe('#setFlows',function() {
        it('should save and start an empty tab flow',function(done) {
            var saved = 0;
            var testFlows = [{"type":"tab","id":"tab1","label":"Sheet 1"}];
            var storage = {
                saveFlows: function(conf) {
                    var defer = when.defer();
                    defer.resolve();
                    should.deepEqual(testFlows, conf);
                    return defer.promise;
                },
                saveCredentials: function (creds) {
                    return when(true);
                }
            };
            RED.init(settings, storage);
            flows.setFlows(testFlows);
            events.once('nodes-started', function() { done(); });
        });
    });

});
