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

import * as React from 'react'
import {
    CvState, CvProps, CvBaseMixin,
    CvEvent, CvContext, CvViewDesc,
    CvViewDescProps, CvViewDescCallback, CvActionFiredResult,
    CvMessage, CvEventType, CvMessageType, CvNavigationResult,
    CvValueListener
} from 'catreact'
import {ViewDesc, PaneContext, ViewId, Try, ArrayUtil} from 'catavolt-sdk'
import ReactElement = React.ReactElement;

export interface CvViewMenuState extends CvState {
    selectedViewId:ViewId;
    visible:boolean;
}

export interface CvViewMenuProps extends CvProps {
    navigationListeners?:Array<(event:CvEvent<CvNavigationResult>)=>void>
    navTarget?:string;
    actionListeners?:Array<(event:CvEvent<CvActionFiredResult>)=>void>
    paneContext?:PaneContext;
    viewDescs:Array<ViewDesc>;
    openLeft?:boolean;
    viewSelectionListener?:CvValueListener<string>;
    viewLoadedListener?:CvValueListener<string>;
    selectedViewId?:string;
}

export var CvViewMenuBase = {

    paneContext: function (nextProps, nextContext):PaneContext {
        var paneContext:PaneContext = null;
        if(nextProps && nextProps.paneContext) {
            paneContext = nextProps.paneContext;
        } else if(nextContext) {
           paneContext = this.findPaneContext(nextContext.cvContext.scopeCtx);
        } else {
            paneContext = this.props.paneContext || this.findPaneContext();
        }
        return paneContext;
    },

    refresh: function (nextProps, nextContext) {

        /*
         * The purpose of this method is to reconcile the selectedView (given as a parameter)
          * with the server's selectedView
         */
        const paneContext = this.paneContext(nextProps, nextContext);
        const viewDescs = this.viewDescs(nextProps, nextContext);
        const selectedView = nextProps && nextProps.selectedViewId ? nextProps.selectedViewId : this.props.selectedViewId;
        const selectedViewDesc:ViewDesc = ArrayUtil.find<ViewDesc>(viewDescs, (viewDesc:ViewDesc)=>{
            return selectedView == viewDesc.viewId;
        });
        //if state hasn't been set, retrieve from server and set
        if(!this.state.selectedViewId) {
            paneContext.getSelectedViewId().onComplete((viewTry: Try<ViewId>) => {
                if (viewTry.isSuccess) {
                    if (this.isMounted()) {
                        this.setState({selectedViewId: viewTry.success});
                    }
                    //compare 'requested' view with what the server 'thinks' is the selected view
                    if(selectedViewDesc && selectedViewDesc.viewId != viewTry.success.value) {
                        //try to open the 'requested' view
                        (CvViewDesc as any).openView( selectedViewDesc, paneContext, this.eventRegistry(), this.catavolt(),
                            this.props.actionListeners, [], this.props.navigationListeners, this.props.navTarget,
                            (success:any, error?:any)=>{
                                if(!error){
                                    this.setState({selectedViewId: new ViewId(selectedViewDesc.viewId)});
                                    this.props.viewLoadedListener && this.props.viewLoadedListener(selectedViewDesc.viewId);
                                }
                            }
                        );
                    } else {
                        this.props.viewLoadedListener && this.props.viewLoadedListener(viewTry.success.value);
                    }
                } else {
                    const event: CvEvent<CvMessage> = {
                        type: CvEventType.MESSAGE,
                        eventObj: {
                            message: 'Could not get selected view id for ' + paneContext.paneDef.findTitle(),
                            messageObj: viewTry.failure,
                            type: CvMessageType.ERROR
                        }
                    }
                    this.eventRegistry().publish(event, false);
                }
            });
        } else {
            this.props.viewLoadedListener && this.props.viewLoadedListener(this.state.selectedViewId.value);
        }
    },
    
    viewDescs: function(nextProps, nextContext):Array<ViewDesc> {
        if(nextProps && nextProps.viewDescs) {
            return nextProps.viewDescs;
        } else {
            return this.props.viewDescs;
        }
    }

}


/*
 ***************************************************
 * Render a Menu
 ***************************************************
 */

export var CvDropdownViewMenu = React.createClass<CvViewMenuProps, CvViewMenuState>({
    
    mixins: [CvBaseMixin, CvViewMenuBase],
    
    componentWillMount: function() {
        if(!this._checkVisibility()) {
           this.props.viewLoadedListener && this.props.viewLoadedListener('no_view_support');
        }
    },

    componentDidMount: function () {
        if(this.state.visible) {
            this.refresh();
        }
    },

    componentWillReceiveProps: function (nextProps, nextContext) {
        if(this._checkVisibility(nextProps, nextContext)) {
            this.refresh(nextProps, nextContext);
        }
    },
    
    getDefaultProps: function () {
        return {
            paneContext: null,
            actionListeners: [],
            navigationListeners: [],
            navTarget: null,
            viewDescs: [],
            openLeft: false,
            viewSelectionListener: null,
            viewLoadedListener: null,
            selectedViewId: null
        }
    },
    
    getInitialState: function() {
        return {selectedViewId: null, visible:true}   
    },

    render: function () {
        
        if(this.state.visible) {

            const viewDescs:Array<ViewDesc> = this.viewDescs();
            const selectedViewId:ViewId = this.state.selectedViewId;
            let buttonText = 'Select View';
            if(selectedViewId && selectedViewId.value) {
                const selectedViewDesc:ViewDesc = ArrayUtil.find<ViewDesc>(this.viewDescs(), (viewDesc:ViewDesc)=>{
                    return selectedViewId.value == viewDesc.viewId;  
                });
                if(selectedViewDesc) {
                    buttonText =  selectedViewDesc.name;
                }
            }
            
            const itemProps:CvViewDescProps = {
                paneContext: this.props.paneContext,
                actionListeners: this.props.actionListeners,
                navigationListeners: this.props.navigationListeners,
                navTarget: this.props.navTarget,
                catavolt: this.props.catavolt,
                eventRegistry: this.props.eventRegistry
            };

            let viewItemClassName = "dropdown-menu cv-dropdown-menu";
            if (this.props.openLeft) viewItemClassName += ' dropdown-menu-right';

            const itemRenderer = (cvContext:CvContext, callback:CvViewDescCallback)=> {
                const viewDesc:ViewDesc = cvContext.scopeCtx.scopeObj;
                return <li onClick={()=>{ if(selectedViewId && (selectedViewId.value != viewDesc.viewId)) {
                    callback.openView((success:any, error?:any)=>{
                        if(!error){
                            this.setState({selectedViewId: new ViewId(viewDesc.viewId)});
                            this.props.viewSelectionListener && this.props.viewSelectionListener(viewDesc.viewId);
                        }
                    });
                }}}><a className="cv-target">{viewDesc.name}</a></li>
            };
            return (
                <span className="dropdown cv-view-dropdown">
                    <button className="btn btn-xs" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
                        {buttonText} <span className="caret"/>
                    </button>
                    <ul className={viewItemClassName}>
                        {viewDescs.map((viewDesc:ViewDesc)=>{
                            return <CvViewDesc {...itemProps} viewDesc={viewDesc} renderer={itemRenderer} key={viewDesc.viewId}/>
                        })}
                    </ul>
                </span>
            );
        } else {
            return null;
        }
    },
    
    _checkVisibility: function(nextProps, nextContext):boolean {
        const viewDescs:Array<ViewDesc> = this.viewDescs(nextProps, nextContext);
        if(!this.catavolt().isFeatureSetAvailable("View_Support") || !viewDescs || viewDescs.length < 2) {
            if(this.state.visible) {
                this.setState({visible: false});
            }
            return false;
        } else {
            if(!this.state.visible) {
                this.setState({visible:true});
            }
            return true;
        }
    }
    
});

