import React from 'react';
import { Row, Col, OverlayTrigger, Tooltip, Popover, Button, Well, Label, FormControl, InputGroup, Glyphicon } from 'react-bootstrap';
import { getEventCreationDate, getEventHistoryCreationDate, getOriginalEvent, getPreviousVersionNumber, getEventIcon } from '../../helpers/EventHelpers';

import EventFooter from './EventFooter';
import { ANNOTATION, NOTIFICATION, READ_MODE, DETAILED_EVENT_CONTEXT } from '../../constants/EventTypes';
import PropTypes from 'prop-types';
import EventContentDisplayer from './EventContentDisplayer';
import Popup from 'reactjs-popup';
import Moment from 'moment';
import EventVersion from './EventVersion';
import _ from 'lodash';
import TagContainer from '../../containers/TagContainer';


/**
 * A detailed event of the logbook.
 */
class DetailedEvent extends React.Component {
    constructor(props) {
        super(props);

        // Initialize state
        this.state = {
            isSaveButtonEnabled: false, // whether the event is valid ie can be saved
            isEditorContentValid: false
        };

        this.canEnableSaveButton = this.canEnableSaveButton.bind(this);
        this.onCancelButtonClicked = this.onCancelButtonClicked.bind(this);
        this.onSuccessfullyUpdated = this.onSuccessfullyUpdated.bind(this);
        this.setTitleInput = this.setTitleInput.bind(this);
        this.setTagContainer = this.setTagContainer.bind(this);
        this.updateEvent = this.updateEvent.bind(this);
    }

    render() {
        let { event, user } = this.props;

        if (event.type === ANNOTATION || event.type === NOTIFICATION) {
            return (
                <div id='editionBox' style={{ display: 'flex' }} >

                    {/* the left panel */}
                    <div style={{ flexGrow: '0', maxWidth: '155px' }}>
                        <div className='pull-right' style={{ paddingRight: '8px' }}>
                            {getEventIcon(event.category, '20')}
                        </div>

                        <div style={{ paddingLeft: '5px' }} >
                            <div style={{ height: '50px' }} />

                            <OverlayTrigger
                                placement='top'
                                overlay={<Tooltip id='tooltip'> <p> Manage tags </p> </Tooltip>}>

                                <a href={'/investigation/' + this.props.investigationId + '/events/tagManager'}
                                    target='_blank'
                                    style={{ float: 'right', paddingRight: '10px', color: '#777', marginTop: '2px' }}>
                                    <Glyphicon glyph='cog' />
                                </a>
                            </OverlayTrigger>

                            <Label> Tags </Label>
                            <div style={{ paddingTop: '5px', marginRight: '10px' }}>
                                <TagContainer
                                    canEnableSaveButton={this.canEnableSaveButton}
                                    context={DETAILED_EVENT_CONTEXT}
                                    event={event}
                                    investigationId={this.props.investigationId}
                                    setTagContainer={this.setTagContainer}
                                />
                            </div>

                            <hr id='hrEvents' />

                            <Label> Creation date </Label>
                            <OverlayTrigger
                                placement='right'
                                overlay={
                                    <Tooltip id='tooltip'>
                                        <p> Event created on {getEventHistoryCreationDate(getOriginalEvent(event))} </p>
                                    </Tooltip>
                                }>
                                <div>
                                    <div style={{ paddingTop: '5px', paddingLeft: '10px', color: '#666666' }}>
                                        {getEventCreationDate(getOriginalEvent(event))}
                                    </div>
                                </div>
                            </OverlayTrigger>

                            <hr id='hrEvents' />

                            <CommentBy event={event} />

                            <div style={{ position: 'relative' }}>
                                <div >
                                    <OverlayTrigger
                                        trigger='click'
                                        placement='top'
                                        overlay={eventVersionsPopover(event)}
                                        rootClose={true}
                                    >
                                        <Label>  History <div className='arrow-down' /> </Label>
                                    </OverlayTrigger>
                                </div>
                            </div>
                        </div>
                    </div>
                    <div
                        style={{ flexGrow: '1' }}>

                        {(event.type === ANNOTATION) ? <AnnotationContent
                            canEnableSaveButton={this.canEnableSaveButton}
                            event={event}
                            investigationId={this.props.investigationId}
                            setTitleInput={this.setTitleInput}
                            user={user}
                        /> : null}
                        {(event.type === NOTIFICATION) ? <NotificationContent
                            canEnableSaveButton={this.canEnableSaveButton}
                            event={event}
                            investigationId={this.props.investigationId}
                            user={user}
                        /> : null}

                        <EventFooter
                            onCancelButtonClicked={this.onCancelButtonClicked}
                            onSaveButtonClicked={this.updateEvent}
                            isSaveButtonEnabled={this.state.isSaveButtonEnabled} />
                    </div>
                </div >);
        } else {
            console.log('[ERROR] Event (' + event._id + ') not shown because its type is not annotation and not notification. ');
            return null;
        };
    }

    updateEvent() {
        let { investigationId, event, user } = this.props;

        // get tags
        let currentTagIds = this.tagContainer.state.selectedTags.map((tag) => tag._id);

        let updatedEvent = {
            _id: event._id,
            category: event.category,
            content: [
                {
                    format: 'plainText',
                    text: localStorage.getItem('plainText')
                },
                {
                    format: 'html',
                    text: localStorage.getItem('HTMLText')
                }
            ],
            creationDate: Date(),
            type: event.type,
            tags: currentTagIds,
            title: (this.inputTitle && this.inputTitle.props) ? this.inputTitle.props.value : null,
            username: user.username,
            previousVersionEvent: event._id
        };
        this.props.updateEvent(updatedEvent, user.sessionId, investigationId, this.onSuccessfullyUpdated);
    }

    /** Callback executed when the event has been successfully updated on the server side*/
    onSuccessfullyUpdated(updatedEvent) {
        this.props.toggleMode(READ_MODE); //this makes sure the mode is changed in case the event is updated.
        this.props.onEventUpdated(updatedEvent);
    }

    /**
     * Callback function triggered when the user click the cancel button
     * @param {*} e the browser's event
    */
    onCancelButtonClicked(e) {
        e.stopPropagation();
        this.props.toggleMode(READ_MODE);
    }

    /**
    * Callback function called when the text of the editor changed from empty to something or vice versa
    * @param {object} change an object containing the properties:
    *   -1- hasText boolean which indicates whether the editor content has text or not; not null
    *   -2- currentTextEqualsOriginal, boolean, which indicates whether the current content is the same as the original content; not null
    */
    canEnableSaveButton(change) {
        let hasEventTitleChangedFromItsOriginalValue =
            this.inputTitle &&
            this.props.event &&
            this.inputTitle.props.value !== this.props.event.title;

        let hasEventTagsChangedFromItsOriginalValue =
            this.tagContainer &&
            this.props.event &&
            !(_.isEqual(this.tagContainer.state.selectedTags.map((tag) => tag._id), this.props.event.tag));

        if (hasEventTitleChangedFromItsOriginalValue || hasEventTagsChangedFromItsOriginalValue) {
            /* title is not the same as original. can save (even with no content) */
            if (this.state.isSaveButtonEnabled !== true) { this.setState({ isSaveButtonEnabled: true }); }
        } else {
            /* title is the same as original */
            if (change) {
                /* triggered from the editor */
                let hasText = null;
                let currentTextEqualsOriginal = null;
                if ('hasText' in change) { hasText = change.hasText; };
                if ('currentTextEqualsOriginal' in change) {
                    currentTextEqualsOriginal = change.currentTextEqualsOriginal;
                };
                if (!hasText) {
                    // there is no text in the editor
                    if (this.state.isEditorContentValid !== false) {
                        this.setState({
                            isEditorContentValid: false,
                            isSaveButtonEnabled: false
                        });
                    };
                } else {
                    // there is text in the editor
                    if (currentTextEqualsOriginal === undefined || currentTextEqualsOriginal === null) {
                        if (this.state.isEditorContentValid !== false) {
                            this.setState({
                                isEditorContentValid: false,
                                isSaveButtonEnabled: false
                            });
                        };
                    } else if (currentTextEqualsOriginal) {
                        // current text in the editor equals the original text
                        if (this.state.isEditorContentValid !== false) {
                            this.setState({
                                isEditorContentValid: false,
                                isSaveButtonEnabled: false
                            });
                        };
                    } else {
                        if (this.state.isEditorContentValid !== true) {
                            this.setState({
                                isEditorContentValid: true,
                                isSaveButtonEnabled: !hasEventTitleChangedFromItsOriginalValue
                            });
                        };
                    };
                }
            } else {
                if (!this.state.isEditorContentValid) {
                    /* Editor content is not valid. Can not save */
                    if (this.state.isSaveButtonEnabled !== false) { this.setState({ isSaveButtonEnabled: false }); }
                };
            };
        };
    }

    setTitleInput(element) {
        this.inputTitle = element;
    }

    setTagContainer(element) {
        this.tagContainer = element;
    }
}

DetailedEvent.propTypes = {
    /** the event object as received from the ICAT+ server */
    event: PropTypes.object.isRequired,
    /** the investigationId which the events belong to. */
    investigationId: PropTypes.string.isRequired,
    /**Callback function triggered when the user updated an existing event */
    onEventUpdated: PropTypes.func,
    /* Callback function used to change from one mode to the other READ_MODE vs EDIT_MODE*/
    toggleMode: PropTypes.func.isRequired,
    /** the user who is currently logged in */
    user: PropTypes.object.isRequired,
};

/**
* Render the popup which displays all event versions of the event
* @param {*} event the event under investigation
        */
function eventVersionsPopover(event) {
    let e = event;


    /* build the different lines representing the previous versions */
    let lines = [];
    while (e.previousVersionEvent != null) {
        if (lines.length === 0) {
            lines.push(<EventVersionItem event={e} type='edition' mostRecent={true} />);
        } else {
            lines.push(<EventVersionItem event={e} type='edition' mostRecent={false} />);
        };
        e = e.previousVersionEvent;
    }
    lines.push(<EventVersionItem event={e} type='creation' />);


    /* build the popover */
    return (<Popover id='mypopover'>
        <div>
            <p style={{ marginBottom: '5px' }}> This log has {getPreviousVersionNumber(event) + 1} versions. </p>
            <hr style={{ marginTop: '5px' }} />
            {lines.map((item, index) => <Popup
                key={index}
                trigger={<div> {item} </div>}
                modal
                closeOnDocumentClick={false}
                contentStyle={{ width: '90%', height: '90%' }}
            >
                {close => (
                    <div className='fullPage'>
                        <a className='close' onClick={close}> &times; </a>
                        <div className='content'>
                            <EventVersion
                                event={item.props.event}
                                isLatestVersion={(index === 1) ? true : false}
                                isOriginalVersion={(index === lines.length - 1) ? true : false}
                            />
                        </div>
                    </div>
                )}
            </Popup>
            )}
            <hr style={{ marginBottom: '5px' }} />

            <Popup
                trigger={<div style={{ display: 'inline' }}> <Button bsStyle='link'> See all versions  </Button> </div>}
                modal
                closeOnDocumentClick={false}
                contentStyle={{ width: '90%', height: '90%' }}
            >
                {close => (
                    <div className='fullPage'>
                        <a className='close' onClick={close}> &times; </a>
                        <div className='content'>
                            <CompleteEventHistory event={event} />
                        </div>
                    </div>
                )}
            </Popup>

        </div>
    </Popover>);
}

/**
 * React component which represents the content of an annotation
* @param {*} props the props passed to this component
        */
class AnnotationContent extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            inputTitleValue: this.props.event.title || ''
        };

        this.onChangeInputValue = this.onChangeInputValue.bind(this);
    }

    onChangeInputValue(e) {
        this.setState({ inputTitleValue: e.target.value });
    }

    render() {
        let { event, investigationId, user } = this.props;

        if (event.type && event.type === ANNOTATION) {
            return (
                <div>
                    <EventContentDisplayer
                        content={event.content}
                        useRichTextEditor={true}
                        isEditionMode={true}
                        user={user}
                        investigationId={investigationId}
                        canEnableSaveButton={this.props.canEnableSaveButton}
                    />

                    <div style={{ paddingTop: '8px' }}>
                        <InputGroup>
                            <InputGroup.Addon style={{ backgroundColor: 'transparent', border: 'none' }}> <Label> Title </Label> </InputGroup.Addon>
                            <FormControl
                                type='text'
                                value={this.state.inputTitleValue}
                                onChange={this.onChangeInputValue}
                                placeholder='Optional title here'
                                ref={this.props.setTitleInput}
                            />
                        </InputGroup>
                    </div>
                </div>
            );
        };
    }

    componentDidUpdate() {
        this.props.canEnableSaveButton();
    }
}

AnnotationContent.propTypes = {
    /* the callback function which activates the save button */
    canEnableSaveButton: PropTypes.func.isRequired,
    /* The event to be shown */
    event: PropTypes.object.isRequired,
    /* the investigationId */
    investigationId: PropTypes.string.isRequired,
    /* the callback function which adds a ref to this */
    setTitleInput: PropTypes.func.isRequired,
    /* the user */
    user: PropTypes.object.isRequired
};

/**
 * React component which represents the content of an notification
* @param {*} props  the props passed to this component
        */
const NotificationContent = (props) => {
    let { event, investigationId, user } = props;

    let notificationMessage = getOriginalEvent(event);

    if (event.type && event.type === NOTIFICATION) {
        let editorContent;
        if (getPreviousVersionNumber(event) === 0) {
            let fakeContent = [{ format: 'html', text: '<p> </p>' }];
            editorContent = (<EventContentDisplayer
                content={fakeContent}
                useRichTextEditor={true}
                isEditionMode={true}
                user={user}
                investigationId={investigationId}
                canEnableSaveButton={props.canEnableSaveButton}
            />);
        } else {
            editorContent = (<EventContentDisplayer
                content={event.content}
                useRichTextEditor={true}
                isEditionMode={true}
                user={user}
                investigationId={investigationId}
                canEnableSaveButton={props.canEnableSaveButton}
            />);
        };

        return (
            <div>
                <div style={{ marginLeft: '10px' }} >
                    <div id='divContainingHTMLNotificationInDocView'>
                        <EventContentDisplayer
                            content={notificationMessage.content}
                            useRichTextEditor={false}
                            isEditionMode={false}
                        />
                    </div>
                </div>
                {editorContent}
            </div>
        );
    };
};

NotificationContent.propTypes = {
    /* the callback function which activates the save button */
    canEnableSaveButton: PropTypes.func.isRequired,
    /* The event to be shown */
    event: PropTypes.object.isRequired,
    /* the investigationId */
    investigationId: PropTypes.string.isRequired,
    /* the user */
    user: PropTypes.object.isRequired
};

/**
 * React component which represents the commentBy part.
* @param {*} props
            */
const CommentBy = (props) => {
    let { event } = props;
    if (getPreviousVersionNumber(event) === 0) {
        return (
            <div>
                <Label> Created by </Label>
                <div style={{ paddingTop: '5px', paddingLeft: '10px' }}>
                    <p style={{ color: '#666666' }}> {props.event.username} </p>
                </div>
                <hr id='hrEvents' />
            </div>
        );
    };
    if (getPreviousVersionNumber(event) !== 0) {
        return (
            <div>
                <Label> Commented by </Label>
                <div style={{ paddingTop: '5px', paddingLeft: '10px' }}>
                    <p style={{ color: '#666666' }}> {props.event.username} </p>
                </div>
                <hr id='hrEvents' />
            </div>
        );
    };
    return null;
};

/**
 * React component which represents on item of the event history
* @param {*} props  the props passed to this component
                */
class EventVersionItem extends React.Component {
    render() {
        function buildTheDisplay(event, type, mostRecent) {
            return (
                <Well bsSize='small' style={{ marginBottom: '5px', cursor: 'pointer' }}>
                    <b> {event.username} </b>
                    {type === 'creation' ? 'created on ' : ''}
                    {type === 'edition' ? 'edited on ' : ''}
                    {Moment(event.creationDate).format('MMMM DD HH:mm')}
                    {mostRecent === true ? ' (most recent)' : ''}
                    {event.machine ? <span style={{ color: '#777777', fontStyle: 'italic' }}> from {event.machine} </span> : ''}
                </Well>
            );
        };

        return (
            buildTheDisplay(this.props.event, this.props.type, this.props.mostRecent)
        );
    };
};

/**
 * React component which displays the complete event history
 */
const CompleteEventHistory = (props) => {
    let { event } = props;
    let eventVersions = [];

    /* first push the current event which is the latest version of the event*/
    //eventHistoryItems.push(<EventListViewExpanded event={event} isFullPage={true} />)
    eventVersions.push(<EventVersion event={event} isLatestVersion={true} />);
    /* then display the previous version of this event */
    while (event.previousVersionEvent != null) {
        event = event.previousVersionEvent;
        eventVersions.push(<div class='margin-bottom-10'>
            <Row>
                <Col xs={1}> </Col>
                <Col xs={11}>
                    <EventVersion event={event} isOriginalVersion={event.previousVersionEvent === null ? true : false} />
                </Col>
            </Row>
        </div>);
    };

    return eventVersions;
};

export default DetailedEvent;