<commit_before>_          = require 'underscore'
classNames = require 'classnames'
React      = require 'react'
ReactDOM   = require 'react-dom'

{div, section, a, form, label, input} = React.DOM

ComposeEditor  = React.createFactory require './compose_editor'
ComposeToolbox = React.createFactory require './compose_toolbox'
FilePicker     = React.createFactory require './file_picker'
MailsInput     = React.createFactory require './mails_input'
AccountPicker  = React.createFactory require './account_picker'

AccountStore = require '../stores/account_store'
MessageStore = require '../stores/message_store'
LayoutStore = require '../stores/layout_store'

{ComposeActions, Tooltips} = require '../constants/app_constants'

MessageUtils = require '../utils/message_utils'

LayoutActionCreator  = require '../actions/layout_action_creator'
MessageActionCreator = require '../actions/message_action_creator'

RouterMixin      = require '../mixins/router_mixin'
LinkedStateMixin = require 'react-addons-linked-state-mixin'

# Component that allows the user to write emails.
module.exports = Compose = React.createClass
    displayName: 'Compose'


    mixins: [
        RouterMixin
        LinkedStateMixin
    ]


    propTypes:
        selectedAccountID:    React.PropTypes.string.isRequired
        selectedAccountLogin: React.PropTypes.string.isRequired
        layout:               React.PropTypes.string
        accounts:             React.PropTypes.object.isRequired
        message:              React.PropTypes.object
        action:               React.PropTypes.string
        callback:             React.PropTypes.func
        onCancel:             React.PropTypes.func
        settings:             React.PropTypes.object.isRequired
        useIntents:           React.PropTypes.bool.isRequired


    getDefaultProps: ->
        layout: 'full'

    getInitialState: ->
        @getStateFromStores()

    getStateFromStores: ->
        props = _.clone @props

        # Get Message
        unless props.message
            props.message = MessageStore.getByID props.messageID

        # Get Reply message
        if _.isString props.inReplyTo
            id = props.inReplyTo
            if (message = MessageStore.getByID id)?.size
                message.set 'id', id
                props.inReplyTo = message
        MessageUtils.createBasicMessage props

    isNew: ->
        not @state.conversationID

    getChildKey: (name) ->
        'message-' + (@state.id or 'new') + '-' + name

    componentWillUpdate: (nextProps={}, nextState={}) ->
        if nextState.composeInHTML
            {html, text} = MessageUtils.cleanContent nextState
            nextState.html = html
            nextState.text = text

    # Update state with store values.
    _setStateFromStores: (message) ->
        isMessage = message?._id is @state.id
        isReplyTo = message?._id is @props.inReplyTo
        if not @isMounted() or (not isMessage and not isReplyTo)
            return

        _difference = (obj0, obj1) ->
            result = {}
            _.filter obj0, (value, key) ->
                unless _.isEqual value, obj1[key]
                    result[key] = value
            result

        nextState = @getStateFromStores()
        changes = _difference nextState, @state
        unless _.isEmpty changes
            @setState changes

    componentDidMount: ->
        # Listen to Stores changes
        MessageStore.addListener 'change', @_setStateFromStores

        # scroll compose window into view
        @refs.compose.scrollIntoView()

        # Save focus
        @addFocusListener()

        # Focus Element
        @handleFocus()

        # Each state:change do not send data to server
        # update date for client modifications
        @state.date = new Date().toISOString() unless @state.date
        @state.lastUpdate = @state.date unless @state.lastUpdate

    componentDidUpdate: ->
        # Initialize @state
        # with values from server
        @saveDraft() if @isNew()

        # Focus Element
        @handleFocus()

        # Each state:change do not send data to server
        # update date for client modifications
        @state.lastUpdate = new Date().toISOString()

    hasChanged: (props, state) ->
        @state.lastUpdate isnt @state.date

    resetChange: ->
        @state.lastUpdate = @state.date

    componentWillUnmount: ->
        MessageStore.removeListener 'change', @_setStateFromStores

        # Stop listening to focus
        @removeFocusListener()

        # Save Message into Draft
        @closeSaveDraft()

    handleFocus: ->
        return unless (path = LayoutStore.getFocus())

        if -1 < path.indexOf 'ref='
            # Element Focusable are not always
            # DOM form element :
            # It can be React Component
            ref = path.split('ref=')[1]
            element = ReactDOM.findDOMNode @refs[ref]

        else if (elements = ReactDOM.findDOMNode(@).querySelectorAll(path))
            element = elements[0]

        element.focus() if (element)


    saveFocus: (event) =>
        if event.refsPath
            path = 'ref=' + event.refsPath
        else if (name = event.currentTarget.name)
            path = '[name="' + event.currentTarget.name + '"]'
        LayoutActionCreator.focus path

    addFocusListener: ->
        _.each ['input[type="text"]', 'textarea'], (path) =>
            _.each ReactDOM.findDOMNode(@).querySelectorAll(path), (element) =>
                element.addEventListener 'focus', @saveFocus

        # Editor is a specific case
        if (editor = ReactDOM.findDOMNode @refs.editor)
            editor.addEventListener 'click', (event) =>
                @saveFocus refsPath: 'editor'

    removeFocusListener: ->
        _.each ['input[type="text"]', 'textarea'], (path) =>
            _.each ReactDOM.findDOMNode(@).querySelectorAll(path), (element) =>
                element.removeEventListener 'focus', @saveFocus

        # Editor is a specific case
        if (editor = ReactDOM.findDOMNode @refs.editor)
            editor.removeEventListener 'click', @saveFocus

    closeSaveDraft: ->
        # Fetch
        unless @hasChanged()
            return

        # Do not ask for save
        MessageActionCreator.send _.clone(@state), (error, message) ->
            if error? or not message?
                msg = "#{t "message action draft ko"} #{error}"
                LayoutActionCreator.alertError msg
                return

    render: ->
        closeUrl = @buildClosePanelUrl @props.layout

        classLabel = 'compose-label'
        classInput = 'compose-input'

        section
            ref: 'compose'
            className: classNames
                compose: true
                panel:   @props.layout is 'full'
            'aria-expanded': true,

            form className: 'form-compose', method: 'POST',
                div className: 'form-group account',<commit_msg>Reove buggy focus<commit_after>_          = require 'underscore'
classNames = require 'classnames'
React      = require 'react'
ReactDOM   = require 'react-dom'

{div, section, a, form, label, input} = React.DOM

ComposeEditor  = React.createFactory require './compose_editor'
ComposeToolbox = React.createFactory require './compose_toolbox'
FilePicker     = React.createFactory require './file_picker'
MailsInput     = React.createFactory require './mails_input'
AccountPicker  = React.createFactory require './account_picker'

AccountStore = require '../stores/account_store'
MessageStore = require '../stores/message_store'
LayoutStore = require '../stores/layout_store'

{ComposeActions, Tooltips} = require '../constants/app_constants'

MessageUtils = require '../utils/message_utils'

LayoutActionCreator  = require '../actions/layout_action_creator'
MessageActionCreator = require '../actions/message_action_creator'

RouterMixin      = require '../mixins/router_mixin'
LinkedStateMixin = require 'react-addons-linked-state-mixin'

# Component that allows the user to write emails.
module.exports = Compose = React.createClass
    displayName: 'Compose'


    mixins: [
        RouterMixin
        LinkedStateMixin
    ]


    propTypes:
        selectedAccountID:    React.PropTypes.string.isRequired
        selectedAccountLogin: React.PropTypes.string.isRequired
        layout:               React.PropTypes.string
        accounts:             React.PropTypes.object.isRequired
        message:              React.PropTypes.object
        action:               React.PropTypes.string
        callback:             React.PropTypes.func
        onCancel:             React.PropTypes.func
        settings:             React.PropTypes.object.isRequired
        useIntents:           React.PropTypes.bool.isRequired


    getDefaultProps: ->
        layout: 'full'

    getInitialState: ->
        @getStateFromStores()

    getStateFromStores: ->
        props = _.clone @props

        # Get Message
        unless props.message
            props.message = MessageStore.getByID props.messageID

        # Get Reply message
        if _.isString props.inReplyTo
            id = props.inReplyTo
            if (message = MessageStore.getByID id)?.size
                message.set 'id', id
                props.inReplyTo = message
        MessageUtils.createBasicMessage props

    isNew: ->
        not @state.conversationID

    getChildKey: (name) ->
        'message-' + (@state.id or 'new') + '-' + name

    componentWillUpdate: (nextProps={}, nextState={}) ->
        if nextState.composeInHTML
            {html, text} = MessageUtils.cleanContent nextState
            nextState.html = html
            nextState.text = text

    # Update state with store values.
    _setStateFromStores: (message) ->
        isMessage = message?._id is @state.id
        isReplyTo = message?._id is @props.inReplyTo
        if not @isMounted() or (not isMessage and not isReplyTo)
            return

        _difference = (obj0, obj1) ->
            result = {}
            _.filter obj0, (value, key) ->
                unless _.isEqual value, obj1[key]
                    result[key] = value
            result

        nextState = @getStateFromStores()
        changes = _difference nextState, @state
        unless _.isEmpty changes
            @setState changes

    componentDidMount: ->
        # Listen to Stores changes
        MessageStore.addListener 'change', @_setStateFromStores

        # scroll compose window into view
        @refs.compose.scrollIntoView()

        # Each state:change do not send data to server
        # update date for client modifications
        @state.date = new Date().toISOString() unless @state.date
        @state.lastUpdate = @state.date unless @state.lastUpdate

    componentDidUpdate: ->
        # Initialize @state
        # with values from server
        @saveDraft() if @isNew()

        # Each state:change do not send data to server
        # update date for client modifications
        @state.lastUpdate = new Date().toISOString()

    hasChanged: (props, state) ->
        @state.lastUpdate isnt @state.date

    resetChange: ->
        @state.lastUpdate = @state.date

    componentWillUnmount: ->
        MessageStore.removeListener 'change', @_setStateFromStores

        # Save Message into Draft
        @closeSaveDraft()


    closeSaveDraft: ->
        # Fetch
        unless @hasChanged()
            return

        # Do not ask for save
        MessageActionCreator.send _.clone(@state), (error, message) ->
            if error? or not message?
                msg = "#{t "message action draft ko"} #{error}"
                LayoutActionCreator.alertError msg
                return

    render: ->
        closeUrl = @buildClosePanelUrl @props.layout

        classLabel = 'compose-label'
        classInput = 'compose-input'

        section
            ref: 'compose'
            className: classNames
                compose: true
                panel:   @props.layout is 'full'
            'aria-expanded': true,

            form className: 'form-compose', method: 'POST',
                div className: 'form-group account',
{'fraction_non_alphanumeric': 0.09563786008230453, 'fraction_numerical': 0.0009053497942386831, 'mean_word_length': 2.1148423481158676, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 46, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5537161', 'n_tokens_mistral': 3283, 'n_tokens_neox': 3179, 'n_words': 820}