var Request = require('../../lib/net/Request').Request;
var Event = require('../../lib/event/Event.js').Event;
var ErrorEvent = require('../../lib/event/ErrorEvent').ErrorEvent;
var Random = require('../../lib/common/Random.js');
var http = require('http');

describe('Loader', function () {
    it('should require', function () {
        var Loader;

        expect(function () {
            Loader = require('../../lib/net/Loader.js').Loader;
        }).not.toThrow();

        expect(Loader).toBeTruthy();
    });

    describe('loader', function () {
        var Loader;

        beforeEach(function () {
            Loader = require('../../lib/net/Loader.js').Loader;
            this._loader = new Loader();
        });

        describe('getRequest/setRequest', function () {
            describe('getRequest', function () {
                it('should return null', function () {
                    expect(this._loader.getRequest()).toBeNull();
                });
            });

            describe('setRequest', function () {
                it('should throw if not Request subclass passed', function () {
                    var X = function () {};

                    expect((function () {
                        this._loader.setRequest(new X())
                    }).bind(this)).toThrow();
                });

                it('should NOT throw if Request instance passed', function () {
                    expect((function () {
                        this._loader.setRequest(new Request());
                    }).bind(this)).not.toThrow();
                });
            });
        });

        describe('load', function () {
            beforeEach(function () {
                spyOn(Loader.prototype, 'dispatchEvent').andCallThrough();
                spyOn(console, 'info').andCallThrough();

                this._r = new Request('/');
                this._r.setHeader('host', 'www.onet.pl');
                this._r.setConnectionHost('fx.m1r2.onet');

                this._loader.setForwardedHost('www.kubek.pl');
            });

            describe('no Request passed', function () {
                it('should throw', function () {
                    expect((function () {
                        this._loader.load();
                    }).bind(this)).toThrow();
                });
            });

            describe('empty Request passed', function () {
                beforeEach(function () {
                    this._loader.load(new Request());
                });


                it('should dispatch Error', function () {
                    expect(Loader.prototype.dispatchEvent).toHaveBeenCalled()
                });

                it('should log monitoring', function () {
                    expect(console.info.callCount).toEqual(1);
                    expect(console.info).toHaveBeenCalledWith(jasmine.any(String), 'www.kubek.pl', null, 0, jasmine.any(Number), 0, Request.GET, null);
                });
            });

            describe('nodejs client error', function () {
                beforeEach(function () {
                    spyOn(http, 'request').andCallFake(function () {
                        return {
                            'addListener': function (ev, cb) {
                                this._cb = cb;
                            },
                            'end': function () {
                                this._cb({});
                            }
                        };
                    });

                    this._loader.load(this._r);
                });

                it('should dispatch Error', function () {
                    expect(Loader.prototype.dispatchEvent).toHaveBeenCalled()
                });

                it('should log monitoring', function () {
                    expect(console.info.callCount).toEqual(1);
                    expect(console.info).toHaveBeenCalledWith(jasmine.any(String), 'www.kubek.pl', 'www.onet.pl', 0, jasmine.any(Number), 0, Request.GET, 'fx.m1r2.onet');
                });
            });

            describe('nodejs client timeout', function () {
                beforeEach(function () {
                    spyOn(http, 'request').andCallFake(function () {
                        return {
                            'addListener': function (ev, cb) {
                                this._cb = cb;
                            },
                            'removeAllListeners': function () {},
                            'abort': function () {},
                            'end': function () {
                            }
                        };
                    });

                    spyOn(global, 'setTimeout').andCallFake(function (fn) {
                        fn();
                    });

                    this._loader.load(this._r);
                });

                it('should dispatch Error', function () {
                    expect(Loader.prototype.dispatchEvent).toHaveBeenCalled();
                });

                it('should log monitoring', function () {
                    expect(console.info.callCount).toEqual(1);
                    expect(console.info).toHaveBeenCalledWith(jasmine.any(String), 'www.kubek.pl', 'www.onet.pl', 0, jasmine.any(Number), 0, Request.GET, 'fx.m1r2.onet');
                });
            });

            describe('nodejs client success', function () {
                beforeEach(function () {
                    var that = this;

                    this._m = new http.IncomingMessage();

                    spyOn(http, 'request').andCallFake(function (options, callback) {
                        return {
                            'addListener': function (ev, cb) {
                                this._cb = cb;
                            },
                            'removeAllListeners': function () {},
                            'abort': function () {},
                            'end': function () {
                                callback(that._m);
                            }
                        };
                    });

                    var first = true;

                    spyOn(http.IncomingMessage.prototype, 'addListener').andCallFake(function (ev, cb) {
                        if (ev == 'data' && first) {
                            cb(new Buffer(Random.randomString(128)));
                            cb(new Buffer(Random.randomString(128)));
                            first = false;
                        }
                        if (ev == 'end') {
                            cb();
                        }
                    });

                });

                describe('nodejs client success 30x', function () {
                    beforeEach(function () {
                        this._m.statusCode = 301;
                        this._m.headers.location = 'http://facet.onet.pl';

                        this._loader.load(this._r);
                    });

                    it('should dispatch Error', function () {
                        expect(Loader.prototype.dispatchEvent).toHaveBeenCalled();
                    });

                    it('should log monitoring', function () {
                        expect(console.info.callCount).toEqual(this._loader.getMaxRedirectsCount() + 1);
                        expect(console.info).toHaveBeenCalledWith(jasmine.any(String), 'www.kubek.pl', 'www.onet.pl', 301, jasmine.any(Number), 256, Request.GET, 'fx.m1r2.onet');
                        expect(console.info).toHaveBeenCalledWith(jasmine.any(String), 'www.kubek.pl', 'facet.onet.pl', 301, jasmine.any(Number), 0, Request.GET, 'facet.onet.pl');
                    });
                });

                describe('nodejs client success 200', function () {
                    beforeEach(function () {
                        this._m.statusCode = 200;

                        this._loader.load(this._r);
                    });

                    it('should dispatch Error', function () {
                        expect(Loader.prototype.dispatchEvent).toHaveBeenCalled();
                    });

                    it('should log monitoring', function () {
                        expect(console.info).toHaveBeenCalledWith(jasmine.any(String), 'www.kubek.pl', 'www.onet.pl', 200, jasmine.any(Number), 256, Request.GET, 'fx.m1r2.onet');
                    });
                });
            });
        });
    });
});
