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

import * as React from 'react'
import {CvState, CvBaseMixin, CvContext, CvActionBase, CvActionBaseProps} from './catreact-core'
import {MenuDef, ObjUtil, EditorContext} from 'catavolt-sdk'
import {CvActionBaseState} from "./CvAction";


export var CvMenuItemBase = {

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

};

export interface CvMenuItemState extends CvActionBaseState {
}

export interface CvMenuItemProps extends CvActionBaseProps {

    /**
     * If no menuDef property and no actionId property is provided, the render method will
     * render all child MenuDefs of the given parentMenuItem (or attempt to find it in scope)
     */
    parentMenuItem?:MenuDef;
    /**
     * If provided, each 'child' sdk {MenuDef} of the current MenuDef is passed to the function, which should return a a component
     * to be rendered. The function should accept 2 params:
     * 
     * @param cvContext The current {@link CvContext}.  The cvContext.cvScope.scopeObj will be the current sdk {MenuDef}
     * @param menuItem A child sdk {MenuDef} of the current MenuDef
     */
    subMenuItemRenderer?:(cvContext:CvContext, menuItem:MenuDef)=>{}
}

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

/**
 * There are several ways to use CvMenuItem  
 * 
 * 1. Simple wrapper - Provide an actionId OR menuItem and (optionally) a wrapperElem and wrapperElemProps.  
 * This will render your child tags wrapped in wrapperElem with an onClick that fires 'this' action  
 * 1. Function for submenus - Provide an actionId OR menuItem and a subMenuItemRenderer
 * see {@link CvMenuItemProps.subMenuItemRenderer}.
 * Providing this function will allow you to render all 'child' MenuDefs (but not 'this' MenuDef).
 * The result will be wrapped in wrapperElem (if provided)
 * 1. Recursive rendering of child menus - Omit both an actionId and menuItem and (optionally) specify a parentMenuItem
 * The render method will render each child of the parentMenuItem (provided or found in scope) passing along all
 * additional properties to new child {@link CvMenuItem}s
 */
export var CvMenuItem = React.createClass<CvMenuItemProps, CvMenuItemState>({

    mixins: [CvBaseMixin, CvActionBase, CvMenuItemBase],
    
    componentDidMount: function() {
        this._componentDidMount();
    },

    componentWillReceiveProps: function(nextProps) {
        this._componentWillReceiveProps(nextProps);
    },

    getDefaultProps: function () {
        return {
            actionId: null,
            fireOnLoad:null,
            paneContext: null,
            navTarget: null,
            menuDef: null,
            actionListeners: [],
            navigationListeners: [],
            stateChangeListeners:[],
            parentMenuItem: null,
            subMenuItemRenderer: null,
            selectionProvider: null,
            renderer:null,
            wrapperElemName:'span',
            wrapperElemProps:{},
            wrapperEventHandlerName:'onClick',
            actionHandler:null
        }
    },

    getInitialState: function() {
        return this._getInitialState();
    },

    parentMenuDef: function() {
        return this.props.parentMenuItem || this.firstInScope(MenuDef);
    },

    render: function() {

        const menuDef = this.menuDef();

        if(menuDef) {
            
            /* render me (this.menuDef) */
            /* showOnMenu and displayMode values apply here */
            if(this.props.renderer) {
                return this._shouldRender(menuDef) ?
                    this.props.renderer(this.getChildContext().cvContext, this._getCallbackObj()) : null;
            /* render me - the markup with a 'click' wrapper */
            /* showOnMenu and displayMode values apply here */
            } else if(React.Children.count(this.props.children) > 0) {
                if(this._shouldRender(menuDef)) {
                    const props = ObjUtil.addAllProps(this.props.wrapperElemProps, {});
                    props[this.props.wrapperEventHandlerName] = ()=>{this.performAction()};
                    return React.createElement(this.props.wrapperElemName, props, this.props.children);
                } else {
                    return null;
                }
                
            /* render child menuDefs (this.menuDef.menuDefs) */
            } else if (this.props.subMenuItemRenderer) {
                let newChildren = [];
                menuDef.menuDefs.forEach((md:MenuDef, i:number)=> {
                    newChildren.push(React.cloneElement(this.props.subMenuItemRenderer(this.getChildContext().cvContext, md), {key:md.name + i}));
                });
                return React.createElement(this.props.wrapperElemName, this.props.wrapperElemProps, newChildren);
            } else {
                return null;
            }
            
        //render all menuDefs of my parent (i.e. wildcard)
        }else if(!this.props.actionId && this.props.renderer) {
            const parentMenuDef:MenuDef = this.parentMenuDef();
            if(parentMenuDef && parentMenuDef.menuDefs && parentMenuDef.menuDefs.length > 0) {
                let newChildren = [];
                parentMenuDef.menuDefs.forEach((md:MenuDef, i:number)=> {
                    newChildren.push(<CvMenuItem {...this.props} menuDef={md} key={md.actionId + i}/>);
                });
                return React.createElement(this.props.wrapperElemName, this.props.wrapperElemProps, newChildren);
            } else {
                return null;
            }
        } else {
            return null;
        }
    },
    
    _shouldRender: function(menuDef:MenuDef):boolean {
        
        if(!menuDef.showOnMenu) {
           return false; 
        }
        const paneContext = this.paneContext();
        if(paneContext && paneContext instanceof EditorContext) {
            if(menuDef.isRead && menuDef.isWrite) {
                return true;
            } else if(menuDef.isRead) {
               return (paneContext as EditorContext).isReadMode;
            } else if(menuDef.isWrite){
               return (paneContext as EditorContext).isWriteMode;
            } else {
                return false;
            }
        } else {
            return true;
        }
        
    }

});
