import React, {useRef, useCallback, useMemo,useState, useEffect} from 'react'
import {shallowEqual, useSelector,useDispatch} from 'react-redux'
import {createPortal} from 'react-dom'
import {Dropdown} from 'semantic-ui-react'
import {batch,connect} from 'react-redux'
import * as Immer from 'immer'
import * as Steps from './steps'
import * as Steps2 from './Steps2'
import * as Common from './common'
import * as StepMenu from './StepMenu'
import * as Operation from './Operation'
import * as SC from './SComponents'
import * as Palette from './Palette'
import useResizeAware from 'react-resize-aware';
import * as Shared from 'placeholder-shared'
import * as RunResult from './RunResult'
import * as Antd from 'antd'
import * as Drag from './Drag'
import * as Lineage from './Lineage'
import TextField from '@material-ui/core/TextField';

import { PlusOutlined,EllipsisOutlined,CaretDownOutlined} from '@ant-design/icons';
import { lineageGroupsReducer } from '../../shared/src/State'


var classnames = require('classnames')

export const getNextID = (treeData:Shared.TreeData.TreeData) => {
    const stepCounters = treeData.nodes.map(n=> n.stepCounter)
    if (!stepCounters.length) {
        return 1
    }
    return Math.max(...stepCounters) + 1
}

export const renameSuccessorsThunk = (stepCounter:number, newName:string) => {
    return (dispatch, getState) => {
        const currentName = Shared.Runner.getName(getState().steps[stepCounter])
        const successors = getState().edges.gFinal.successors(stepCounter)
        successors.forEach((successor) => 
        {
            const sql = getState().steps[successor].operation.sql
            let processedSQL = sql.slice(0)

            let regex = Shared.Runner.getTableRegex()
            let array1;
            while ((array1 = regex.exec(processedSQL)) !== null) {
                const tableRefName = array1[1].trim()
                if (tableRefName == currentName){
                    processedSQL = processedSQL.replace(array1[0], '${' + newName + '}')
                }
            }
            console.log("replace named SQL", processedSQL)

            dispatch(Shared.State.getUpdateStepOperationAction(successor,'sql', processedSQL, false))
            const config: Shared.Runner.IConfig = Shared.Runner.getConfigFromSQLString(processedSQL)
			dispatch(Shared.State.getUpdateTableRefAction(successor, config.tableRefs))
            return processedSQL
        }
        )
    }
}

export const useCreateMaterialization = () => {
    const dispatch = useDispatch()
    const createMaterialization = useCallback(() => {
        dispatch((dispatch, getState) => {
            const currentState = getState();
            const materializations = currentState.materializations
            const nextID = Math.max(Math.max(...(Object.keys(materializations).map(c => parseInt(c)))), 0) + 1
            dispatch(Shared.State.NewMaterialization(nextID, 'asdfasdf'))
        })
    }, [dispatch])
    return createMaterialization;
}

export const useCreateQueryStep = () => {
    const dispatch = useDispatch()
    const state = useSelector(state => state)

    const cb = useCallback((stepCounters) => {
        dispatch((dispatch,getState) => {
            batch(() => {
                const currentTask = 1
                //create new step
                const treeData = getState().treeData[currentTask]
                let newStepCounter = getNextID(treeData)
                const operation = Steps2.StepDict[Shared.Runner.StepTypes.sql].newOperation()
                dispatch(Shared.State.getCreateStepAction(operation, currentTask, newStepCounter, "", true, 0, 0))

                const sql = getSQLFromRunResult(getState(), stepCounters,newStepCounter)
                dispatch(Shared.State.getUpdateStepOperationAction(newStepCounter, 'sql', sql, false))
                dispatch(Shared.State.getShowStepAction(newStepCounter))
            })
        })
    },[dispatch])
    return cb
}

export const usePlayClick = (runState:Shared.RunState.RunState) => {
    let dispatch = useDispatch()
    return (e: React.MouseEvent) => {
        dispatch(Steps.PlayThunk(runState.currentTask, runState.currentStep, {}))
    }
}
export const useShowStepOnClick = (stepCounter:number) => {
    let dispatch = useDispatch()
    const isAddSqlActivated = useSelector(state => (state as any).UIState.isAddSqlActivated)
    const [hasDragged, setHasDragged] = useState({x:0,y:0})
    const onClick = useCallback((e:React.MouseEvent) => {
        e.stopPropagation()
        e.preventDefault()
        const inTolerance = (diff) => {
            return Math.abs(diff) < 3 

        }
        if (!inTolerance(e.clientX  -  hasDragged.x)|| !inTolerance(e.clientY -  hasDragged.y)) {
            return;
        }
        if (isAddSqlActivated) {
            dispatch(Shared.State.getSQLSelectAction(stepCounter))
        }
        else if (e.shiftKey) {
            dispatch(Shared.State.getShiftClickAction(stepCounter))
        }
        else {
            dispatch(Shared.State.getSetCurrentStepGraph(stepCounter))
            dispatch(Shared.State.changeUIState('mainWindowHide', false))
        }

    },[stepCounter,dispatch, isAddSqlActivated,hasDragged])
    const onMouseDown= useCallback((e:React.MouseEvent) => {
        setHasDragged({ x: e.clientX, y: e.clientY })
    },[setHasDragged])
    return [onClick, onMouseDown]
}
export const useStepRightClick = () => {
    const [visible, setVisible] = useState(false)
    const onVisibleChangeCB = useCallback((visible:boolean) => {
        setVisible(visible) 
    },[setVisible])
    return {visible, onVisibleChangeCB};
}
interface Dimensions {
	width: number;
	height: number;
}
export class SizeData {
	[Immer.immerable] = true;
	sizes:{[key:string]: Dimensions} =  {}
}

export type SizeDataUpdateCBType = (key:any, width:number, height:number) => any;
export const useSizeData = ():[any, SizeDataUpdateCBType] => {
    let sizeData = useSelector((currentState:any) => {
        return currentState.sizeRegistry
    })
    let dispatch = useDispatch()
	const onResize = useCallback((key:any, width:number, height:number) => {

        dispatch(Shared.State.getChangeSizeRegistry(key, width, height))
        /*
		setSizes((currentSize:SizeData) => {
			let newState = Immer.produce(currentSize, (draftState) => {
				draftState.sizes[key] = { width, height }
			})
			return newState;
        })
        */
    }, [dispatch])
    return [sizeData, onResize]
}

enum DragType { drag}
type PropTypes ={
    stepCounter?:number;
    children?:any
    onClick?:(e:React.MouseEvent) => any;
    style?:any;
    className?:string
    onResize:(width:number, height:number) => any;
}

interface DragInfo {
    stepCounterDragging :number | null;
}
const DefaultDragInfo:DragInfo = {
    stepCounterDragging:null
}

export const NodeContainer = (props:PropTypes) => {
    //drag
    const dragStep = useSelector((currentState:any) => {
        return currentState.UIState.dragStep
    })
    const {stepCounter, children, onClick, style, className, onResize} = props;
      //resize
    const [resizeListener, sizes] = useResizeAware();
    

    useEffect(() => {
        onResize(sizes.width, sizes.height)
    }, [onResize,sizes.width, sizes.height])


    let swallowEvent = useCallback((e:React.MouseEvent) => {
        if (dragStep.type != Drag.DragPayloadType.port) {
            e.stopPropagation()
        }
    }, [dragStep])
   let item = (<div style={props.style} onClick={props.onClick} className={classnames({
       'NodeContainerDragging':dragStep != null, 
       [className]:true,
       'NodeContainer':true})}>
       {resizeListener}

        {props.children}
    </div>)
    return item;
}

type NodeProps = {
    children?:any;
    selected:boolean
    className?:string
}
export const Node = (props:NodeProps) => {
    return <div className={classnames( {'Node':true, NodeSelected:props.selected, 
    NodeUnselected:!props.selected})}>
        {props.children}
    </div>
}


type StepTopProps = {
    children:React.ReactNode;
}
export const StepTop = (props:StepTopProps) => {
    return <div className='StepTop'>
        {props.children}
    </div>

}
type StepProps = {
    stepCounter: any,
}
export const Step = (props:StepProps) => {
    const { stepCounter} = props
    const stepType = useSelector(state => (state as any).steps[stepCounter].type)
    let item = null;
    item = Steps2.StepDict[stepType].step(stepCounter)
    console.assert(item)
    return <StateStepContainer
        stepCounter={stepCounter}
    >
        {item}
    </StateStepContainer>
}

type ResultsWidgetProps = {
    runResult:any;
    className?:string;
}

export const ResultsWidget = (props:ResultsWidgetProps) => {
    const {runResult, className} = props
    const getResultsDiv = useCallback(() => {
        return <RunResult.ResultsIndicator runResult={runResult} />
    }, [runResult])
  
    if (!runResult) {
        return null
    }
    return <div className={classnames('ResultsWidgetContainer', className)}>
        {getResultsDiv()}
    </div>;
}
type StepContainerProps = {
    stepCounter:number;
    children?:React.ReactNode;
    className?:string
}

const getSQLFromRunResult = (state, stepCounters: number[], newStepCounter: number) => {
    const internal = () => {
        const runResults = Shared.Runner.getRunResultsForStepCounters(state, stepCounters)
        const columnString = Object.keys(runResults).map((r) => {
            const fields = Shared.Common.getValueSafe(runResults[r], ['previewResult', 'fields'], [])
            let columnString = null
            if (!fields.length) {
                columnString = '*'
            }
            else {
                const columns = fields.map((f) => {
                    return f.name
                })
                columnString = columns.map(c => `${c} AS ${c}`).join(",\n\t")
            }
            return columnString
        })
        const getName = (operation) => {
            if (operation.type == Shared.Runner.StepTypes.sourceInput) {
                return operation.table
            }
            else {
                return operation.name
            }

        }
        let refString = null;
        if (!stepCounters.length) {
            refString = `\`YOUR_TABLE_HERE\``
        }
        else if (stepCounters.length == 1) {
            refString = `\$\{${getName(state.steps[stepCounters[0]].operation)}}`
        }
        else {
            //debugger;
            const joinColumnString = Object.keys(runResults).map((r) => {
                const stepName = getName(state.steps[r].operation)
                const fields = Shared.Common.getValueSafe(runResults[r], ['previewResult', 'fields'], [])
                let columnString = null
                if (!fields.length) {
                    columnString = `${stepName}.*`
                }
                else {
                    const columns = fields.map((f) => {
                        return f.name
                    })
                    columnString = columns.map(c => `${stepName}.${c} AS ${c}`).join(",\n\t")
                }
                return columnString

            })


            refString = `\$\{${getName(state.steps[stepCounters[0]].operation)}} AS ${getName(state.steps[stepCounters[0]].operation)}`
            let columnJoinStrings = []
            stepCounters.forEach((s, index) => {
                const stepName = getName(state.steps[s].operation)
                columnJoinStrings.push(`${stepName}.*`)
                if (!index)
                    return;
                const previousStepName = getName(state.steps[stepCounters[index - 1]].operation)
                refString = `${refString} 
INNER JOIN \$\{${stepName}} AS ${stepName} 
    ON ${previousStepName}./* INSERT JOIN KEY 1 */ = ${stepName}./* INSERT JOIN KEY 2*/`
            })
            return `SELECT 
    ${joinColumnString.join(",\n\t")} 
FROM ${refString}
`

        }
        return `SELECT 
    ${columnString}
FROM ${refString}
`
    }
    return Common.FormatSQL(internal())
}

export const TreeContext = React.createContext({inDragPreview:false})

export const useCreateJoinQueryThunk = (nameAlreadyExistsCB)=>{    
    const onViewDependencies = StepMenu.useViewDependencies()
    return (dispatch, getState) =>{
        //const onViewDependencies = StepMenu.useViewDependencies()
        const currentTask = getState().currentTask;
        const currentStepGraph = getState().currentStepGraph;
        const stepsSelect = getState().stepsSelect;
        let newStepCounter = getNextID(getState().treeData[1])
        const operation = Steps2.StepDict[Shared.Runner.StepTypes.sql].newOperation()
        const queryName = "NewModel"+newStepCounter;
        //check for name colision
        const [nameExists, conflictingName] = nameAlreadyExistsCB(newStepCounter-1, queryName)
        if (nameExists) {
            Antd.message.error(<span>Cannot add  <b>{queryName}</b> because the table name {conflictingName} already exists in the graph.</span>
            )
        }
        else {
            batch(() => {
                dispatch(Shared.State.getCreateStepAction(operation, currentTask, newStepCounter, "", true, 0, 0))
                const sql = getSQLFromRunResult(getState(), [currentStepGraph, ...Object.keys(stepsSelect)],newStepCounter)
                dispatch(Shared.State.getUpdateStepOperationAction(newStepCounter, 'name', queryName, false))
                dispatch(Shared.State.getUpdateStepOperationAction(newStepCounter, 'sql', sql, false))
                dispatch(Shared.State.getShowStepAction(newStepCounter))
                dispatch(Shared.State.changeUIState("isAddJoinModalVisible", false))
                setTimeout(() => onViewDependencies(newStepCounter), 0)
            })
        }
    }
}

export const postAddActions = (fromStepCounters: number[], newStepCounter: number) => {
    return (dispatch, getState) => {
        const queryName = "NewModel" + newStepCounter;
        dispatch(Shared.State.getShowStepAction(newStepCounter))
        dispatch(Shared.State.getUpdateStepOperationAction(newStepCounter, 'name', queryName, false))
        if (fromStepCounters.length) {
            const lineageGroups = Lineage.getLineageForSteps(getState(), fromStepCounters)
            dispatch(Shared.State.moveToLineageGroup({ [newStepCounter]: true }, lineageGroups))
        }
    }
}

export const StepContainer = (props:StepContainerProps)=> {
    const {stepCounter, children, className} = props
    const dispatch = useDispatch()
    const nameAlreadyExistsCB = StepMenu.useNameAlreadyExistsCB();
    const {visible, onVisibleChangeCB} = useStepRightClick()
    const currentTask = useSelector(state=>(state as any).currentTask)
    const currentStep = useSelector(state=>(state as any).currentStep)
    const currentStepGraph = useSelector(state=>(state as any).currentStepGraph)
    const stepsSelect = useSelector(state => (state as any).stepsSelect)
    const lineageGroups = useSelector(state => (state as any).lineageGroups)

    const runResults = useSelector(state => (state as any).runResults[stepCounter])
    const dragStep :any = useSelector((currentState:any) => {
        return currentState.UIState.dragStep
    })

    //const dragPreviewRef = useRef()
    const onMouseDown = (e:any) => {
        //e.stopPropagation()
    }
    const changeDragStep = Drag.useChangeDragInfo('dragStep')
    const onDragStart = useCallback((e: React.DragEvent) => {
        //console.log("drag start", e, stepCounter, dragPreviewRef.current)
        if (e.currentTarget == e.target) {
            changeDragStep({ type: Drag.DragPayloadType.step, stepCounter, offsetX: e.nativeEvent.offsetX, offsetY: e.nativeEvent.offsetY })
        }
        //let elem = document.getElementById('DragPreviewContainer-' + stepCounter)
        //e.dataTransfer.setDragImage(dragPreviewRef.current, 0, 0)
        //e.stopPropagation()
    }, [])
    const onDragEnd = useCallback(() => {
        console.log("in step container computing on drag end")
        changeDragStep(null)
    }, [])


    //menuprompt
    const [mouseInside, setMouseInside] = useState(false)
    const [visible2, setVisible2] = useState(false)
    const onVisibleChange2CB = (visible:boolean) => {
        setVisible2(visible)
    }

   let thisNodeBeingDragged = dragStep && stepCounter == dragStep.stepCounter

    const onDeleteStep = useCallback(() => {
        dispatch((dispatch, getState) => {
            const edges = getState().edges
            dispatch(
                Shared.State.getRemoveStepAction(stepCounter, currentTask, edges))
        })
    }, [currentTask, stepCounter,dispatch])
    const onViewDependencies = StepMenu.useViewDependencies()
    const filtering = StepMenu.useGetFiltering()
    const createJoinQuery = useCallback((e) => {
        dispatch((dispatch, getState) => {
            let newStepCounter = getNextID(getState().treeData[1])
            const operation = Steps2.StepDict[Shared.Runner.StepTypes.sql].newOperation()
            const queryName = "NewModel"+newStepCounter;
            //check for name colision
            const [nameExists, conflictingName] = nameAlreadyExistsCB(stepCounter, queryName)
            if (nameExists) {
                Antd.message.error(<span>Cannot add  <b>{queryName}</b> because the table name {conflictingName} already exists in the graph.</span>
                )
            }
            else {
                batch(() => {
                    //dispatch(Shared.State.getCreateStepAction(operation, currentTask, newStepCounter, "", true, 0, 0))
                    //const joinSteps = [currentStepGraph, ...Object.keys(stepsSelect)]
                    //const sql = getSQLFromRunResult(getState(), joinSteps,newStepCounter)
                    //dispatch(Shared.State.getUpdateStepOperationAction(newStepCounter, 'name', queryName, false))
                    //dispatch(Shared.State.getUpdateStepOperationAction(newStepCounter, 'sql', sql, false))
                    //dispatch(Shared.State.getShowStepAction(newStepCounter))
                    //const lineageGroups = Lineage.getLineageForSteps(getState(), [currentStepGraph, ...Object.keys(stepsSelect)])
                    //const steps = {[newStepCounter]:true}
                    //dispatch(Shared.State.moveToLineageGroup( steps, lineageGroups))

                    dispatch(Shared.State.changeUIState('isAddJoinModalVisible', true));
                    onVisibleChangeCB(false)
                    onVisibleChange2CB(false)
                    //setTimeout(() => onViewDependencies(newStepCounter), 0)
                })
            }
        })
    },[stepsSelect,currentStepGraph,currentTask,dispatch,onVisibleChangeCB, onVisibleChange2CB,onViewDependencies,nameAlreadyExistsCB,stepCounter])

    const createQuery = useCallback(() => {
        
        dispatch((dispatch,getState)=> {
            dispatch(Shared.State.changeUIState('mainWindowHide', false))
            let newStepCounter = getNextID(getState().treeData[1])
            const operation = Steps2.StepDict[Shared.Runner.StepTypes.sql].newOperation()
            const queryName = "NewModel"+newStepCounter;
            //check for name colision
            const [nameExists, conflictingName] = nameAlreadyExistsCB(stepCounter, queryName)
            if (nameExists) {
                Antd.message.error(<span>Cannot add  <b>{queryName}</b> because the table name {conflictingName} already exists in the graph.</span>
                )
            }
            else {
                batch(() => {
                    dispatch(Shared.State.getCreateStepAction(operation, currentTask, newStepCounter, queryName, true, 0, 0))
                    const sql = getSQLFromRunResult(getState(), [stepCounter],newStepCounter)
                    dispatch(Shared.State.getUpdateStepOperationAction(newStepCounter, 'sql', sql, false))
                    dispatch(postAddActions([stepCounter], newStepCounter))
                })
            }
            onVisibleChangeCB(false)
            onVisibleChange2CB(false)
            setTimeout(() => onViewDependencies(newStepCounter),0)
        })
    },[currentTask, stepCounter,dispatch,onVisibleChangeCB,onVisibleChange2CB,onViewDependencies,nameAlreadyExistsCB])

    const runTo =useCallback((e) => {
        dispatch((dispatch, getState) => {
            const gFinal = getState().edges.gFinal
            let predecessors = []
            const processNode = (stepCounter) => {
                const thisP = gFinal.predecessors(stepCounter)
                if (thisP) {
                    thisP.forEach((singleP) => {
                        predecessors.push(parseInt(singleP))
                        processNode(singleP)
                    })
                }
            }
            processNode(stepCounter)
            dispatch(Shared.Runner.PlayTaskThunk(1, null, predecessors))
        })
        onVisibleChangeCB(false)
        onVisibleChange2CB(false)
    },[dispatch,stepCounter,onVisibleChangeCB, onVisibleChange2CB])

    const runStep = useCallback((e) => {
        dispatch((dispatch,getState) => {
            dispatch(Shared.Runner.PlayTaskThunk(1, null, [stepCounter]))
        })

        onVisibleChangeCB(false)
        onVisibleChange2CB(false)
    },[dispatch,stepCounter,onVisibleChangeCB, onVisibleChange2CB])
    const runAfter = useCallback((e) => {
        dispatch((dispatch,getState) => {
            dispatch((dispatch, getState) => {
                const gFinal = getState().edges.gFinal
                let successors = []
                const processNode = (stepCounter) => {
                    const thisP = gFinal.successors(stepCounter)
                    if (thisP) {
                        thisP.forEach((singleP) => {
                            successors.push(parseInt(singleP))
                            processNode(singleP)
                        })
                    }
                }
                processNode(stepCounter)
                dispatch(Shared.Runner.PlayTaskThunk(1, null, [stepCounter,...successors]))
            })
        })

        onVisibleChangeCB(false)
        onVisibleChange2CB(false)
    }, [dispatch, stepCounter, onVisibleChangeCB, onVisibleChange2CB])

    const runModels = useCallback((e) => {
        dispatch((dispatch, getState) => {
            dispatch(Shared.Runner.PlayTaskThunk(1, null, [currentStepGraph, ...Object.keys(stepsSelect)].map(s => parseInt(s))))
        })

        onVisibleChangeCB(false)
        onVisibleChange2CB(false)
    }, [dispatch, onVisibleChangeCB, onVisibleChange2CB, currentStepGraph, stepsSelect])

    const swallow = (e) => { e.stopPropagation() }

    const openNewTab = useCallback((e) => {
        onVisibleChangeCB(false)
        onVisibleChange2CB(false)
        batch(() => {
            dispatch(Shared.State.getShowStepAction(stepCounter))
            dispatch(Shared.State.getSetCurrentStepGraph(stepCounter))
            onViewDependencies(stepCounter)
        })
    }, [stepCounter, dispatch, onViewDependencies, onVisibleChangeCB, onVisibleChange2CB])
    const deleteModels = useCallback(() => {
        dispatch((dispatch, getState) => {
            const edges = getState().edges
            const modelsToDelete = [currentStepGraph, ...Object.keys(stepsSelect)].map(s => parseInt(s))
            batch(() => {
                modelsToDelete.forEach((s) => {
                    dispatch(
                        Shared.State.getRemoveStepAction(s, currentTask, edges))
                })
            })
        })
    },[currentStepGraph, dispatch, currentTask, stepsSelect])
    const rightMenu = useMemo(() => {
        const allHighlightedSteps = { [currentStepGraph]: true, ...stepsSelect }
        const inHighlightedSteps = stepCounter in allHighlightedSteps
        const hasMultipleSteps = Object.keys(stepsSelect).length
        const singleStep = currentStepGraph == stepCounter && !hasMultipleSteps

        const getLineageGroupMenu = () => {
            return <Antd.Menu.SubMenu  key='MoveToLineageGroup' title='Add to Lineage Group'>
                {!lineageGroups? []:Object.keys(lineageGroups).map((k) => {
                    return <Antd.Menu.Item onMouseDown={swallow} onClick={(e:any) => {
                        dispatch(Lineage.AddToLineageGroupThunk(k))
                    }}
                    key={k}>{k}</Antd.Menu.Item>
        })
}

<Antd.Menu.Divider />
                <Antd.Menu.Item key='createNew' onMouseDown={swallow}
                onClick={
                    () => {
                        dispatch(Shared.State.changeUIState('createLineageGroupModal',true))
                    }
                }>
                    <PlusOutlined/>Create new lineage group
                </Antd.Menu.Item>
            </Antd.Menu.SubMenu>
        }


        if (singleStep == true || !(stepCounter in allHighlightedSteps) == true) {
            return <Antd.Menu>
                <Antd.Menu.Item key='edit' onMouseDown={swallow} onMouseUp={swallow} onClick={openNewTab}>Edit</Antd.Menu.Item>
                <Antd.Menu.Divider key='divider0' />
                <Antd.Menu.Item onMouseDown={swallow} onMouseUp={swallow} onClick={runStep}>Run</Antd.Menu.Item>
                <Antd.Menu.Divider key='divider3' />
                <Antd.Menu.Item onMouseDown={swallow} onMouseUp={swallow} onClick={runTo}>Run Before</Antd.Menu.Item>
                <Antd.Menu.Item onMouseDown={swallow} onMouseUp={swallow} onClick={runAfter}>Run After</Antd.Menu.Item>
                <Antd.Menu.Divider key='divider2' />
                {getLineageGroupMenu()}
                <Antd.Menu.Divider key='divider1' />
                <Antd.Menu.Item key='deleteStep' onMouseDown={swallow} onMouseUp={swallow} onClick={onDeleteStep}>Delete</Antd.Menu.Item>
                <Antd.Menu.Divider />
                <Antd.Menu.Item key='createQuery' onMouseDown={swallow} onMouseUp={swallow} onClick={createQuery}>Add New Model</Antd.Menu.Item>
            </Antd.Menu>
        }
        else {
            return <Antd.Menu>
                <Antd.Menu.Item key='runModels' onMouseDown={swallow} onMouseUp={swallow} onClick={runModels}>Run Models</Antd.Menu.Item>
                <Antd.Menu.Divider key='divider3' />
                {getLineageGroupMenu()}
                <Antd.Menu.Divider key='divider1' />
                <Antd.Menu.Item key='createJoinQuery' onMouseDown={swallow} onMouseUp={swallow} onClick={createJoinQuery}>Join Models</Antd.Menu.Item>
                <Antd.Menu.Divider key='divider2' />
                <Antd.Menu.Item key='deleteModels' onMouseDown={swallow} onMouseUp={swallow} onClick={deleteModels}>Delete Models</Antd.Menu.Item>
            </Antd.Menu>
        }
    }, [createQuery, createJoinQuery,currentStepGraph, deleteModels,lineageGroups, dispatch,openNewTab,stepsSelect, stepCounter, onDeleteStep, runTo, runAfter, runStep, runModels])

    const mouseEnter=(e:React.MouseEvent) => {
        setMouseInside(true)
    }
    const mouseLeave = (e:React.MouseEvent) => {
        setMouseInside(false)
    }

    const getMenuPrompt = useCallback(() => {
        return null;
        const shouldShow = visible2 || mouseInside
        return <Common.DivWithClassName className=
            {Common.classNames({ displayNone: !shouldShow })
            }
        >
            <EllipsisOutlined />
        </Common.DivWithClassName>
    },[mouseInside, visible2])
    return <Common.DivWithClassName
        className={className}
        style={{ padding: '0px 0px 0px 0px' }}
        onMouseEnter={mouseEnter}
        onMouseLeave={mouseLeave}>
    <Antd.Dropdown visible={visible} onVisibleChange={onVisibleChangeCB} trigger={['contextMenu']}
        overlay={rightMenu} ><div className='rowFlexBox flexGrow'
         >
      
      {/*}
            <Drag.DragSourceContainer className={classnames({
                'StepContentContainer': true,
                'ThisNodeBeingDragged': thisNodeBeingDragged
            })}
                sourceID={stepCounter} onDragEnd={onDragEnd} onDragStart={onDragStart} payload={{ stepCounter }}>
        */}
                {children}
                {/*}

            </Drag.DragSourceContainer>
            <Common.DivWithClassName className='dropdownPrompt floatRight'
            onClick={swallow}
            >
                    <Antd.Dropdown 
                    visible={visible2}
                    onVisibleChange={onVisibleChange2CB}
                    trigger={['click']} overlay={rightMenu}>
                        <Common.DivWithClassName className={
                            Common.classNames({
                                positionAbsolute:true,
                            })
                        }>
                        {getMenuPrompt()}
                        </Common.DivWithClassName>
                    </Antd.Dropdown>
            </Common.DivWithClassName>
    */}
    </div>
    </Antd.Dropdown>
    </Common.DivWithClassName>
}
export var StateStepContainer = React.memo(StepContainer)

export const StepField = (props:{
    onFocus:Function,
    onBlur:Function,
    onKeyUp:Function,
    onKeyPress:Function,
    onChange:Function,
    nameRef:React.Ref<any>,
    value:String|number,
    label:String,
    id:string
}) => {
    const {id,onFocus, onBlur, onKeyUp, onKeyPress,onChange,nameRef,value, label} = props
	return <TextField id={id} fullWidth
		onFocus={(e: any) => {
            onFocus(e)
		}}
		onBlur={(e: any) => {
            onBlur(e)
		}}

		onKeyUp={(ev) => {
            onKeyUp(ev)
        }}
        onKeyPress={(ev) => {
            onKeyPress(ev)
        }}
        className={Common.classNames({
        })}
		inputRef={nameRef} label={label} size="small" value={
			value != -1? value:
				name}
		onChange={onChange as any}
	/>

}