declare var pexpect;
(function() {
/*global JSZip*/
	'use strict';

	describe('Session Service', function() {

		var ufSession, _;

		// since we are testing the session we don't want a default one setup
		testHarness.beforeEachCreateMocks();

		var testStartSessionPromise; 
		testHarness.beforeEachInjectSession(function(sessionPromise) {
			testStartSessionPromise = sessionPromise;
		});


		var target = testHarness.target;

		function testDataProvider(done) {
			ufSession.registerSessionDataProvider('sessionTest', {
				onSessionLoad: function(newData) {
					expect(newData).toBeUndefined();
					done();
				}
			});
		}

		beforeEach(inject(function(_ufSession_) {
			ufSession = _ufSession_;
		}));


		describe('New', function() {

			it('should call data providers on registeration', function(done) {
				testDataProvider(done);
			});

			it('should provide configured target ccxml file content', function() {
				expect(ufSession.getCCXML()).toBe(target.expectedCCXMLFileContent);
			});

			it('should provide configured target cores list', function() {
				var cores = ufSession.getCores();
				expect(cores.length).toBe(1);
				var core = cores[0];
				expect(core.name).toBe(target.expectedCoreName);
			});

			it('should not start a new session if already started', function() {
				var sessionPromise = ufSession.startIfNeeded(target.deviceID, target.connectionID);
				expect(testStartSessionPromise).toBe(sessionPromise);
			});

			it('should force start a new session', function(done) {
				var sessionPromise = ufSession.startIfNeeded(target.deviceID, target.connectionID, true);
				expect(testStartSessionPromise).not.toBe(sessionPromise);
				testDataProvider(done);
			});

		});

		describe('Save/Load', function() {

			function testSaveSession(done) {
				testHarness.fileDialogs.nextFD(testHarness.fileDialogs.createFD(
					'test_session.uniflash', 'test_session.uniflash'));
				pexpect(ufSession.save(), function() {
					expect(true).toBe(true);
				}, done);
			}

			it('should save a new session', function(done) {
				testSaveSession(done);
			});

			it('should save core session properties', function(done) {
				testSaveSession(function() {
					var lastSaved = JSON.parse(testHarness.fileStorage.lastSaveFD().contents);
					expect(lastSaved.session).toBeDefined();
					done();
				});
			});



			it('should call registered data provider on save', function(done) {

				var provider : any = createFakeSessionProvider('sessionTest');
				testSaveSession(function() {
					var lastSaved = JSON.parse(testHarness.fileStorage.lastSaveFD().contents);
					var savedFakeSessionData = lastSaved.sessionTest;
					expect(angular.equals(provider.fakeSessionData, savedFakeSessionData)).toBe(true);
					expect(provider.getSessionDataCalled).toBe(true);
					done();
				});

			});

			function createFakeSessionProvider(id) {

				var provider : any = {};

				provider.fakeSessionData = {};
				provider.fakeSessionData['fake_key' + id] = 'fake_value' + id;
				provider.onSessionLoadCalled = false;
				provider.getSessionDataCalled = false;

				ufSession.registerSessionDataProvider(id, {
					onSessionLoad: function(newData) {
						provider.fakeSessionData = newData;
						provider.onSessionLoadCalled = true;
					},
					getSessionData: function() {
						provider.getSessionDataCalled = true;
						return provider.fakeSessionData;
					}
				});

				return provider;
			}

			function createFakeSessionProviders(num) {
				var fakeSessionDataProviders = {};

				// lets create 10 providers
				for (var i = 0; i < num; i++) {
					var id = 'fake_provider' + i;
					fakeSessionDataProviders[id] = createFakeSessionProvider(id);
				}

				return fakeSessionDataProviders;
			}

			function verifyFakeSessionProviderData(fakeSessionDataProviders, lastSavedSession) {
				_.each(fakeSessionDataProviders, function(provider, id) {
					var savedFakeSessionData = lastSavedSession[id];
					expect(angular.equals(provider.fakeSessionData, savedFakeSessionData)).toBe(true);
					expect(provider.getSessionDataCalled).toBe(true);
				});
			}

			function testSaveSessionMultipleDataProviders(done, fakeSessionDataProviders) {
				testSaveSession(function() {
					var lastSavedSession = JSON.parse(testHarness.fileStorage.lastSaveFD().contents);
					verifyFakeSessionProviderData(fakeSessionDataProviders, lastSavedSession);
					done();
				});
			}

			it('should call multiple registered data providers on save', function(done) {
				var fakeSessionDataProviders = createFakeSessionProviders(10);
				testSaveSessionMultipleDataProviders(done, fakeSessionDataProviders);
			});

			var sessionLoadTestData = {
				'fake_provider0': {
					'fake_keyfake_provider0': 'fake_valuefake_provider0'
				},
				'fake_provider1': {
					'fake_keyfake_provider1': 'fake_valuefake_provider1'
				},
				'session': {
					'version': 'uniflash_session_format_version_1',
					'deviceID': 'MSP430FR5969',
					'connectionID': 'TIMSP430-USB',
					'cores': [{
						'id': '0',
						'name': 'MSP430FR5969'
					}]
				}
			};

			it('should load a saved session', function(done) {

				// expectLoadData will verify data load
				var providers = createFakeSessionProviders(2);

				var fd = testHarness.fileDialogs.createFD(
					'load_test_session.uniflash', 'load_test_session.uniflash', JSON.stringify(sessionLoadTestData));

				testHarness.fileDialogs.nextFD(fd);
				testHarness.fileStorage.nextOpenFD(fd);
				pexpect(ufSession.load(), function() {

					_.each(providers, function(provider, id) {
						var expectLoadData = sessionLoadTestData[id];
						expect(angular.equals(provider.fakeSessionData, expectLoadData)).toBe(true);
						expect(provider.onSessionLoadCalled).toBe(true);
					});

				}, done);

			});


		});

	});


})();
