/*
 * Copyright © 2016-2017 European Support Limited
 *
 * 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.
 */

import React from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';

import Modal from 'nfvo-components/modal/Modal.jsx';
import Button from 'sdc-ui/lib/react/Button.js';
import i18n from 'nfvo-utils/i18n/i18n.js';
import {modalContentComponents} from 'sdc-app/common/modal/ModalContentMapper.js';
import {actionTypes, typeEnum} from './GlobalModalConstants.js';


const typeClass = {
	'default': 'primary',
	error: 'negative',
	warning: 'warning',
	success: 'positive'
};

const type2HeaderColor = {
	'default': 'primary',
	error: 'danger',
	warning: 'warning',
	success: 'success'
};


const ModalFooter = ({type, onConfirmed, onDeclined, onClose, confirmationButtonText, cancelButtonText}) => {
	let myPropsForNoConfirmed = {};
	if (onConfirmed) {
		myPropsForNoConfirmed.btnType = 'outline';
	}
	return (
		<Modal.Footer>
			<div className='sdc-modal-footer'>
				{onConfirmed && <Button data-test-id='sdc-modal-confirm-button' color={typeClass[type]} onClick={() => {
					onConfirmed();
					onClose();
				}}>{confirmationButtonText}</Button>}
				<Button {...myPropsForNoConfirmed} data-test-id='sdc-modal-cancel-button' btnType='outline' color={typeClass[type]} onClick={onDeclined ? () => {
					onDeclined();
					onClose();} : () => onClose()}>
					{cancelButtonText}
				</Button>
			</div>
		</Modal.Footer>
	);
};

ModalFooter.defaultProps = {
	type: 'default',
	confirmationButtonText: i18n('OK'),
	cancelButtonText: i18n('Cancel')
};

ModalFooter.PropTypes = {
	type: PropTypes.string,
	confirmationButtonText: PropTypes.string,
	cancelButtonText: PropTypes.string
};

export const mapStateToProps = ({modal}) => {
	const show = !!modal;
	return {
		show,
		...modal
	};
};

export const mapActionToProps = (dispatch) => {
	return {
		onClose:  () => dispatch({type: actionTypes.GLOBAL_MODAL_CLOSE})
	};
};


export class  GlobalModalView extends React.Component {

	static propTypes = {
		show: PropTypes.bool,
		type: PropTypes.oneOf(['default', 'error', 'warning', 'success']),
		title: PropTypes.string,
		modalComponentProps: PropTypes.object,
		modalComponentName: PropTypes.string,
		onConfirmed: PropTypes.func,
		onDeclined: PropTypes.func,
		confirmationButtonText: PropTypes.string,
		cancelButtonText: PropTypes.string
	};

	static defaultProps = {
		show: false,
		type: 'default',
		title: ''
	};

	render() {
		let {title, type, show, modalComponentName, modalComponentProps,
		modalClassName, msg, onConfirmed, onDeclined, confirmationButtonText, cancelButtonText, onClose} = this.props;
		const  ComponentToRender = modalContentComponents[modalComponentName];
		return (
			<Modal show={show} bsSize={modalComponentProps && modalComponentProps.size} className={`onborading-modal ${modalClassName || ''} ${type2HeaderColor[type]}`}>
				<Modal.Header>
					<Modal.Title>{title}</Modal.Title>
				</Modal.Header>
				<Modal.Body>
					{ComponentToRender ?
						<ComponentToRender {...modalComponentProps}/> :
						msg && typeof msg === 'string' ?
							<div> {msg.split('\n').map((txt, i) => <span key={i}> {txt} <br/> </span>)} </div> :
							msg
					}
				</Modal.Body>
				{(onConfirmed || onDeclined || type !== typeEnum.DEFAULT) &&
						<ModalFooter
							type={type}
							onConfirmed={onConfirmed}
							onDeclined={onDeclined}
							onClose={onClose}
							confirmationButtonText={confirmationButtonText}
							cancelButtonText={cancelButtonText}/>}
			</Modal>
		);
	}

	componentDidUpdate() {
		if (this.props.timeout) {
			setTimeout(this.props.onClose, this.props.timeout);
		}
	}
};

GlobalModalView.propTypes = {
	show: PropTypes.bool,
	type: PropTypes.oneOf(['default', 'error', 'warning', 'success']),
	title: PropTypes.string,
	modalComponentProps: PropTypes.object,
	modalComponentName: PropTypes.string,
	onConfirmed: PropTypes.func,
	onDeclined: PropTypes.func,
	confirmationButtonText: PropTypes.string,
	cancelButtonText: PropTypes.string
};

export default connect(mapStateToProps, mapActionToProps, null, {withRef: true})(GlobalModalView);
