import React from 'react';
import PropTypes from 'prop-types';

import MediaObject from '../../../model/MediaObject';
import MediaSegment from '../../../model/MediaSegment';

import HTML5AudioPlayer from '../../player/audio/HTML5AudioPlayer';
import HTML5VideoPlayer from '../../player/video/HTML5VideoPlayer';
import VimeoPlayer from '../../player/video/VimeoPlayer';
import YouTubePlayer from '../../player/video/YouTubePlayer';

import PlayList from '../../player/PlayList';

import Transcriber from '../transcription/Transcriber';

import SegmentationTimeline from '../tiers/SegmentationTimeline';
import AnnotationTimeline from '../tiers/AnnotationTimeline';

import AnnotationSummary from '../annotation/AnnotationSummary';
import SegmentationControls from '../annotation/SegmentationControls';

import IDUtil from '../../../util/IDUtil';
import FlexPlayerUtil from '../../../util/FlexPlayerUtil';
import AnnotationUtil from '../../../util/AnnotationUtil';
import IconUtil from '../../../util/IconUtil';
import RegexUtil from '../../../util/RegexUtil';
import ComponentUtil from '../../../util/ComponentUtil';

import FlexBox from '../../FlexBox';

import AppAnnotationStore from '../annotation/flux/AnnotationStore';
import AnnotationActions from '../annotation/flux/AnnotationActions';

//TODO test out media fragments to shield off "off-air content"

/*
This class receives a (generic) playerAPI from the implementing player component.
Currently VimeoPlayer, JWPlayer, HTML5VideoPlayer, HTML5AudioPlayer and YouTubePlayer have implemented this API.

It is able to pass the playerAPI to its owner. This is useful e.g. for the current AnnotationRecipe,
who needs to pass on this API to the AnnotationBox (so it's possible to seek the video when clicking on an annotation)

TODO:
	- the annotation buttons must be made logical (just a single button, instead of two. Detect when a segment is active etc)
	- somewhere the annotations made on the media object level must be displayed

Some (older?) B&G videos don't work well: http://lbas2.beeldengeluid.nl:8093/viz/KRO_KINDERTIJ-KN_000093U2

http://0.0.0.0:5304/tool/resource-viewer?id=4232174@program&cid=nisv-catalogue-aggr

Raar geskipt naar het einde:

http://0.0.0.0:5304/tool/resource-viewer?id=4238372@program&cid=nisv&fq=aanleg
http://0.0.0.0:5304/tool/resource-viewer?id=4238372@program&cid=nisv-catalogue-aggr

TODO: check out this new React player: https://github.com/CookPete/react-player

*/

class FlexPlayer extends React.Component {

	constructor(props) {
		super(props);

		const currentMediaObject = this.determineCurrentMediaObject(
			this.props.mediaObjects, this.props.transcript, this.props.initialSearchTerm
		);
		let currentMediaSegment = null;
		if(currentMediaObject) {
			currentMediaSegment = currentMediaObject.segments || null;
		}
		this.state = {
			currentMediaObject : currentMediaObject,
			currentMediaSegment : currentMediaSegment,
			transcriptMatches : this.calcTranscriptMatchesPerMediaObject(
				this.props.mediaObjects, this.props.transcript, this.props.initialSearchTerm
			),

			playerAPI : null,

			relativePosition : 0, //player pos relative to on-air start time (e.g. on-air starts at 6:01, real player = 8:01, so relative pos = 2:00)
			realPosition : 0, //real player position
			duration : 0,

			segmentStart : -1, //start point of the active ANNOTATION
			segmentEnd : -1, //end point of the active ANNOTATION

			paused : true,//FIXME call the player API instead (isPaused)?

			annotations : [], //populated in onLoadAnnotations()
			activeAnnotation : null,
			activeAnnotationIndex : -1,
			mediaObjectAnnotation : null //populated in onLoadAnnotations(), there should only be one per user!
		}
	}

	componentDidMount() {
		if(this.props.active) {
			document.addEventListener('keydown', this.onKeyPressed);
		}
		this.loadAnnotations();

		//then listen to any changes that happen in the API
		const mediaObjects = this.props.mediaObject ? [this.props.mediaObject] : this.props.mediaObjects;
		mediaObjects.forEach(mo => {
			AppAnnotationStore.bind(
				mo.assetId,
				this.onChange
			);
		});

		AppAnnotationStore.bind('change-project', this.loadAnnotations.bind(this, null));
	}

	componentWillUnmount() {
        document.removeEventListener('keydown', this.onKeyPressed);
    }

    //returns the first media object that matches the search term in the accompanied transcript (if any, else it returns the first media object)
	determineCurrentMediaObject = (mediaObjects, transcript, initialSearchTerm) => {
		if(!transcript || !initialSearchTerm) return mediaObjects[0];
		let regex = null;
		try {
			regex = RegexUtil.generateRegexForSearchTerm(initialSearchTerm);
		} catch(err) {
			console.debug('invalid regex');
		}
		const firstMatch = regex ? transcript.find(phrase => {
			return phrase.words.search(regex) !== -1;
		}) : null;
		return firstMatch ? mediaObjects.find(
			mo => mo.assetId === firstMatch.carrierId || mo.devientTranscriptId === firstMatch.carrierId
		) : mediaObjects[0];
	};

	//TODO get the number of matches per segment as well!
	calcTranscriptMatchesPerMediaObject = (mediaObjects, transcript, initialSearchTerm) => {
		if(!transcript || !initialSearchTerm) return {};

		const matches = {};
        let regex = null;
        try {
            regex = RegexUtil.generateRegexForSearchTerm(initialSearchTerm);
        } catch (err) {
            console.debug('invalid regex');
        }
        if (regex) {
            mediaObjects.forEach(mo => {
                matches[mo.assetId] = this.getTranscript(transcript, mo).reduce((acc, phrase) => {
                    return acc + (phrase.words.match(regex) || []).length;
                }, 0);
            });
        }
        return matches;
    };

    /************************************** Keyboard controls ***************************************/

	onKeyPressed = e => {
		switch(e.keyCode) {
			case 73: //i
				e.shiftKey ?
					ComponentUtil.checkFocusAndExec(this.playStart) : //shift+i
					ComponentUtil.checkFocusAndExec(this.setStart); //i
				break;
			case 79: //o
				e.shiftKey ?
					ComponentUtil.checkFocusAndExec(this.playEnd) : //shift+o
					ComponentUtil.checkFocusAndExec(this.setEnd); //o
				break;

			case 37: //left
				e.shiftKey ?
					ComponentUtil.checkFocusAndExec(this.previousSegment, 60) : //shift+left
					ComponentUtil.checkFocusAndExec(this.rw, 60); //left
				break;
			case 39: //right
				e.shiftKey ?
					ComponentUtil.checkFocusAndExec(this.nextSegment, 60) : //shift+right
					ComponentUtil.checkFocusAndExec(this.ff, 60); //right
				break;

			case 80: ComponentUtil.checkFocusAndExec(this.togglePlay); break; //p

			case 83: //s
				e.shiftKey ?
					ComponentUtil.checkFocusAndExec(this.saveSegment) : //shift+s
					() => {}; //do nothing
			break;

			case 78: //n
				e.shiftKey ?
					ComponentUtil.checkFocusAndExec(this.newSegment) : //shift+n
					e.ctrlKey ?
						ComponentUtil.checkFocusAndExec(this.newSegmentFromLast) : //ctrl+n
						() => {}; //do nothing
			break;

			case 69: //e
				e.shiftKey ?
					ComponentUtil.checkFocusAndExec(this.editAnnotation) : //shift+e
					() => {}; //do nothing
			break;

			case 65: //a
				e.shiftKey ?
					ComponentUtil.checkFocusAndExec(this.editMediaObjectAnnotation) : //shift+a
					() => {}; //do nothing
			break;
		}

		if(e.keyCode >= 49 && e.keyCode <= 57) { //1-9
			e.shiftKey ?
				ComponentUtil.checkFocusAndExec(this.rw, e.keyCode - 48) :
				ComponentUtil.checkFocusAndExec(this.ff, e.keyCode - 48)
		}
	}

	onChange = (eventType, data, annotation, index) => {
		if(eventType == 'change-target') {
			this.loadAnnotations(null);
		} else if(eventType == 'update') {
			this.loadAnnotations(annotation);//after adding or saving an annotation
		} else if(eventType == 'delete') {
			this.loadAnnotations(null);//after deleting an annotation
		} else if(eventType == 'play') {//whenever an annotation within this media object needs to be played
			this.setActiveAnnotation(annotation, true);
		} else if(eventType == 'set') {//whenever an annotation within this media object needs to be set
			this.setActiveAnnotation(annotation, true);//false
		}
	};

	loadAnnotations(annotation) {
		this.setState(
			{activeAnnotation : annotation},
			() => {
				AppAnnotationStore.getMediaObjectAnnotations(
					this.state.currentMediaObject.assetId,
					this.props.user,
					this.props.project,
					this.onLoadAnnotations
				)
			}
		)
	}

	onLoadAnnotations = annotationList => {
		let mediaObjectAnnotation = null;
		if(annotationList) {
			//get the annotation on the media object level (there should be only one per user!)
			mediaObjectAnnotation = annotationList.filter((a) => {
			    if (a.target){
			        return a.target.source === this.state.currentMediaObject.assetId && a.target.selector === null;
			    } else {
			        return false;
			    }
			});
			mediaObjectAnnotation = mediaObjectAnnotation.length > 0 ? mediaObjectAnnotation[0] : null;
		}
		this.setState({
			annotations : annotationList,
			mediaObjectAnnotation : mediaObjectAnnotation
		});
	};

	//called by the playerAPI (this component is an observer of that. I know it's ugly, will make it pretty later)
	//TODO is this still necessary?
	update = () => {
		const activeSegment = this.state.playerAPI.getActiveSegment();
		this.setState({
			segmentStart : activeSegment.start,
			segmentEnd : activeSegment.end
		})
	};

	/*************************************** Player event callbacks ***************************************/

	//called after the underlying player implemtation has loaded a video
	onPlayerReady = playerAPI => {
		//remove this instance as an observer from the old playerAPI
		if(this.state.playerAPI) {
			this.state.playerAPI.removeObserver(this)
		}

		//add this instance as an observer of the new playerAPI
		playerAPI.addObserver(this);

		this.setState(
			{playerAPI : playerAPI},
			() => {
				//get the new duration
				this.state.playerAPI.getDuration(this.onGetDuration);
				this.state.playerAPI.isPaused((paused) => {
					this.state.playerAPI.play();
				})

				//propagate to the owner (if any)
				if(this.props.onPlayerReady) {
					this.props.onPlayerReady(playerAPI);
				}
			}
		);
	};

	playProgress = event => {
		if(this.state.playerAPI) {
			this.state.playerAPI.getPosition(this.onGetPosition);
			if(this.props.onPlayProgress) {
				this.props.onPlayProgress(event);
			}
		}
	};

	onPlay = data => {
        this.setState({paused : false});
        if(this.props.onPlay) {
			this.props.onPlay(data);
		}
	};

	onPause = paused => {
        this.setState({paused : true});
        if(this.props.onPause) {
			this.props.onPause(data);
		}
	};

	//TODO test this well! (relative duration)
	onGetDuration = value => {
		if(!isNaN(value)) {
			this.setState({
				duration : FlexPlayerUtil.onAirDuration(value, this.state.currentMediaObject)
			})
		}
	};

	//TODO test this well! (relative player pos)
	onGetPosition = value => {
	    this.setState({
	    	relativePosition : FlexPlayerUtil.timeRelativeToOnAir(value, this.state.currentMediaObject),
	    	realPosition : value
	    })
	};

	loadProgress = data => {
		if(this.props.onLoadProgress) {
			this.props.onLoadProgress(data);
		}
	};

	onFinish = data => {
		if(this.props.onFinish) {
			this.props.onFinish(data);
		}
	};

	onSeek = data => {
		if(this.props.onSeek) {
			this.props.onSeek(data);
		}
	};

	/************************************** Segmentation controls ***************************************/

	setManualStart = start => {
		if(start > 0 && start <= this.state.duration) {
		    this.setState(
		    	{segmentStart : start},
		    	() => {
		    		this.__doOnAirSeek(start)
		    	}
		    );
		}
	};

	setManualEnd = end => {
		if(end > 0 && end <= this.state.duration) {
		    this.setState(
		    	{segmentEnd : end},
		    	() => {
		    		this.__doOnAirSeek(end)
		    	}
		    );
		}
	};

	playStart = () => {
		this.__doOnAirSeek(this.state.segmentStart)
	};

	playEnd = () => {
    	this.__doOnAirSeek(this.state.segmentEnd)
	};

	setStart = start => {
	    let temp = -1;
	    if(start === undefined) {
	        temp = this.state.relativePosition;
	    } else {
	        temp = start;
	    }
	    let ac = this.state.activeAnnotation;
	    if(ac && !ac.target.selector) {
	    	ac = null;
	    }
		this.setState({
			segmentStart : temp,
			activeAnnotation : ac
		});
	};

	setEnd = (end, skipPause) => {
	    let temp = -1;
	    if(end === undefined) {
	        temp = this.state.relativePosition;
	    } else {
	        temp = end;
	    }
	    let ac = this.state.activeAnnotation;
	    if(ac && !ac.target.selector) {
	    	ac = null;
	    }
        this.setState({
        	segmentEnd : temp,
        	activeAnnotation : ac
        });
        if(skipPause === undefined) {
            this.state.playerAPI.pause();
        }
	};

	rw = t => {
		this.__doOnAirSeek(this.state.relativePosition - t)
	};

	ff = t => {
		this.__doOnAirSeek(this.state.relativePosition + t)
	};

	//this is the central seek function of the FlexPlayer and makes sure all seeks take on air content into account
	__doOnAirSeek(time) {
		FlexPlayerUtil.seekRelativeToOnAir(this.state.playerAPI, time, this.state.currentMediaObject)
	}

	togglePlay = () => {
		if(this.state.paused === false) {//FIXME, this does not work yet!
			this.state.playerAPI.pause();
		} else {
			this.state.playerAPI.play();
		}
	};

	/* ------------------------------------------------------------------------------
	------------------------------- COMMUNICATION WITH OWNER/RECIPE -----------------
	------------------------------------------------------------------------------- */

	setActiveAnnotation(annotation, play) {
		const index = AnnotationUtil.getSegmentIndex(this.state.annotations, annotation);
		this.setState(
			{
				activeAnnotation : annotation,
				activeAnnotationIndex : index
			},
			play ? this.playAnnotation.call(this, annotation) : null
		);
	}

	//TODO set the active index too
	playAnnotation(annotation) {
		if(annotation && annotation.target) {
			//TODO make sure to check the mimeType and also add support for images/spatial targets!!
			if(annotation.target.source === this.state.currentMediaObject.assetId) {
				this.setActiveAnnotation(annotation);
				const frag = AnnotationUtil.extractTemporalFragmentFromAnnotation(annotation.target);
				if(frag) {
					this.state.playerAPI.setActiveSegment(this.state.currentMediaObject, frag, true, true);
				} else {
					this.state.playerAPI.setActiveSegment(this.state.currentMediaObject, null, true, true);
				}
			}
		}
	}

	editAnnotation = () => {
		if(this.state.activeAnnotation) {
			AnnotationActions.edit(this.state.activeAnnotation);
		}
	};

	deleteAnnotation = () => {
		if(this.state.activeAnnotation) {
			AnnotationActions.delete(this.state.activeAnnotation);
		}
	};

	/* ---------------------------- MEDIA OBJECT ANNOTATION SPECIFIC ------------------------- */

	editMediaObjectAnnotation = () => {
		if(!this.props.annotationSupport.mediaObject) return; //return when not configured for annotating media objects
		let annotation = this.state.mediaObjectAnnotation;
		if(!annotation) {
			annotation = AnnotationUtil.generateW3CEmptyAnnotation(
				this.props.user,
				this.props.project,
				this.props.collectionId,
				this.props.resourceId,
				this.state.currentMediaObject
			);
		}
		AnnotationActions.edit(annotation);
	};

	/* ---------------------------- SEGMENT ANNOTATION SPECIFIC ------------------------- */

	newSegment = () => {
		if(!this.props.annotationSupport.mediaSegment) return;
		this.setState({
			activeAnnotation : null,
			segmentStart : -1,
			segmentEnd : -1
		});
	};

	newSegmentFromLast = () => {
		if(!this.props.annotationSupport.mediaSegment) return;
		if(this.state.segmentEnd > 0) {
			this.setState(
				{
					activeAnnotation : null,
					segmentStart : this.state.segmentEnd,
					segmentEnd : -1
				},
				() => {
					this.__doOnAirSeek(this.state.segmentEnd)
				}
			);
		} else {
			this.newSegment();
		}
	};

	saveSegment = () => {
		if(!this.props.annotationSupport.mediaSegment) return;
		AnnotationActions.save(
			AnnotationUtil.toUpdatedAnnotation(
				this.props.user,
				this.props.project,
				this.props.collectionId,
				this.props.resourceId,
				this.state.currentMediaObject,
				{
					start : this.state.segmentStart,
					end : this.state.segmentEnd
				},
				this.state.activeAnnotation
			)
		);
	};

	nextSegment = () => {
		const segment = AnnotationUtil.getSegment(this.state.annotations, this.state.activeAnnotationIndex + 1);
		if(segment) {
			AnnotationActions.set(segment);
		}
	};

	previousSegment = () => {
		const segment = AnnotationUtil.getSegment(this.state.annotations, this.state.activeAnnotationIndex - 1);
		if(segment) {
			AnnotationActions.set(segment);
		}
	};

	/* ----------------- inter component communication --------------------- */

	onOutput(mediaObject) {
		if(this.props.onOutput) {
			this.props.onOutput(this.constructor.name, mediaObject)
		}
	}

	/* ----------------- RENDERING ANNOTATION & SEGMENTATION COMPONENTS --------------------------- */

	renderSegmentationControls = (activeAnnotation, segmentStart, segmentEnd) => {
		return (
			<SegmentationControls
				controls={{
					setManualStart : this.setManualStart,
					setManualEnd : this.setManualEnd
				}}
				annotation={activeAnnotation}
				start={segmentStart}
				end={segmentEnd}/>
		)
	}

	renderAnnotationSummary = (activeAnnotation, tiers) => {
		return (
			<AnnotationSummary
				annotation={activeAnnotation}
				annotationLayers={tiers}
				showTitle={false}/>
		)
	}

	renderTiers = (state, tiers) => {
		let segmentationTier = this.renderSegmentationTier(state);
		let annotationTier = this.renderAnnotationTier(state, tiers);
		return (
			<div className="row">
				<div className="col-md-12">
					<div>
						{segmentationTier}
						{annotationTier}
					</div>
				</div>
			</div>
		)
	}

	renderSegmentationTier = (state) => {
		return (
			<SegmentationTimeline
				mediaObject={state.currentMediaObject}
				duration={state.duration}
				curPosition={state.relativePosition}

				start={state.segmentStart}
				end={state.segmentEnd}

				playerAPI={state.playerAPI}
			/>
		)
	};

	renderAnnotationTier = (state, tiers) => {
		return (
			<AnnotationTimeline
				mediaObject={state.currentMediaObject}
				duration={state.duration}
				curPosition={state.relativePosition}

				start={state.segmentStart}
				end={state.segmentEnd}

				playerAPI={state.playerAPI}

				annotations={state.annotations}
				annotation={state.activeAnnotation}
				annotationLayers={tiers}
			/>
		)
	};

	/* ----------------- RENDERING THE TRANSCRIBER --------------------------------------------*/

	//takes into account the active carrier/track and whether it relates to off-air content or not
	getTranscript = (transcript, currentMediaObject) => {
		if(!transcript || !currentMediaObject) return null;
		return transcript.filter(t => {
			//first make sure the transcript only includes the active carrier/track
			if(t.carrierId === currentMediaObject.assetId || t.carrierId === currentMediaObject.devientTranscriptId) {
				//then make sure the transcript does not contain off-air lines
				if(!FlexPlayerUtil.isTimeBeforeOnAir(t.start / 1000, currentMediaObject) &&
					!FlexPlayerUtil.isTimeAfterOnAir(t.start / 1000, currentMediaObject)) {
					return true
				}
			}
			return false
		})
	};

	renderTranscriber = (transcript, playerAPI, initialSearchTerm, currentMediaObject, realPosition) => {
		if(!(transcript && transcript.length > 0 && playerAPI && currentMediaObject)) return null;
		return (
			<Transcriber
				key={'transcriber__' + currentMediaObject.assetId}
				initialSearchTerm={this.props.initialSearchTerm}
				transcript={transcript}
				curPosition={realPosition}
				playerAPI={playerAPI}
				mediaObject={currentMediaObject}
			/>
		)
	};

	/* ----------------- RENDER THE TRACKLIST ------------------------------------------------ */

	playTrack = (mediaObject, segment) => {
		if(mediaObject.assetId === this.state.currentMediaObject.assetId) {
			this.setState({
				currentMediaSegment : segment
			})
		} else {
			this.setState(
				{
					currentMediaObject : mediaObject,
					currentMediaSegment : segment,
					playerAPI : null,
					activeAnnotation : null,
					segmentStart : -1,
					segmentEnd : -1
				},
				() => {
					//make sure to load the annotations of the selected track
					this.loadAnnotations(null);

					//communicate the selected track back to the details page
					this.onOutput(mediaObject)
				}
			)
		}
	};

	//FIXME make this a nice coherant list, instead of the horrible abomination it is now
	renderPlayList = (playList) => {
		if(!playList || playList.length === 0 || (playList.length === 1 && !playList[0].segments)) return null;

		return (
			<FlexBox title="Play list (including segments)" isVisible={false}>
				<PlayList mediaObjects={playList} transcriptMatches={this.state.transcriptMatches} onSelect={this.playTrack}/>
			</FlexBox>
		)
	};

	/* ----------------- MAIN RENDER --------------------------------------------------------- */

	render() {
		//first update the activeSegment in the playerAPI
		if(this.state.segmentStart !== -1 && this.state.segmentEnd !== -1 && this.state.playerAPI) {
			this.state.playerAPI.setActiveSegment({
				segmentStart : this.state.segmentStart,
				segmentEnd : this.state.segmentEnd
			});
		}

		//then just continue rendering
		const annotationSummary = this.state.activeAnnotation ? this.renderAnnotationSummary(
			this.state.activeAnnotation,
			this.props.annotationLayers
		) : null;

		//render annotation & segmentation controls & tiers
		let segmentationControls = null;
		let annotationTiers = null;
		if(this.props.annotationSupport.mediaSegment && this.state.playerAPI) {
			segmentationControls = this.renderSegmentationControls(this.state.activeAnnotation, this.state.segmentStart, this.state.segmentEnd);
			annotationTiers = this.renderTiers(this.state, this.props.annotationLayers);
		}

		//render the transcriber
		const transcript = this.getTranscript(this.props.transcript, this.state.currentMediaObject)
		const transcriber = this.renderTranscriber(
			transcript,
			this.state.playerAPI,
			this.props.initialSearchTerm,
			this.state.currentMediaObject,
			this.state.realPosition
		);

		//render the play list
		const playList = this.renderPlayList(this.props.mediaObjects);

		const playerEventCallbacks = {
		    playProgress : this.playProgress,
		    onPlay : this.onPlay,
		    onPause : this.onPause,
		    onFinish : this.onFinish,
		    loadProgress : this.loadProgress,
		    onSeek : this.onSeek
		};

		let player = null;

		if(this.state.currentMediaObject) {
			if(this.state.currentMediaObject.mimeType.indexOf('video') !== -1) {
				if(this.state.currentMediaObject.url.indexOf('player.vimeo.com') !== -1)  {
					player = ( //TODO adapt for playlist and test!
						<VimeoPlayer
						key={'vimeo_player__' + this.state.currentMediaObject.assetId}
						mediaObject={this.state.currentMediaObject}
						eventCallbacks={playerEventCallbacks}
						onPlayerReady={this.onPlayerReady}/>
					);
				} else if (this.state.currentMediaObject.url.indexOf('youtube.com') !== -1 ||
					this.state.currentMediaObject.url.indexOf('youtu.be') !== -1) {
					player = ( //TODO adapt for playlists and test!
						<YouTubePlayer
						key={'yt_player__' + this.state.currentMediaObject.assetId}
						mediaObject={this.state.currentMediaObject}
						eventCallbacks={playerEventCallbacks}
						onPlayerReady={this.onPlayerReady}/>
					);
				} else {
					player = (
						<HTML5VideoPlayer
						key={'html_v_player__' + this.state.currentMediaObject.assetId}
						mediaObject={this.state.currentMediaObject}
						segment={this.state.currentMediaSegment}
						useCredentials={this.props.useCredentials && !this.state.currentMediaObject.requiresPlayoutAccess === false}
						hideOffAirContent={this.props.hideOffAirContent}
						eventCallbacks={playerEventCallbacks}
						onPlayerReady={this.onPlayerReady}/>
					);
				}
			} else if(this.state.currentMediaObject.mimeType.indexOf('audio') !== -1) {
				player = (<HTML5AudioPlayer
					key={'html_a_player__' + this.state.currentMediaObject.assetId}
					mediaObject={this.state.currentMediaObject}
					segment={this.state.currentMediaSegment}
					useCredentials={this.props.useCredentials && !this.state.currentMediaObject.requiresPlayoutAccess === false}
					eventCallbacks={playerEventCallbacks}
					onPlayerReady={this.onPlayerReady}/>
				);
			}
		}

		return (
			<div className={IDUtil.cssClassName('flex-player')}>
				<div className="flex-container">
					<div className="player-container" style={{overflowX : 'auto'}}>
						{player}
						<div className="btn-toolbar" role="toolbar">
							<div className="btn-group" role="group">
								<button className="btn btn-default" type="button"
									title="Add annotation to the current media object / carrier (SHIFT+A)"
									onClick={this.editMediaObjectAnnotation}>
									<span className={IconUtil.getUserActionIcon('annotate')}></span>
								</button>
							</div>
							&nbsp;
							<div className="btn-group" role="group">
								<button className="btn btn-default" type="button"
									title="Delete current annotation (SHIFT+D)"
									onClick={this.deleteAnnotation}>
									<span className={IconUtil.getUserActionIcon('remove')}></span>
								</button>
							</div>
							&nbsp;
							<div className="btn-group" role="group">
								<button className="btn btn-default" type="button"
									title="Save segment (SHIFT+S)"
									onClick={this.saveSegment}>
									<span className={IconUtil.getUserActionIcon('save')}></span>
								</button>
								<button className="btn btn-default" type="button"
									title="New segment (SHIFT+N)"
									onClick={this.newSegment}>
									<span className={IconUtil.getUserActionIcon('add')}></span>
								</button>
								<button className="btn btn-default" type="button"
									title="New segment from currently active segment (CTRL+N)"
									onClick={this.newSegmentFromLast}>
									<span className={IconUtil.getUserActionIcon('next')}></span>
								</button>
							</div>
						</div>
					</div>
					<div className="player-tabs">
						{segmentationControls}
						{annotationSummary}
						{playList}
					</div>
				</div>
				{annotationTiers}
				{transcriber}
			</div>
		)
	}

}

FlexPlayer.propTypes = {
	//this is the media object the player will try to load
	//the mimeType & url determine which implementation (HTML5, YouTube, JW, Vimeo) will be used
	mediaObjects: PropTypes.arrayOf(
		MediaObject.getPropTypes()
	).isRequired,

	//the resource & collection ID are required for saving annotations
	resourceId: PropTypes.string.isRequired,
	collectionId: PropTypes.string.isRequired,

	//required for loading & saving media object related annotations of the current user
	user: PropTypes.shape({
    	id: PropTypes.string.isRequired
  	}).isRequired,

	//(optional) represents the active project, used for loading & saving annotations to the right project
	project: PropTypes.shape({
	    id: PropTypes.string.isRequired,
	}),

	//(optional) player callback functions the owner can register to
	onLoadProgress: PropTypes.func,
	onPlay: PropTypes.func,
	onPlayProgress: PropTypes.func,
	onPause: PropTypes.func,
	onFinish: PropTypes.func,
	onSeek: PropTypes.func,
	onPlayerReady: PropTypes.func, //returns the PlayerAPI, so the owner can control the player

	//whether media object annotation
	annotationSupport: PropTypes.shape ({
		mediaObject: PropTypes.object, //if not null, it means: "please activate annotation support for the media object"
		mediaSegment: PropTypes.object //if not null, it means: "please activate annotation support for the media segment"
	}),

	active: PropTypes.bool, // this reflects whether this component is visible, so the keyboard controls can be activated

	transcript : PropTypes.array, //audio transcript
	initialSearchTerm : PropTypes.string, //for jumping to the first matching line in the transcript

	useCredentials : PropTypes.bool, //so the player sends all the required cookie information for the playout proxy
	hideOffAirContent : PropTypes.bool, //in case the content has to be cut off at a certain start and/or end time

	annotationLayers : PropTypes.array //for future implementation

};

export default FlexPlayer;
