class PersonScanner {

	constructor(sfxCount, forceMirrorState = null) {
		
		this.scanner = null;
		this.cameraChangeCb = null;

		this.DEFAULT_IMAGE = '/Static/Images/App/CEDAR_logo_large_grey.png';
		this.LOADING_IMAGE = '/Static/Images/ops_Page/ajax-loader_large_dial.gif';
		this.DEFAULT_DIALOG_CLASS = 'warn';
		

		// JQuery Elements used within the script
		this.$personName = $('#person-name');
		this.$personReference = $('#person-reference');
		this.$qrCapture = $('#qr-capture');
		this.$qrVideo = $('#qr-video');

		// Options to add basic front-facing camera support in iOS.
		this.$qrVideo.attr('autoplay', 'autoplay');
		this.$qrVideo.attr('playsinline', 'playsinline');

		this.$qrCameraOptions = $('#qr-camera-options');
		this.$personImage = $('#person-image');
		this.scanSFXElem = $('#scan-sfx')[0];
		this.sfxCount = sfxCount;

		this.$mirror = $('#qr-mirror-container > div');
		this.forceMirrorState = forceMirrorState;

		this.$dialog = $('#qr-dialog');
	}

	getQrScanner() {
		return this.scanner;
	}

	render() {
		this.scanner = new QrScanner(this.$qrVideo, this.sfxCount, this.scanSFXElem);

		/** Setup video mirroring. The mirror button will use localStorage to remember its last state unless overriden
		    by `this.forceMirrorState`. **/
		var mirrorVideo = (mirror) => {
			localStorage.setItem('ops_qrscanner_mirror', mirror);
			this.scanner.setMirroring(mirror);
		};

		if (this.forceMirrorState !== null) {
			mirrorVideo(this.forceMirrorState);
		} else {
			// Set the initial state.
			mirrorVideo(localStorage.getItem('ops_qrscanner_mirror') === 'true');
			// Bind click event.
			this.$mirror.on('click', () => mirrorVideo(!this.scanner.isMirroring()));
		}


		/** Initialise scanner **/
		this.scanner.onScan((data) => this._onScan(data));
		return this.scanner.initialise()
		.then((activeCamHash) => this._makeCameraOptions(activeCamHash))
		.catch((err) => { this._cameraNotAllowed(); console.error(err); return false; } )
		.finally(() => this._removeLoaderAnimation());
	}

	_onScan(rawQrData) {
		var qrContent = rawQrData.toLowerCase();

		var validation = this.validateScan(qrContent);
		if (validation.valid) {
			this.processScan(qrContent);
		} else {
			this.onFailedScan(validation.message);
		}
	}

	/**
	 * @param qrContent
	 * @returns {{valid: boolean}}
	 */
	validateScan(qrContent) {
		return {valid: true};
	}

	/**
	 * What to do on QR code scan?
	 * Should be overridden.
	 * @param qrContent
	 * @protected
	 */
	processScan(qrContent){
		throw 'NotImplementedException';
	}
	
	onSuccessfulScan(reference, name) {
		this.setScanResults(
			name,
			reference,
			'/Person/'+reference+'/Photo'
		);
	}
	
	onFailedScan(msg) {
		this.setScanResultsToDefault();
		this.showDialog(msg);
	}
	
	setLoading(loading){
		this.$qrCapture.toggleClass('loading', loading);
		if (loading) {
			this.$personImage.attr('src', this.LOADING_IMAGE);
		}
	}
	
	setScanResultsToDefault() {
		this.setScanResults('', '', this.DEFAULT_IMAGE);
	}
	
	setScanResults(name, reference, imageUrl) {
		
		this.setLoading(false);
		
		this.$personImage.attr('src', imageUrl);
		this.$personName.html(name);
		this.$personReference.html(reference);
	}
	
	// `cssClass` and `lengthInMs` are Optional.
	showDialog(msg, cssClass, lengthInMs) {
		
		cssClass = defaultTo(cssClass, this.DEFAULT_DIALOG_CLASS);
		lengthInMs = defaultTo(lengthInMs, 3000);
		
		this.$dialog.html(msg);
		
		// Show the mark dialog
		this.$dialog.attr('class', 'animated '+cssClass);
		this.$dialog.attr('style', 'opacity: 1');

		setTimeout( ()=>this.$dialog.attr('style', 'opacity: 0'), lengthInMs );
	}
	
	
	/** Helper methods: **/
	
	_cameraNotAllowed() {
		
		this.$qrVideo.after(
			'<img class="centered" id="no-camera" src="/Static/ui/ux2/no-camera.png"></img>'
			+'<span>No camera detected</span>'
		);
		
		this.$qrVideo.remove();
	}


	onCameraChange(cb) {
		this.cameraChangeCb = cb;
	}

	/**
	 * Generate a set of buttons to switch camera.
	 * @param activeCamHash
	 * @return {boolean} TRUE if there are any cameras, FALSE otherwise
	 * @private
	 */
	_makeCameraOptions(activeCamHash) {
		if (this.$qrCameraOptions.length < 1) {
			return false;
		}

		var self = this;

		// For each camera, create an '<a>' tag button.
		$.each(this.scanner.getCameras(), function(hash, cam) {
			var extraClasses = hash == activeCamHash ? 'active': '';
			self.$qrCameraOptions.prepend(
				'<a class="action small '+extraClasses+'" id="'+hash+'">'+cam.name+'</a>'
			);
		})

		this.$qrCameraOptions.children('a').each(function(idx, elem){

			$(elem).on('click', function(){
				let selectedId = $(elem).attr('id');
				self.scanner.activateCamera(selectedId);
				self.$qrCameraOptions.children('a').removeClass('active');
				$(elem).addClass('active');
				if (self.cameraChangeCb) {
					self.cameraChangeCb(selectedId);
				}
			});
		});

		return true;
	}

	_removeLoaderAnimation() {
		this.$qrCameraOptions.children('#options-loader-animation').remove();
	}
}