/*
Implement the following:
	- https://www.w3.org/2010/05/video/mediaevents.html
	- http://ronallo.com/blog/html5-video-caption-cue-settings-tester/
	- http://www.w3schools.com/tags/ref_av_dom.asp

*/
import PlayerAPI from '../PlayerAPI';
import IDUtil from '../../../util/IDUtil';
import SessionStorageHandler from "../../../util/SessionStorageHandler";
import FlexPlayerUtil from '../../../util/FlexPlayerUtil';
import FlexPlayerControls from '../FlexPlayerControls';

import { SESSION_PLAYER_VOLUME } from '../PlayerAPI';

class HTML5VideoPlayer extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			playerAPI: null
		};
		this.controlsRef = React.createRef();
		this.fullScreenWrapperRef = React.createRef();
		this.alreadyShowing = true;
		this.alertTimerId = null;
	}

	componentDidMount() {
		const vid = document.getElementById('video-player');
		if (this.props.eventCallbacks) {
			vid.onprogress = this.props.eventCallbacks.loadProgress.bind(this);
			vid.ontimeupdate = this.props.eventCallbacks.playProgress.bind(
				this
			);
			vid.onplay = this.props.eventCallbacks.onPlay.bind(this);
			vid.onpause = this.props.eventCallbacks.onPause.bind(this);
			vid.onended = this.props.eventCallbacks.onFinish.bind(this);
			vid.onseeked = this.props.eventCallbacks.onSeek.bind(this);
			vid.onloadedmetadata = this.onReady.bind(this, vid);
		}
		//needed until React will support the controlsList attribute of the video tag
		vid.setAttribute('controlsList', 'nodownload');
	}

	shouldComponentUpdate(nextProps, nextState) {
		if (nextState.playerAPI != null && this.state.playerAPI == null) {
			//rerender when the player is ready
			return true;
		}
		if (nextState.fullScreen != this.state.fullScreen) {
			//rerender when full screen is toggled
			return true;
		}
		if (nextProps.mediaObject.assetId == this.props.mediaObject.assetId) {
			//but only rerender when the media object changed
			if (
				this.state.playerAPI &&
				this.props.mediaObject.segments &&
				(nextProps.segment &&
					nextProps.segment.start != this.props.segment.start)
			) {
				this.state.playerAPI.seek(nextProps.segment.start);
			}
			return false;
		}
		return true;
	}

	componentDidUpdate() {
		this.state.playerAPI.getApi().load();
	}

	onReady(playerAPI) {
		if (this.state.playerAPI == null) {
			this.setState(
				{ playerAPI: new HTML5VideoPlayerAPI(playerAPI) },
				() => {
					this.onSourceLoaded();
				}
			);
		} else {
			this.onSourceLoaded();
		}
	}

	onSourceLoaded() {
		if (this.state.playerAPI) {
			//then seek to the starting point
			const start = this.props.mediaObject.start
				? this.props.mediaObject.start
				: 0;
			if (start > 0) {
				this.state.playerAPI.seek(start / 1000);
			}

			//skip to the on-air content
			if (this.props.segment) {
				this.props.segment &&
					this.state.playerAPI.seek(this.props.segment.start);
			} else if (
				FlexPlayerUtil.containsOffAirStartOffset(this.props.mediaObject)
			) {
				this.state.playerAPI.seek(this.props.mediaObject.resourceStart);
			}

			//notify the owner
			if (this.props.onPlayerReady) {
				this.props.onPlayerReady(this.state.playerAPI);
			}
		} else {
			console.error('No player API? (too many renders?)');
		}
	}

	toggleFullScreen(exitFullScreen) {
		const curMode =
			exitFullScreen === true
				? 'full-screen'
				: this.fullScreenWrapperRef.current.className;
		this.fullScreenWrapperRef.current.className =
			curMode === 'default' ? 'full-screen' : 'default';
	}

	toggleControls(e) {
		if (this.controlsRef.current) {
			if (!this.alreadyShowing) {
				this.controlsRef.current.setVisible(true);
				this.alreadyShowing = true;
			}

			if (this.alertTimerId == null) {
				this.alertTimerId = setTimeout(() => {
					this.alreadyShowing = false;
					if (this.controlsRef.current) {
						this.controlsRef.current.setVisible(false);
					}
				}, 2000);
			} else {
				clearTimeout(this.alertTimerId);
				this.alertTimerId = setTimeout(() => {
					this.alreadyShowing = false;
					if (this.controlsRef.current) {
						this.controlsRef.current.setVisible(false);
					}
				}, 2000);
			}
		}
	}

	renderCustomControls = (playerAPI, hideOffAirContent) => {
		if (playerAPI && hideOffAirContent) {
			return (
				<FlexPlayerControls
					ref={this.controlsRef}
					api={playerAPI}
					mediaObject={this.props.mediaObject}
					duration={FlexPlayerUtil.onAirDuration(
						playerAPI.getDuration(),
						this.props.mediaObject
					)}
					toggleFullScreen={this.toggleFullScreen.bind(this)}
				/>
			);
		}
		return null;
	};

	render() {
		//only show the custom controls when absolutely necessary. They are not yet perfect
		const customControls = this.renderCustomControls(
			this.state.playerAPI,
			this.props.hideOffAirContent
		);
		const nativeControls = customControls
			? { controls: false }
			: { controls: true, controlsList: 'nodownload', muted: false };
		return (
			<div className={IDUtil.cssClassName('html5-video-player')}>
				<div
					id={'__htmlvid__' + this.props.mediaObject.assetId}
					ref={this.fullScreenWrapperRef}
					className="default"
					onMouseMove={this.toggleControls.bind(this)}
				>
					<video
						id="video-player"
						width="100%"
						crossOrigin={
							this.props.useCredentials ? 'use-credentials' : null
						}
						{...nativeControls}
					>
						<source src={this.props.mediaObject.url}></source>
						Your browser does not support the video tag
					</video>
					{customControls}
				</div>
			</div>
		);
	}
}

//TODO implement volume & mute functions as well
//TODO make sure the getPosition, getDuration and isPaused also supports direct returns accross all other players (check Vimeo)
class HTML5VideoPlayerAPI extends PlayerAPI {
	constructor(playerAPI) {
		super(playerAPI);
		this.lastVolume = this.playerAPI.volume;
	}

	/* ------------ Implemented API calls ------------- */

	play() {
		const promise = this.playerAPI.play();
		if (promise) {
			//Older browsers may not return a promise, according to the MDN website
			promise.catch(function(error) {});
		}
	}

	pause() {
		this.playerAPI.pause();
	}

	seek(secs) {
		if (secs != isNaN && secs != undefined) {
			this.playerAPI.currentTime = secs;
		}
	}

	getPosition(callback = null) {
		if (!callback) {
			return this.playerAPI.currentTime;
		}
		callback(this.playerAPI.currentTime);
	}

	getDuration(callback = null) {
		if (!callback) {
			return this.playerAPI.duration;
		}
		callback(this.playerAPI.duration);
	}

	isPaused(callback = null) {
		if (!callback) {
			return this.playerAPI.paused;
		}
		callback(this.playerAPI.paused);
	}

	setVolume(volume) {
		//value between 0-1
		if (volume !== 0) {
			this.lastVolume = volume;
		}
		this.playerAPI.volume = volume;

		this.storeVolume(volume);
	}

	getVolume() {
		return this.playerAPI.volume;
	}

	getLastVolume() {
		return this.lastVolume;
	}

	toggleMute() {
		this.playerAPI.muted = !this.playerAPI.muted;
		if (this.isMuted()) {
			this.lastVolume = this.playerAPI.volume;
		}
	}

	isMuted() {
		return this.playerAPI.muted;
	}

	storeVolume(volume) {
		SessionStorageHandler.set(SESSION_PLAYER_VOLUME, volume);
	}
}

export default HTML5VideoPlayer;
