import * as React from 'react';
import Srl from "../data/Srl";
import SrlVisualizer from "./SrlVisualizer";
import TokensSelection from "./Selection/TokensSelection";
import RoleSelection from "./Selection/RoleSelection";
import DragingSelection from "./Selection/DragingSelection";
import {Selection} from "./SrlVisualizer";
import {blue, grey, red} from '@material-ui/core/colors';
import UndoIcon from '@material-ui/icons/Undo';
import EditHistory from './EditHistory';
import MenuList from "@material-ui/core/MenuList/MenuList";
import MenuItem from "@material-ui/core/MenuItem/MenuItem";
import Popover from "@material-ui/core/Popover/Popover";
import {FrameLabelSet} from "../data/FrameLabelSet";
import IconButton from "@material-ui/core/IconButton";
import Typography from "@material-ui/core/Typography";

type Anchor = {left:number, top:number};

type Props = {
    srl: Srl,
    noArrow?: boolean,
    onRequestSrlChange?: (srl:Srl)=>void,
    width?: number,
    frameLabelSets: FrameLabelSet[]
};


type Inks = string[];
type State = {
    srl?: Srl,
    selectedFrame: null|number,
    selection: Selection,
    menuAnchor: null|Anchor,
}

const menuItemProps = {
    dense: true,
    style: {
        fontSize: 12,
        lineHeight: 1,
        paddingTop: 4,
        paddingBottom: 4,
    }
};

class SrlEditable extends React.Component<Props, State>{
    currMousePos: Anchor = {left:0, top:0};
    state:State = {selectedFrame: null, selection: null, menuAnchor:null};
    history:EditHistory = new EditHistory();
    getInksThatHighlightFrame(frameIndex: null|number):Inks {
        if (frameIndex == null) return [grey[500]];
        const numFrames = this.getSrl().frames.length;
        const ret:Inks = Array(numFrames).fill(grey[500]);
        if(frameIndex<numFrames) ret[frameIndex] = blue[700];
        return ret;
    }
    getSrl():Srl {
        if(typeof this.state.srl === 'undefined') return this.props.srl;
        if(typeof this.props.onRequestSrlChange !== 'undefined') return this.props.srl;
        return this.state.srl
    }
    handleSelectionChange = (selection:Selection) => {
        if(selection instanceof DragingSelection) {
            this.setState({selection:selection, menuAnchor:null});
            return;
        }
        let candidate:Partial<State> = {selection:selection, menuAnchor:this.currMousePos};
        if(selection instanceof RoleSelection) candidate = {selectedFrame:selection.frameIndex, ...candidate};
        else if(selection == null) candidate = {selection: null, menuAnchor:null};
        this.setState(candidate as Pick<State, keyof State>);
    };
    handleSrlChange = (srl:Srl) => {
        this.setState({menuAnchor:null});
        if(typeof this.props.onRequestSrlChange === "function") this.props.onRequestSrlChange(srl);
        else this.setState({srl})
    };
    handleMenuClose = () => {
        this.setState({menuAnchor: null})
    };
    pushHistory() {
        this.history.push(this.getSrl(), this.state.selection, this.state.selectedFrame);
    }
    popHistory = () => {
        if(this.history.isEmpty()) return;
        const {srl, selection, selectedFrame} = this.history.pop()!;
        this.setState({selection, selectedFrame});
        setTimeout(()=>this.handleSrlChange(srl));
    };
    addFrame(predLabel: string) {
        const {selection} = this.state;
        if(selection instanceof TokensSelection) {
            const srl = Srl.addFrame(this.getSrl(), selection.beginIndex, selection.endIndex, predLabel);
            this.pushHistory();
            this.handleSrlChange(srl);
            this.handleSelectionChange(new RoleSelection(srl.frames.length-1, 0));
            this.setState({menuAnchor: null});
        }
    }
    addRole(name:string) {
        const {selectedFrame, selection} = this.state;
        if(selectedFrame != null && selection instanceof TokensSelection) {
            const srl = Srl.addRole(this.getSrl(), selectedFrame, selection.beginIndex, selection.endIndex,name);
            this.pushHistory();
            this.handleSrlChange(srl)
        }
    }
    removeFrame() {
        const {selectedFrame} = this.state;
        if(selectedFrame != null) {
            this.handleSelectionChange(null);
            const srl = Srl.removeFrame(this.getSrl(),selectedFrame);
            this.pushHistory();
            this.handleSrlChange(srl);
            this.setState({selectedFrame: null});
        }
    }
    removeRole() {
        const {selectedFrame, selection} = this.state;
        if(selectedFrame != null && selection instanceof RoleSelection) {
            this.handleSelectionChange(null);
            const srl = Srl.removeRole(this.getSrl(),selectedFrame, selection.roleIndex);
            this.pushHistory();
            this.handleSrlChange(srl);
        }
    }
    changeRole(name:string) {
        const {selectedFrame, selection} = this.state;
        if(selectedFrame != null && selection instanceof RoleSelection) {
            const srl = Srl.changeRole(this.getSrl(),selectedFrame, selection.roleIndex, name);
            this.pushHistory();
            this.handleSrlChange(srl);
        }
    }
    static findFrameLabelSet(frameLabelSets:FrameLabelSet[], srl:Srl):FrameLabelSet|null {
        const name = srl.frameLabelSetName;
        if(name == null) return null;
        for(const frameLabelSet of frameLabelSets) {
            if(frameLabelSet.name === name) return frameLabelSet;
        }
        return null;
    }
    renderMenuList() {
        const {frameLabelSets, srl} = this.props;
        const frameLabelSet = SrlEditable.findFrameLabelSet(frameLabelSets, srl) || frameLabelSets[0];
        if(frameLabelSet == null) {
            return <Typography style={{color:red[500]}}>no frame configuration defined</Typography>
        }
        const {selectedFrame, selection} = this.state;
        if(selectedFrame == null && selection instanceof TokensSelection) {
            return <MenuList>
                {frameLabelSet.targets.map(x=><MenuItem key={x} onClick={()=>this.addFrame(x)} {...menuItemProps}>
                    create frame&nbsp;<strong>{x}</strong>
                </MenuItem>)}
            </MenuList>
        }
        if(selectedFrame != null && selection instanceof TokensSelection) {
            return <MenuList>
                {frameLabelSet.targets.map(x=><MenuItem key={x} onClick={()=>this.addFrame(x)} {...menuItemProps}>
                    create frame&nbsp;<strong>{x}</strong>
                </MenuItem>)}
                {frameLabelSet.args.map(x=><MenuItem key={x} onClick={()=>this.addRole(x)} {...menuItemProps}>
                    mark as&nbsp;<strong>{x}</strong>
                </MenuItem>)}
            </MenuList>
        }
        if(selection instanceof RoleSelection) {
            const srl = this.getSrl();
            if(srl.frames.length<=selection.frameIndex) return null;
            const frame = srl.frames[selection.frameIndex];
            if(frame.roles.length<=selection.roleIndex) return null;
            if(frame.roles[selection.roleIndex].isPredicate) {
                return <MenuList>
                    <MenuItem onClick={()=>this.removeFrame()} {...menuItemProps}>remove frame</MenuItem>
                </MenuList>
            }
            return <MenuList>
                <MenuItem onClick={()=>this.removeRole()} {...menuItemProps}>remove role</MenuItem>
                {frameLabelSet.args.map(x=><MenuItem key={x} onClick={()=>this.changeRole(x)} {...menuItemProps}>
                    change to&nbsp;<strong>{x}</strong>
                </MenuItem>)}
            </MenuList>
        }
        return null;
    }
    render() {
        const srl = this.getSrl();
        const {selection,menuAnchor,selectedFrame} = this.state;
        return <div onMouseOver={e=>this.currMousePos = {left:e.clientX, top:e.clientY}}>
            {!this.history.isEmpty() && <IconButton color={"primary"} onClick={this.popHistory}><UndoIcon/></IconButton>}
            <SrlVisualizer srl={srl} selection={selection} onRequestSelectionChange={this.handleSelectionChange}
                           inks={this.getInksThatHighlightFrame(selectedFrame)} width={this.props.width}/>
            <Popover anchorReference={"anchorPosition"} anchorPosition={menuAnchor || {left:0,top:0}} open={!!(selection && menuAnchor)}
                     onClose={this.handleMenuClose}>
                {this.renderMenuList()}
            </Popover>

        </div>
    }
}

export default SrlEditable;