/**
 * Created by rburson on 12/23/15.
 */

import * as React from 'react'
import {
    CvState,
    CvProps,
    CvBaseMixin,
    CvEventRegistry,
    CvEvent,
    CvEventType,
    CvNavigationResult,
    CvNavigationResultUtil,
    CvContext,
    CvActionFiredResult,
    CvActionFiredResultType,
    CvActionBase,
    CvMessage,
    CvMessageType,
    CvResultCallback,
    CvResourceManager
} from './catreact-core'
import {Workbench, WorkbenchLaunchAction, Try, NavRequest, ObjUtil} from 'catavolt-sdk'

/*
 ***************************************************
 * Render a 'Launcher'
 ***************************************************
 */

export interface CvLauncherState extends CvState {
}

export interface CvLauncherProps extends CvProps {
    navTarget?:string;
    actionId?:string;
    launchAction?:WorkbenchLaunchAction;
    workbench?:Workbench;
    renderer:(cvContext:CvContext, callback:CvLaunchActionCallback) => {}
    launchListeners?:Array<(event:CvEvent<CvNavigationResult>)=>void>
    actionListeners?:Array<(event:CvEvent<CvActionFiredResult>)=>void>
    wrapperElemName?:string;
    wrapperElemProps?:any;
}

export interface CvLaunchActionCallback {
    fireLaunchAction(resultCallback?:CvResultCallback<CvNavigationResult>):void;
}

export var CvLauncher = React.createClass<CvLauncherProps, CvLauncherState>({

    mixins: [CvBaseMixin],

    getChildContext: function () {
        const ctx = this.getDefaultChildContext();
        ctx.cvContext.scopeCtx.scopeObj = this.launchAction();
        return ctx;
    },

    getDefaultProps: function () {
        return {
            navTarget: null,
            actionId: null,
            launchAction: null,
            workbench: null,
            renderer: null,
            launchListeners: [],
            actionListeners: [],
            wrapperElemName: 'span',
            wrapperElemProps: {}
        }
    },

    launchAction: function () {
        if (this.props.launchAction) {
            return this.props.launchAction;
        } else {
            const workbench:Workbench = this.workbench();
            let workbenchLaunchAction:WorkbenchLaunchAction = null;
            workbench.workbenchLaunchActions.some((launchAction)=> {
                if (launchAction.actionId == this.props.actionId) {
                    workbenchLaunchAction = launchAction;
                    return true;
                } else {
                    return false;
                }
            });
            return workbenchLaunchAction;
        }
    },

    render: function () {

        const launchAction = this.launchAction();
        if (this.props.renderer) {
            if (launchAction) {
                return this.props.renderer(this.getChildContext().cvContext, this._getCallbackObject())
            } else {
                const newChildren = [];
                this.workbench().workbenchLaunchActions.forEach((launchAction:WorkbenchLaunchAction)=> {
                    newChildren.push(<CvLauncher {...this.props} actionId={launchAction.actionId}
                                                                 key={launchAction.actionId}/>);
                });
                return React.createElement(this.props.wrapperElemName, this.props.wrapperElemProps, newChildren);
            }
        } else {
            return null;
        }
    },

    performAction: function (resultCallback?:CvResultCallback<CvNavigationResult>) {
        const launchAction:WorkbenchLaunchAction = this.launchAction();
        this._publishActionStarted(launchAction.actionId);
        this.catavolt().performLaunchAction(launchAction).onComplete((launchTry:Try<NavRequest>) => {
            this._publishActionFinished(launchAction.actionId);
            if (launchTry.isSuccess) {
                const event:CvEvent<CvNavigationResult> = 
                    CvNavigationResultUtil.publishNavigation(this.catavolt(), this.eventRegistry(), launchTry.success,
                    launchAction.actionId, launchAction.workbenchId, this.props.navTarget,
                    this.props.launchListeners, false, false);
                if(resultCallback && typeof resultCallback === 'function'){
                    resultCallback(event.eventObj);
                }
            } else {
                const event:CvEvent<CvMessage> = {type:CvEventType.MESSAGE,
                    eventObj:{message:'Launch of ' + this.launchAction().name + ' failed', messageObj:launchTry.failure,
                        type:CvMessageType.ERROR}}
                if(resultCallback && typeof resultCallback === 'function'){
                    resultCallback(null, launchTry.failure);
                }
                this.eventRegistry().publish(event, false);
            }
        });
    },

    workbench: function () {
        return this.props.workbench || this.firstInScope(Workbench);
    },

    _getCallbackObject: function ():CvLaunchActionCallback {

        return {
            fireLaunchAction: (resultCallback?:CvResultCallback<CvNavigationResult>):void => {
                this.performAction(resultCallback);
            }
        }
    },
    _publishActionStarted: function (actionId:string):void {
        const e:CvEvent<CvActionFiredResult> = {
            type: CvEventType.ACTION_FIRED,
            eventObj: {
                actionId: actionId,
                type: CvActionFiredResultType.ACTION_STARTED,
                source: null,
                clientAction: false
            }
        };
        this.props.actionListeners.forEach((listener)=> {
            listener(e)
        });
        (this.eventRegistry() as CvEventRegistry).publish<CvActionFiredResult>(e, false);
    },

    _publishActionFinished: function (actionId:string):void {
        const e:CvEvent<CvActionFiredResult> = {
            type: CvEventType.ACTION_FIRED,
            eventObj: {
                actionId: actionId,
                type: CvActionFiredResultType.ACTION_COMPLETED,
                source: null,
                clientAction: false
            }
        };
        this.props.actionListeners.forEach((listener)=> {
            listener(e)
        });
        (this.eventRegistry() as CvEventRegistry).publish<CvActionFiredResult>(e, false);
    }

});
