/*
Markdown controller to view and update journal entries.

@copyright (c) Copyright 2013-2016 Dorian Pula
@license AGPL v3
@author Dorian Pula [dorian.pula@amber-penguin-software.ca]
*/


import React from "react";
import {connect} from "react-redux";

import marked from "marked";
import highlighter from "highlight.js";
import {Button, Panel} from "react-bootstrap";
import FontAwesome from "react-fontawesome";

import {fetchArticle, saveArticle} from '../actions';
import {appStore} from "../stores";

/*
    Remember to install codemirror before react-codemirror,
    see issue https://github.com/JedWatson/react-codemirror/issues/34
    Also add in the themes in the CSS to get proper theming support.
*/
import CodeMirror from "react-codemirror";
import "codemirror/mode/markdown/markdown";


// # TODO Remove and rework to allow for two flags, rather than a single state?
export const EditorPaneState = {
    hidden: 0,
    editableClosed: 1,
    editableOpen: 2
};


export class JournalMarkdownView extends React.Component {
    static get propTypes() {
        return {
            id: React.PropTypes.string,
            article: React.PropTypes.string,
            title: React.PropTypes.string,
            editorTheme: React.PropTypes.string,
            params: React.PropTypes.shape({
                pageId: React.PropTypes.string
            }),
            userCanEdit: React.PropTypes.bool
        }
    }

    constructor(props) {
        super(props);
        this.state = {
            displayContent: this.props.article || "Please wait while we load this journal entry.",
            originalContent: this.props.article || "Please wait while we load this journal entry.",
            editorPaneState: EditorPaneState.hidden
        };
        this.handleSaveContent = this.handleSaveContent.bind(this);
        this.handleToggleEditorPane = this.handleToggleEditorPane.bind(this);
        this.handleSaveContent = this.handleSaveContent.bind(this);
        this.handleResetContent = this.handleResetContent.bind(this);
        this.handleUpdateCode = this.handleUpdateCode.bind(this);
    }

    componentDidMount() {
        let pageToLoad = this.props.params.pageId;
        appStore.dispatch(fetchArticle(pageToLoad));
        this.updateEditAllowance(this.props.userCanEdit);
    }

    componentWillReceiveProps(nextProps) {
        this.setState({displayContent: nextProps.article, originalContent: nextProps.article});
        this.updateEditAllowance(nextProps.userCanEdit)
    }

    handleUpdateCode(newCode) {
        this.setState({displayContent: newCode});
    }

    handleToggleEditorPane() {
        let nextEditorState = this.state.editorPaneState;
        if (this.state.editorPaneState === EditorPaneState.editableOpen) {
            nextEditorState = EditorPaneState.editableClosed;
        }

        if (this.state.editorPaneState === EditorPaneState.editableClosed) {
            nextEditorState = EditorPaneState.editableOpen;
        }
        this.setState({editorPaneState: nextEditorState});
    }

    isEditorPaneOpen() {
        return this.state.editorPaneState === EditorPaneState.editableOpen;
    }

    handleResetContent() {
        this.setState({displayContent: this.state.originalContent});
    }

    handleSaveContent() {
        // # TODO Start using proper models for page and json
        let pageContent = {
            id: this.props.id,
            title: this.props.title,
            content: this.state.displayContent
        };
        appStore.dispatch(saveArticle(pageContent));
    }

    updateEditAllowance(allowEdits) {
        let editorState = this.state.editorPaneState;
        if (!allowEdits) {
            editorState = EditorPaneState.hidden;
        }

        if (allowEdits && this.state.editorPaneState === EditorPaneState.hidden) {
            editorState = EditorPaneState.editableClosed;
        }
        this.setState({editorPaneState: editorState});
    }

    render() {
        let code = this.state.displayContent;
        let rawMarkup = marked(code, {sanitized: true, highlight: (code) => {
            return highlighter.highlightAuto(code).value;
        }});
        let options = {mode: "markdown", theme: this.props.editorTheme};

        // # TODO Factor the view into something nicer.
        let showEditorButton = (
            <Button onClick={ this.handleToggleEditorPane }>
                <FontAwesome name="edit"/> Edit
            </Button>
        );
        // # TODO Add in ability to display messages outside the collapsible pane
        let showPanel = (
            <Panel collapsible expanded={ this.isEditorPaneOpen() }>
                <CodeMirror value={ code } onChange={ this.handleUpdateCode } options={ options } />
                <Button onClick={ this.handleSaveContent }><FontAwesome name="save"/> Save </Button>
                <Button onClick={ this.handleResetContent }><FontAwesome name="undo"/> Reset </Button>
            </Panel>
        );
        if (this.state.editorPaneState === EditorPaneState.hidden) {
            showEditorButton = (<div />);
            showPanel = (<div />);
        }

        return (
            <div>
                <h1>{ this.props.title }</h1>
                <span dangerouslySetInnerHTML={ {__html: rawMarkup} }/>
                { showEditorButton }
                { showPanel }
            </div>
        );
    }
}

export const ConnectedArticle = connect(
    (state) => {
        return {
            'id': state.page.id,
            'article': state.page.content,
            'title': state.page.title,
            'editorTheme': state.editor.theme,
            'userCanEdit': state.user.token !== ""
        };
    })(JournalMarkdownView);
