import React from 'react';
import {connect} from 'react-redux';
import {ResizableBox} from 'react-resizable';
import Draggable from 'react-draggable';

import * as socket from '../service/socket';
import * as dataTransporter from '../service/data-transporter';
import * as appAction from '../actions/app';

import './Application.less';
import 'react-resizable/css/styles.css';

class Application extends React.Component {
    constructor() {
        super();

        let self = this;
        this.onMessageHandler = function(ev) {
            self.onMessage(ev);
        };

        this.state = {
            showOpacityWrap: false,
            expand: false,
            x: 20,
            y: 20,
            width: '600px',
            height: '400px',
            disabledResize: false,
            closing: false
        };
    }

    componentDidMount() {
        window.addEventListener('message', this.onMessageHandler);
    }

    componentWillUnmount() {
        if (this.closingTimer) {
            clearTimeout(this.closingTimer);
        }
        window.removeEventListener('message', this.onMessageHandler);
    }

    render() {
        let opacityWrap;
        if (this.state.showOpacityWrap || !this.props.app.active) {
            opacityWrap = (
                <div
                    className='opacity-wrap'
                    onClick={this.activeApp.bind(this)}
                >
                </div>
            );
        }

        let expandBtn;
        if (this.state.expand) {
            expandBtn = (
                <button
                    className='ctrlbar-btn compress-btn pull-right'
                    onClick={this.toggleExpand.bind(this)}
                >
                    <i className='fa fa-compress'></i>
                </button>
            );
        }
        else {
            expandBtn = (
                <button
                    className='ctrlbar-btn expand-btn pull-right'
                    onClick={this.toggleExpand.bind(this)}
                >
                    <i className='fa fa-expand'></i>
                </button>
            );
        }

        return (
            <Draggable
                handle='.app-ctrlbar'
                position={{
                    x: this.state.x,
                    y: this.state.y
                }}
                onStart={this.onDragStart.bind(this)}
                onStop={this.onDragStop.bind(this)}
            >
                <div
                    className='ui-app'
                    style={{
                        zIndex: this.props.app.zIndex,
                        width: this.state.width,
                        height: this.state.height
                    }}
                >
                    <ResizableBox
                        ref='resizableBox'
                        id={`app_${this.props.app.id}_resizableBox`}
                        width={600}
                        height={400}
                        onResizeStart={this.onResizeStart.bind(this)}
                        onResizeStop={this.onResizeStop.bind(this)}
                        draggableOpts={{
                            disabled: this.state.disabledResize
                        }}
                    >
                        <div
                            className='app-wrap'
                        >
                            <div className='app-ctrlbar clearfix'>
                                <img className='app-icon' src={this.props.app.iconUrl} />
                                <span className='app-title'>{this.props.app.title}</span>
                                <button
                                    className='ctrlbar-btn close-btn pull-right'
                                    onClick={this.onCloseBtnClick.bind(this)}
                                >
                                    <i className='fa fa-close'></i>
                                </button>
                                {expandBtn}
                            </div>
                            {opacityWrap}
                            <iframe
                                ref='iframe'
                                src={this.props.app.url + `?appId=${this.props.app.id}`}
                                frameborder='0'
                                className='app-body'
                            >
                            </iframe>
                        </div>
                    </ResizableBox>
                </div>
            </Draggable>
        );
    }

    onMessage(ev) {
        if (ev.origin !== location.origin) {
            return;
        }

        let payload = ev.data;
        let event = payload.event;
        let data = payload.data;
        let reqId = payload.id;
        let senderAppId = payload.appId;
        let appId = this.props.app.id;
        if (senderAppId !== appId) {
            return;
        }

        let {dispatch} = this.props;

        switch (event) {
            case 'ready':
                dispatch(appAction.createDone(appId, this.receiveData.bind(this)));
                break;
            case 'std':
                this.std(data, reqId);
                break;
            case 'setTitle':
                dispatch(appAction.setTitle(appId, data));
                break;
            case 'quit':
                dispatch(appAction.close(appId, data));
                break;
            case 'sendData':
                dataTransporter.sendData(data.ident, data.data);
                dispatch(appAction.updateApp());
                break;
            case 'cmd':
                socket.request('cmd', data, res => this.send('cmd.send', res, reqId))
                    .then(res => this.send('cmd.done', res, reqId))
                    .catch(err => this.send('cmd.fail', err, reqId));
        }
    }

    onDragStart() {
        let {dispatch} = this.props;
        dispatch(appAction.active(this.props.app.id));
        this.setState({showOpacityWrap: true});
    }

    activeApp() {
        let {dispatch} = this.props;
        dispatch(appAction.active(this.props.app.id));
    }

    onDragStop(e, data) {
        this.setState({
            x: data.x,
            y: data.y,
            showOpacityWrap: false
        });
    }

    onResizeStart() {
        this.setState({showOpacityWrap: true});
    }

    onResizeStop(e, data) {
        this.setState({
            width: data.size.width,
            height: data.size.height,
            showOpacityWrap: false
        });
    }

    onCloseBtnClick() {
        if (this.state.closing) {
            return;
        }
        this.state.closing = true;
        this.closingTimer = setTimeout(() => {
            let res = confirm(`"${this.props.app.name}" has no response, ` +
                'force close?');
            if (res) {
                let {dispatch} = this.props;
                dispatch(appAction.close(this.props.app.id, {code: 1}));
            }
            else {
                this.setState({closing: false});
                if (this.closingTimer) {
                    clearTimeout(this.closingTimer);
                    this.closingTimer = null;
                }
            }
        }, 5000);
        this.send('quit');
    }

    receiveData(data) {
        this.send('receiveData', data);
    }

    toggleExpand() {
        let resizableBox = document.getElementById(`app_${this.props.app.id}_resizableBox`);
        if (!this.state.expand) {
            this.currentPosition = {
                x: this.state.x,
                y: this.state.y
            };
            this.currentSize = {
                width: this.state.width,
                height: this.state.height
            };
            this.setState({
                x: 0,
                y: 0,
                width: '100%',
                height: '100%',
                expand: true,
                disabledResize: true
            });

            resizableBox.style.width = '100%';
            resizableBox.style.height = '100%';
        }
        else {
            this.setState({
                x: this.currentPosition.x,
                y: this.currentPosition.y,
                width: this.currentSize.width,
                height: this.currentSize.height,
                expand: false,
                disabledResize: false
            });
            resizableBox.style.width = this.currentSize.width;
            resizableBox.style.height = this.currentSize.height;
        }
    }

    send(event, data, reqId) {
        let iframe = this.refs.iframe;
        if (iframe) {
            iframe.contentWindow.postMessage({
                event: event,
                data: data,
                id: reqId
            }, location.origin);
        }
    }

    std(data, reqId) {
        socket.request('std', data)
            .then(res => this.send('std.done', res, reqId))
            .catch(err => this.send('std.fail', err, reqId));
    }
}

function mapStateToProps(state) {
    return {};
}

export default connect(mapStateToProps)(Application);
