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

class NISVDAANCatalogueConfig extends CollectionConfig {

	constructor(clientId, user, collectionId, collectionMetadata) {
		super(clientId, user, collectionId, collectionMetadata);
	}
    
	getProgramSegmentLabel(){ return "Program segments:"; }

	getNamespace() {
		return 'http://av.beeldengeluid.nl/'
	}

	//the type varies for B&G
	getCollectionMediaTypes() {
		return []
	}

	//used to prevent graphs to blow up in case the minimum date is really low (because of incorrect data)
	getMinimunYear() {
		return 1850
	}

	//override so the annotation layer indices are ignored
	getCollectionIndices() {
		return [this.getCollectionId()]
	}

	//this means the resource viewer needs to request access to the content before it can show them
	requiresPlayoutAccess() {
		return true
	}

	hideOffAirContent() {
		return true
	}

	getPreferredDateField() {
		return 'program.publication.begindate.value';
	}

	static __isValidDate(dateString) {
		const regEx = /^\d{2}-\d{2}-\d{4}$/;
		return dateString.match(regEx) !== null;
	}

	// returns the date as a single value to use in sorting.
	// It assumes date as dd-mm-yyyy and returns either a timestamp or null;
	getInitialDate(dateToFormat) {
		// exception made to deal with format dateToFormat.length === 23  "16-08-1996 / 16-08-1996".
		// Once data has been cleaned remove evaluation
		if (dateToFormat && (NISVDAANCatalogueConfig.__isValidDate(dateToFormat) || dateToFormat.length === 23) ) {
			if(dateToFormat.length === 23) {
				dateToFormat = dateToFormat.substring(0,10);
			}

			// TODO : remove dateToFormat.substring(0,23).split("-") once data sanitized.
			const splitting = dateToFormat.length === 23 ? dateToFormat.substring(0,23).split("-") : dateToFormat.split('-');
			return new Date(splitting[2] + '-' + splitting[1] + '-' + splitting[0]).getTime() || null;
		}
		return null;
	}

	getFieldsToExclude() {
		return []
	}

	getFacets() {
		return [
			{
				field: 'program.publication.broadcastorg.value.keyword',
				title : 'Broadcaster',
				id : 'broadcaster',
				type : 'string'
			},
			{
				field: 'series.genre.name.value.keyword',
				title : 'Genre (series)',
				id : 'genre',
				type : 'string'
			},
			{
				field: 'program.subjectterm.name.value.keyword',
				title : 'Keyword',
				id : 'keyword',
				type : 'string'
			}
		];
	}

//TODO: change this once we determine how to model ASR
	getNestedSearchLayers() {
		return [];
	}

	getMetadataFieldCategories() {
		return [
			{
				id : 'titles',
				label : 'Titles',
				fields : [
					'series.title.value',
					'season.title.value',
					'program.title.value',
					'assetItems.logTrackItems.title.value' //for scene descriptions
				]
			},
			{
				id : 'descriptions',
				label : 'Descriptions',
				fields : [
					'program.summaryshort.value',
					'program.summary.value',
					'assetItems.logTrackItems.summary.value' //for scene descriptions
					//NOTE: museum descriptions in DAAN are now modelled as titles
				]
			},
			//TODO: add back in once have worked out how we will model the subtitle logtrack items
			{
				id : 'subtitles',
				label : 'Keywords from Subtitles',
				fields : [
					'assetItems.logTrackItems.text.value' //TODO: is it only Subtitles logtrackitems that have a text field?
				]
			},
			{
				id: 'subject',
				label: 'Subject keywords',
				fields: [
					'program.subjectterm.name.value',
					'season.subjectterm.name.value',
					'assetItems.logTrackItems.subjectterm.name.value', // for scene descriptions
					'series.subjectterm.name.value'
				]
			},
			//TODO: add back once worked out how to model ASR
//			{
//				id : 'asr',
//				label : 'Speech transcripts (ASR)',
//				nestedPath : 'layer__asr',
//				enrichment : true,
//				fields : [
//					'layer__asr.words'
//				]
//			}
		]
	}

	getItemDetailData(result, currentDateField) {
		result = this.formatSearchResult(result);
		const formattedResult = {}
		formattedResult.resourceId = result._id;
		formattedResult.index = result._index;
		formattedResult.docType = result._type;
		formattedResult.collectionId = result.collectionId;
		formattedResult.title = this.__extractTitle(result);
		formattedResult.description = this.__extractDescription(result);
		const dateInfo = this.__extractDateInfo(result, currentDateField);
		if(dateInfo) {
			formattedResult.date = dateInfo.date;
			formattedResult.dateField = dateInfo.field;
		}
		//TODO: does the external source info still exist in DAAN? Perhaps in omp?
//		formattedResult.externalSourceInfo = this.__getExternalSourceInfo(result);
		formattedResult.specialProperties = this.__extractSpecialProperties(result);
		const content = this.__extractPlayableContent(result);

		formattedResult.playableContent = content.playableContent;
		formattedResult.mediaTypes = content.mediaTypes;
		formattedResult.rawData = result;

		return formattedResult;
	}

	//in case the field name cannot be found in the field descriptions
	formatIndexFieldName(esFieldName) {
		return esFieldName; //don't format, force the field_descriptions to be updated
	}

	//override to add the level to each field (which will display in the FieldSelector)
	//at the same time, exclude the level from the pretty field name
	getAllFields() {
		const fields = super.getAllFields()
		fields.forEach(f => {
			const tmp = f.id.split('.');
			let metadataLayer = 'program';
			if (tmp[0].indexOf('series') !== -1) {
				metadataLayer = 'series';
			}
			else if (tmp[0].indexOf('season') !== -1) {
				metadataLayer = 'season';
			}
			f.level = metadataLayer;
			f.title = this.toPrettyFieldName(f.id, false);
		});
		return fields
	}

	usesLayeredModel() {
		return true;
	}

	__extractTitle(result) {
		let title = null;
		//first check the series title
		if (result.hasOwnProperty('series')) {
			const series = result['series'];
			if (series.hasOwnProperty('title') && series['title'].hasOwnProperty('value')) {
			    if (series['title'] instanceof Array){
				    title = series['title']['value'].join(' / ');
			    }
			    else{
				    title = series['title']['value'];
			    }
			}
		}
		//then check the season title
		if (result.hasOwnProperty('season')) {
			const season = result['season'];
			if (season.hasOwnProperty('title') && season['title'].hasOwnProperty('value')) {
				title = title ? title + '; ' : '';
				if (season['title'] instanceof Array){
				    title += season['title']['value'].join(' / ');
				}
				else{
				    title += season['title']['value'];
				}
			}
		}

		//then check the expression title
		if (result.hasOwnProperty('program')) {
			const program = result['program'];
			if (program.hasOwnProperty('title') && program['title'].hasOwnProperty('value')) {
				title = title ? title + '; ' : '';
				if (program['title'] instanceof Array){
                    title += program['title']['value'].join(' / ');
				}
				else{
				    title += program['title']['value'];
				}
				if (program.hasOwnProperty('alttitle') && program['alttitle'].hasOwnProperty('name') && program['alttitle']['name'].hasOwnProperty('value')) {
				if (program['alttitle'] instanceof Array){
				title += ' - ' + program['alttitle']['name']['value'].join('; ');
				}
				else{
				title += ' - ' + program['alttitle']['name']['value']
				}
			}
			}
		}
		return title;
	}

	__extractDescription(result) {

		if (result.hasOwnProperty('program') && result['program'].hasOwnProperty('summaryshort') && result['program']['summaryshort'].hasOwnProperty('value')) {
			return result['program']['summaryshort']['value'];
		} else if (result.hasOwnProperty('series') && result['series'].hasOwnProperty('summaryshort') && result['series']['summaryshort'].hasOwnProperty('value')) {
		    return result['series']['summaryshort']['value'];
		} else if (result.hasOwnProperty('program') && result['program'].hasOwnProperty('publication') && result['program']['publication'].hasOwnProperty('annotation') && result['program']['publication']['annotation'].hasOwnProperty('value')) {
            if (result['program']['publication'] instanceof Array){
            return result['program']['publication']['annotation']['value'].join(';');
            }
            else{
            return result['program']['publication']['annotation']['value']
            }
		} else {
		    const broadcasterGenre = this.__extractSpecialProperties(result);
			if (broadcasterGenre.hasOwnProperty("Broadcaster") && broadcasterGenre.hasOwnProperty("Genre")) {
			    return broadcasterGenre.Genre + " (" + broadcasterGenre.Broadcaster + ")";
			} else if (result.hasOwnProperty('season') && result['season'].hasOwnProperty('summaryshort') && result['season']['summaryshort'].hasOwnProperty('value')) {
                return result['season']['summaryshort']['value'];
			} else {
			    return "";
			}
		}
	}

	__extractDateInfo(result, currentDateField) {
		const usePublicationDate = true;
		if(currentDateField) {
			//if the selected date field is something else than the default sortdate try to fetch something different
			if(currentDateField.indexOf('begindate') === -1) {

			}

		}
		if(usePublicationDate) {
			if (result.hasOwnProperty('program') && result['program'].hasOwnProperty('publication')) {
				const pubs = result['program']['publication'];
				if(pubs.hasOwnProperty('begindate')) {
					return {
						date : pubs['begindate']['value'],
						field : 'program.publication.begindate.value'
					}
				} else if(pubs.map) { //make sure it is actually an array
					return {
						date : pubs.map((pub) => {
							return pub.hasOwnProperty('begindate') ? pub['begindate']['value'] : '';
						}).join(' / '),
						field : 'program.publication.begindate.value'
					}
				}
			}
		}
		return null;
	}

	__extractPlayableContent(result) {
		let mimeType = 'video/mp4';

		//determine whether the content is radio or not
		if(result.hasOwnProperty('program')) {
			const program = result['program'];
			if(program.hasOwnProperty('materialtype') &&
				program['materialtype'].hasOwnProperty('value') ) {
				let materialType = program['materialtype']['value'].toLowerCase();
				if (materialType === 'audio')
				{
				mimeType = 'audio/mp3';
				}
			    else if (materialType === 'photo')
			    {
				mimeType = 'image/jpeg';
			    }
			    else if (materialType === 'paper')
			    {
				mimeType = 'text';
			    }
		}
		}

		//first merge the carriers
		const mergedCarriers = this.__getMergedCarriers(result);
		//fill the playable content array
		const playableContent = Object.keys(mergedCarriers).length > 0 ? this.__generatePlayableContent(mergedCarriers, mimeType) : [];

		//now make sure the mediaTypes are all there
		let mediaTypes = null;
		mediaTypes = ["video"];
		if(mimeType === 'audio/mp3') {
			mediaTypes = ["audio"];
		} else if (mimeType === "image/jpeg") {
			mediaTypes = ["image"];
		}

		return {
			playableContent : playableContent,
			mediaTypes : mediaTypes
		}
	}

	__getMergedCarriers(result) {
		const mergedCarriers = {}

		//get the logtrackitems for all digitally available assetItems (carriers) for the program, and merge the technical
		//logtrack items (program carriers) and the scene description logtrack items (scene carriers) into the list of merged carriers
		if(result['assetItems']) {
		    result['assetItems'].forEach((assetItem) => {
            if(assetItem['carriertypeid'] && assetItem['category']['value'] === 'Digital'){
                if(assetItem['logTrackItems']) {
                    var firstItem = true;
                    assetItem['logTrackItems'].forEach((logtrackItem) =>
                    {
                        if(logtrackItem.hasOwnProperty('dragersoort') && logtrackItem['dragersoort']['value'] === 'Program')
                        {

                            if(logtrackItem['logtrack_type'] == 'Technical'){
                                this.__mergeCarrier(logtrackItem, mergedCarriers, assetItem['carriernumber']['value'], this.getProgramSegmentLabel(), true);
                            }
                            else if (logtrackItem['logtrack_type'] == 'scenedesc'){
                                this.__mergeCarrier(logtrackItem, mergedCarriers, assetItem['carriernumber']['value'], logtrackItem['title']['value'] ? logtrackItem['title']['value'] : "untitled");
                            }

                        }
                    })
                }
		    }
		    })
		}

		return mergedCarriers;
	}

	/* Adds the given carrier into a dict with mediaObjects with 0 or more segments.
		- ProgramSegment indicates if carriers/segments reflect the program as a whole.
		- Lastly each mediaObject is marked being "raw content" in case it's "Schone inlas"
	*/
	__mergeCarrier(carrier, alreadyMerged, carrierNumber, title, programSegment=false) {

            const segment = this.__toSegment(carrier, title,alreadyMerged, programSegment);
            if(segment) {
            			if(segment['corrupted']){
					        if("bad_data" in alreadyMerged) {
                                alreadyMerged["bad_data"].segments.push(segment)
                            } else {
                                alreadyMerged["bad_data"] = {
                                    assetId : "",  //empty as we don't want to try to play corrupted carriers
                                    segments : [{title: "Unplayable segments", programSegment: true, start: 0, end: 0, corrupted: true}, segment],
                                    isRawContent : carrier['dragersoort'] ? carrier['dragersoort']['value'] !== 'Program' : false // as we now filter on Programma, this is only now of use as a check
                                };
                            }
						}
						else
                            {
                            if(carrierNumber in alreadyMerged) {
                                if(programSegment)
                                { //if program, add to start of segments
                                    alreadyMerged[carrierNumber].segments.unshift(segment);
                                }
                                else
                                {
                                    alreadyMerged[carrierNumber].segments.push(segment);
                                }
                            } else {
                            alreadyMerged[carrierNumber] = {
                            assetId : carrierNumber,
                            segments : [segment],
                            isRawContent :  carrier['dragersoort'] ? carrier['dragersoort']['value'] !== 'Program' : false //make default not raw, as shows most information about segment. As we now filter on Program, this is only now of use as a check
                        };
                    }}

            }

    }


	//the alreadyMerged also contains the program level carriers, which are needed in case the segment carrier
	//does not have a startoffset.
	__toSegment(carrier, title, alreadyMerged, programSegment) {
		let start = carrier.hasOwnProperty('media_start') ? parseInt(carrier['media_start']) : -1;
		let end = ( carrier.hasOwnProperty('media_start') && carrier.hasOwnProperty('media_duration')) ? (parseInt(carrier['media_start']) + parseInt(carrier['media_duration'])) : -1;
        let corrupted = false

		if(isNaN(start) || isNaN(end)) {
			return null;
		}

		if (start < 0 || end < 0){
		    corrupted = true;
		    start = 0;
		    end = 0;
		}

		return {
			start : start,
			end : end,
			title : title,
			programSegment: programSegment
		}
	}

	__generatePlayableContent(mergedCarriers, mimeType) {
		return Object.keys(mergedCarriers).map(assetId => {
			const c = mergedCarriers[assetId];
			c.segments.sort((a, b) => a.start > b.start)
			const url = _play +
				'/api/play/' +
				this.__getContentServerId(mimeType) +
				'/' +
				this.__getContentId(assetId) +
				'?cid=' +
				_clientId +
				'&at=' +
				_chickenStock;
			return {
				assetId : assetId,
				mimeType : mimeType,
				url : url,
				contentId : this.__getContentId(assetId),
				contentServerId : this.__getContentServerId(mimeType),
				segments : c.segments.length >= 1 ? c.segments : null,
				resourceStart : c.segments[0].start,
				resourceEnd :  c.segments[c.segments.length-1].end,
				isRawContent : c.isRawContent
			}
		})
	}

	__getContentServerId(mimeType) {
		let contentServerId = 'beng-video';
		if (mimeType.indexOf('audio') !== -1) {
			contentServerId = 'beng-audio';
		}
		return contentServerId;
	}

	__getContentId(guci) {
        if( guci.indexOf(".") > -1 ){ //if carrier number contains the file suffix, remove this (throttler doesn't need it, and it causes problems with the API)
            guci = guci.split(".")[0]}
		let i = guci.length-1;
		let cid = '';
		while(i >= 0) {
			cid += String.fromCharCode(guci.charCodeAt(i) + 1);
			i--;
		}
		return cid;
	}

//TODO: find out what the DAAN replacement for this relation would be
	__getExternalSourceInfo(result) {
		if(result.hasOwnProperty('dc:relation')) {
			return {
				url :result['dc:relation'],
				message : null
			}
		}
		return null;
	}

	//these are the properties that will be shown in the regular item details table
	__extractSpecialProperties(result) {
		const specialProperties = {};
		//broadcaster
		if (result.hasOwnProperty('program') && result['program'].hasOwnProperty('publication')) {
			if (result['program']['publication'].hasOwnProperty('broadcastorg') && result['program']['publication']['broadcastorg'].hasOwnProperty('value')) {
				specialProperties['Broadcaster'] = result['program']['publication']['broadcastorg']['value'];
			}
		}
		//genre
		if (result.hasOwnProperty('program') && result['program'].hasOwnProperty('genre') && result['program']['genre'].hasOwnProperty('name') && result['program']['genre']['name'].hasOwnProperty('value')) {
			specialProperties['Genre'] = result['program']['genre']['name']['value'];
		}
		return specialProperties;
	}

}

export default NISVDAANCatalogueConfig;
