var PATH = '../../lib/opal/OpalClient.js';

describe('OpalClientImport', function(){
  it ('should require properly', function (){
    var OpalClient = require(PATH).OpalClient;
    expect(OpalClient).toBeDefined();
  });
});

describe('OpalClient', function (){
  var OpalClient;
  beforeEach(function () {
    OpalClient = require(PATH).OpalClient;
  });
  afterEach(function () {
    OpalClient = undefined;
  });

  it ('should initialize', function () {
    var instance = new OpalClient('test.onetapi.pl', [], 1, {});
    expect(instance).toBeDefined();
  });

  it ('should set timeout', function () {
    var instance = new OpalClient('http://test.onetapi.pl', [], 2);
    expect(instance.timeout).toEqual(2000);
  });

  it ('should register method', function () {
    var instance = new OpalClient('http://test.onetapi.pl', ['test'], 2, {});
    expect(instance.test).toBeDefined();
  });
});

describe('OpalClient calling methods', function () {
  var OpalClient;
  var OpalLoaderStub;
  var OpalError
  var LoaderStub;
  var OpalFactory;

  var CORE = require('../../lib/index.js');

  beforeEach(function () {
    OpalClient = require(PATH).OpalClient;
    OpalError = require(PATH).OpalError;
    OpalLoaderStub = {
      timeout:0,
      events: [],
      setTimeout: function(x){ this.timeout = x },
      addEventListener: function(type, callback) {
        this.events.push({'type':type, 'callback':callback});
      },
      load: function() {}
    };

    LoaderStub = require('../../lib/net/Loader').Loader;

    OpalFactory = {
      OpalLoader: require('../../lib/opal/OpalLoader.js').OpalLoader,
      OpalRequest: require('../../lib/opal/OpalLoader.js').OpalRequest,
      Loader: CORE.Net.Loader,
      createOpalLoader: function(x){ return OpalLoaderStub; },
      createOpalRequest: function(x){ return x; },
      createLoader: function() { },
      createError: function(message){ return new OpalError(message); }
    };


  });
  afterEach(function () {
    OpalClient = undefined;
  });
  it ('should handle errors thrown by loader', function () {
    // givne
    var err = { code: -32606, message: 'I should be passed as err param' };
    spyOn(OpalLoaderStub, 'load').andCallFake(function () {
      throw err;
    });
    var instance = new OpalClient('http://test.onetapi.pl', ['test'], 2, OpalFactory);
    var params = [1,2,3];
    var flag = false;
    // when
    runs(function () {
        expect(function() {
            instance.test(params, function(e) {
                flag = e;
            });
        }).not.toThrow();
    });

    waitsFor(function () {
        return flag;
    }, 'error loading', 500);

    // then
    runs(function () {
        expect(flag).toBe(err);
    });
  });
  it ('should prepare proper request', function (){
    // given
    var instance = new OpalClient('http://test.onetapi.pl', ['test'], 2, OpalFactory);
    spyOn(OpalFactory, 'createOpalRequest').andCallFake(expectations);
    var params = [1,2,3];
    // when
    instance.test(params, function() {});

    // then
    function expectations(req){
      expect(req.url).toBeDefined();
      expect(req.method).toEqual('test');
      expect(req.params).toEqual(params);
    };
  });

  it ('should raise exception when no callback', function (){
    // given
    var instance = new OpalClient('http://test.onetapi.pl', ['test'], 2, OpalFactory);

    var params = [1,2,3];
    // when
    expect( function () {instance.test(params);}).toThrow(new OpalError("No callback specified"));


  });

  it ('should prepare proper request for many parameters', function (){
    // given
    var instance = new OpalClient('http://test.onetapi.pl', ['test'], 2, OpalFactory);
    spyOn(OpalFactory, 'createOpalRequest').andCallFake(expectations);
    var params = [1,2,3];
    // when
    instance.test(params, function () {});

    // then
    function expectations(req){
      expect(req.url).toBeDefined();
      expect(req.method).toEqual('test');
      params.length = 3
      expect(req.params).toEqual(params);
    };
  });

  it ('should prepare proper request for named parameters', function (){
    // given
    var instance = new OpalClient('http://test.onetapi.pl', ['test'], 2, OpalFactory);
    spyOn(OpalFactory, 'createOpalRequest').andCallFake(expectations);
    var params = {one:1, two:2, three:3}
    // when
    instance.test(params, function(){});

    // then
    function expectations(req){
      expect(req.url).toBeDefined();
      expect(req.method).toEqual('test');
      expect(req.params.one).toEqual(params.one);
      expect(req.params.two).toEqual(params.two);
      expect(req.params.three).toEqual(params.three);
      expect(req.params.callback).toBeUndefined();
    };
  });

  it ('should set timeout in loader', function () {

    // given
    var instance = new OpalClient('http://test.onetapi.pl', ['test'], 2, OpalFactory);
    spyOn(OpalFactory, 'createOpalRequest').andReturn({});
    var params = [1,2,3];
    // when
    instance.test(params, function() {});

    // then
    expect(OpalLoaderStub.timeout).toEqual(2000);
  });

  it ('should call Opal RPC Method', function () {
    // given
    var instance = new OpalClient('http://test.onetapi.pl', ['test'], 2, OpalFactory);
    var response = {
      data: {
        getBody: function () {
          return {
            getError: function(){ return false; },
            getResult: function(){ return {'status': 'OK'}; }
          }
        }
      }
    };
    spyOn(OpalLoaderStub, 'load').andCallFake(function (){
      OpalLoaderStub.events[0].callback(response);
    });
    var params = [1,2,3];

    // when
    instance.test(params, function(err, data){
      expect(data).toBeDefined();
      expect(data.status).toEqual('OK');
    });


  });

  it ('should call Opal RPC Method with error handling', function () {
    // given
    var instance = new OpalClient('http://test.onetapi.pl', ['test'], 2, OpalFactory);
    var response = {
      data: {
        getBody: function () {
          return {
            getError: function(){ return {'status':'ERR'}; },
            getResult: function(){ return {'status': 'OK'}; }
          }
        }
      }
    };
    spyOn(OpalLoaderStub, 'load').andCallFake(function (){
      OpalLoaderStub.events[0].callback(response);
    });
    var params = [1,2,3];

    // when
    instance.test(params, function(err, data){
      expect(err).toBeDefined();
      expect(err.status).toEqual('ERR');
    });


  });
});
