/**
 * Created by rburson on 3/18/16.
 */

import * as React from 'react'
import {
    CvState,
    CvProps,
    CvBaseMixin,
    CvEvent,
    CvNavigationResult,
    CvNavigation,
    CvStateChangeResult,
    CvActionFiredResult,
    CvActionFiredResultType,
    CvEventType,
    CvMessage,
    CvMessageType,
    CvEventRegistry,
    CvContext
} from 'catreact'

import {
    CvFormPanel,
    CvWebNavigator,
    CvFormComponentProvider,
    CvDisplayProperties
} from './catreact-html'

import {AppContext, NavRequest, FormContext, Log, WebRedirection} from 'catavolt-sdk'

export interface CvNavigatorState extends CvState {
}

export interface CvNavigatorProps extends CvProps {
    /**
     * The result of a navigation.  Should not be used if the navigationId property is provided
     */
    navigationResult?:CvNavigationResult;
    /**
     * The cache identifier of the result of a Navigation.
     * Should not be used if the navigationResult property is provided
     */
    navigationId?:string;
    /**
     * Register to receive {@link CvEvent}s of type {@link CvNavigationResult}
     */
    navigationListeners?:Array<(event:CvEvent<CvNavigationResult>)=>void>;
    /**
     * Register to receive {@link CvEvent}s of type {@link CvActionFiredResult}
     */
    actionListeners?:Array<(event:CvEvent<CvActionFiredResult>)=>void>;
    /**
     * Register to receive {@link CvEvent}s of type {@link CvStateChangeResult}
     */
    stateChangeListeners?:Array<(event:CvEvent<CvStateChangeResult>)=>void>;
    /**
     * A FormLayout component to use instead of the one supplied by the server meta data
     */
    layoutOverrideElem?:any;
    /**
     * Provide a custom renderer for the entire form.  See {@link CvFormComponentProvider}
     */
    formComponentProvider?:CvFormComponentProvider;
    /**
     * Setting persistent true, allows this component to remain visible, even after another, new Navigation has
     * taken place.  This is useful for single page apps where components may be coresident.
     */
    persistent?: boolean,
    /**
     * Allows for one Navigation component to target another, when coresident on the page.
     */
    targetId?:string,
    /**
     * Mechanism to provide display 'settings' that are not maintained by the catavolt server
     */
    displayProperties?:CvDisplayProperties,
    /**
     * Register to receive notification of changes to display property values
     * This is primarily to allow urls to react to these changes and update accordingly
     */
    displayPropChangeListeners?:Array<(displayProperties:CvDisplayProperties)=>void>;
}


/**
 * Render a NavRequest
 */
export var CvNavigator = React.createClass<CvNavigatorProps, CvNavigatorState>({

        propTypes: {

            /**
             * navigationResult?:CvNavigationResult;
             */
            navigationResult: React.PropTypes.object,

            /**
             * alternative to navigationResult - the id will be used to find the navigationResult in the cache
             */
            navigationId: React.PropTypes.string,

            /**
             * navigationListeners?:Array<(event:CvEvent<CvNavigationResult>)=>void>;
             */
            navigationListeners: React.PropTypes.arrayOf(React.PropTypes.func),

            /**
             * actionListeners?:Array<(event:CvEvent<CvActionFiredResult>)=>void>;
             */
            actionListeners: React.PropTypes.arrayOf(React.PropTypes.func),

            /**
             * stateChangeListeners?:Array<(event:CvEvent<CvStateChangeResult>)=>void>;
             */
            stateChangeListeners: React.PropTypes.arrayOf(React.PropTypes.func),
            
            layoutOverrideElement: React.PropTypes.element,

            /**
             * formComponentProvider?:CvFormComponentProvider;
             */
            formComponentProvider: React.PropTypes.object,

            targetId: React.PropTypes.string,

            catavolt: React.PropTypes.instanceOf(AppContext),

            eventRegistry: React.PropTypes.instanceOf(CvEventRegistry),
            /**
             * renderer signature: (cvContext:CvContext, callbackObj?:any)=>{}
             * ctx.cvContext.scopeCtx.scopeObj will be of type NavRequest
             */
            renderer:React.PropTypes.func,
            
            displayProperties: React.PropTypes.any,
           
            displayPropChangeListeners: React.PropTypes.arrayOf(React.PropTypes.func)
            
        },

    mixins: [CvBaseMixin],

    shouldComponentUpdate: function(nextProps, nextState) {
       return ((nextProps.navigationId && nextProps.navigationId !== this.props.navigationId) ||
           (nextProps.navigationResult && nextProps.navigationResult !== this.props.navigationResult) ||
        (nextProps.displayProperties && nextProps.displayProperties !== this.props.displayProperties));
    },

    getDefaultProps: function () {
        return {
            navigationResult: null,
            navigationId: null,
            navigationListeners: [],
            actionListeners: [],
            stateChangeListeners: [],
            layoutOverrideElem: null,
            formComponentProvider: null,
            persistent: false,
            targetId: null,
            displayProperties:new CvDisplayProperties(),
            displayPropChangeListeners:[]
        };
    },

    navRequest: function () {
        if (this.props.navigationResult && this.props.navigationResult.navRequest) {
            return this.props.navigationResult.navRequest;
        } else if (this.props.navigationId) {
            return (this.eventRegistry().getEventByKey(this.props.navigationId).eventObj as CvNavigationResult).navRequest;
        } else {
            return null;
        }
    },

    render: function () {
        
        /* @TODO
            Add web navigation renderer back by adding an optional webRenderer to CvFormPane
            See prior version of this file...
         */

        return <CvNavigation navigationResult={this.props.navigationResult}
                             navigationId={this.props.navigationId}
                             persistent={this.props.persistent}
                             targetId={this.props.targetId}
                             renderer={(cvContext:CvContext)=>{
                                return <CvFormPanel formContext={cvContext.scopeCtx.scopeObj} navigationListeners={this.props.navigationListeners}
                                             stateChangeListeners={this.props.stateChangeListeners}
                                             actionListeners={this.props.actionListeners}
                                             layoutOverrideElem={this.props.layoutOverrideElem}
                                             formComponentProvider={this.props.formComponentProvider}
                                             displayProperties={this.props.displayProperties}
                                             displayPropChangeListeners={this.props.displayPropChangeListeners}/>
                                         }}/>
    }

});



