/*
 * 
 *   Copyright 2016 RIFT.IO Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */
/**
 * Created by onvelocity on 11/23/15.
 */

'use strict';

import _ from 'lodash'
import ColorGroups from '../../ColorGroups'
import DescriptorModel from '../DescriptorModel'
import ForwardingGraph from './ForwardingGraph'
import VirtualLink from './VirtualLink'
import ConstituentVnfd from './ConstituentVnfd'
import PhysicalNetworkFunction from './PhysicalNetworkFunction'
import DescriptorModelFactory from '../DescriptorModelFactory'
import DescriptorModelMetaFactory from '../DescriptorModelMetaFactory'

const indexAsInteger = d => 1 + (parseInt(d.model['member-vnf-index'], 10) || 0);

const suffixAsInteger = function (field) {
	return (d) => 1 + (parseInt(String(d.model[field]).split('').reverse().join(''), 10) || 0);
};

const toBiggestValue = (newIndex, curIndex) => Math.max(newIndex, curIndex);

export default class NetworkService extends DescriptorModel {

	static get type() {
		return 'nsd';
	}

	static get className() {
		return 'NetworkService';
	}

	constructor(model, parent) {
		super(model, parent);
		this.type = 'nsd';
		this.className = 'NetworkService';
		this._connectors = [];
	}

	get constituentVnfd() {
		if (!this.model['constituent-vnfd']) {
			this.model['constituent-vnfd'] = [];
		}
		return this.model['constituent-vnfd'].map(d => DescriptorModelFactory.newConstituentVnfd(d, this));
	}

	set constituentVnfd(obj) {
		const updateNextVnfdIndex = (cvnfd) => {
			const items = this.constituentVnfd;
			const length = items.length;
			// the default value is set to an instance count but we want it to be a sequence no
			cvnfd.model['member-vnf-index'] = 0;
			cvnfd.model['member-vnf-index'] = items.map(indexAsInteger).reduce(toBiggestValue, length);
		};
		this.updateModelList('constituent-vnfd', obj, ConstituentVnfd, updateNextVnfdIndex);
	}

	createConstituentVnfd(model) {
		model = model || DescriptorModelMetaFactory.createModelInstanceForType('nsd.constituent-vnfd');
		return this.constituentVnfd = DescriptorModelFactory.newConstituentVnfd(model, this);
	}

	removeConstituentVnfd(cvnfd) {
		cvnfd = this.findChildByUid(cvnfd);
		this.vld.forEach(vld => vld.removeVnfdConnectionPointRefForVnfdIndex(cvnfd.vnfdIndex));
		this.vnffgd.forEach(fg => fg.removeVnfdConnectionPointRefForVnfdIndex(cvnfd.vnfdIndex));
		return this.removeModelListItem('constituentVnfd', cvnfd);
	}

	get pnfd() {
		if (!this.model.pnfd) {
			this.model.pnfd = [];
		}
		return this.model.pnfd.map(d => DescriptorModelFactory.newPhysicalNetworkFunction(d, this));
	}

	set pnfd(obj) {
		this.updateModelList('pnfd', obj, PhysicalNetworkFunction);
	}

	createPnfd(model) {
		model = model || DescriptorModelMetaFactory.createModelInstanceForType('nsd.pnfd');
		return this.pnfd = DescriptorModelFactory.newPhysicalNetworkFunction(model, this);
	}

	removePnfd(pnfd) {
		return this.removeModelListItem('pnfd', pnfd);
	}


	get vld() {
		if (!this.model.vld) {
			this.model.vld = [];
		}
		return this.model.vld.map(d => DescriptorModelFactory.newVirtualLink(d, this));
	}

	set vld(obj) {
		this.updateModelList('vld', obj, VirtualLink);
	}

	createVld() {
		const model = DescriptorModelMetaFactory.createModelInstanceForType('nsd.vld');
		return this.vld = DescriptorModelFactory.newVirtualLink(model, this);
	}

	removeVLD(vld) {
		return this.removeModelListItem('vld', vld);
	}


	get vnffgd() {
		if (!this.model.vnffgd) {
			this.model.vnffgd = [];
		}
		return this.model.vnffgd.map(d => DescriptorModelFactory.newForwardingGraph(d, this)).map((fg, i) => {
			fg.uiState.colors = ColorGroups.getColorPair(i);
			return fg;
		});
	}

	set vnffgd(obj) {
		const onAddForwardingGraph = (fg) => {
			const index = this.vnffgd.map(suffixAsInteger('short-name')).reduce(toBiggestValue, this.vnffgd.length);
			fg.model['short-name'] = 'FG-' + index;
		};
		this.updateModelList('vnffgd', obj, ForwardingGraph, onAddForwardingGraph);
	}

	createVnffgd(model) {
		model = model || DescriptorModelMetaFactory.createModelInstanceForType('nsd.vnffgd');
		return this.vnffgd = DescriptorModelFactory.newForwardingGraph(model, this);
	}

	removeVnffgd(fg) {
		return this.removeModelListItem('vnffgd', fg);
	}

	get forwardingGraphs() {
		return this.vnffgd;
	}


	// NOTE temporarily disable NSD connection points
	// https://trello.com/c/crVgg2A1/88-do-not-render-nsd-connection-in-the-composer
	//get connectionPoint() {
	//	if (this.model && this.model['connection-point']) {
	//		return this.model['connection-point'];
	//	}
	//	return [];
	//}
	//
	//get connectors() {
	//	const parent = this;
	//	if (!this._connectors.length) {
	//		this._connectors = this.connectionPoint.map(cp => {
	//			return DescriptorModelFactory.newConnectionPoint(parent, cp);
	//		});
	//	}
	//	return this._connectors;
	//}

	removeAnyConnectionsForConnector(cpc) {
		// todo need to also remove connection points from related ForwardingGraph paths
		this.vld.forEach(vldc => vldc.removeVnfdConnectionPointRefKey(cpc.key));
	}

	createConstituentVnfdForVnfd(vnfdRef) {
		const cvnfd = this.createConstituentVnfd();
		cvnfd.vnfdRef = vnfdRef;
		cvnfd.vnfdId = vnfdRef.id;
		return cvnfd;
	}

}
