import * as React from "react";
import {SimpleGrid, Text, Title, Stack, Center, Image, Group, Space} from "@mantine/core";

import {PrimitiveRegistry} from "onion/primitive_delta";
import {mockUuid} from "onion/test_helpers";
import {OnionContext} from "../onion_context";
import {newOnion, undoButtonHelpText} from "../versioned_model/single_model2";
import {newCorrespondence, undoButtonHelpTextCorr} from "../versioned_model/correspondence2";
import {ModalManualRenderer, ManualRendererProps} from "../versioned_model/manual_renderer";
import {InfoHoverCard} from "../info_hover_card";
import corr_csImage from './assets/corr_cs.svg';
import corr_asImage from './assets/corr_as.svg';
import corr_corrImage from './assets/corr_corr.svg';
import {Actionblock, Resultblock} from "./blocks";


export const demo_Corr_description =
    <>
        <Title order={4}>
            Correspondence Model
        </Title>
        <Text>
            The different parts we have seen in the previous demos, are now in combined in different tabs in one column.
            The second row is just a copy of the upper one and shows exactly the same model(s). This allows the simultaneous observation of changes in the
            different models.
        </Text>
        <Text>
            The following figure shows the connection of the different models combined in the "Concrete Syntax" (CS)
            column.
            The two abstraction levels of Deltas L1 and L0 are combined as "CS Delta(s)" and the History is omitted in the
            figure.
        </Text>
        <Image src={corr_csImage}/>
        <Text>
            Analogously, the third column combines the different models shown in the first demo "Primitive Delta" into
            a single view, representing the "Abstract Syntax model" (AS).
            The difference to the Concrete Syntax in the first column is, that there is no additional "user-friendly"
            editor for editing the state. Instead, the state graph can be manipulated directly as already introduced in the first
            demo "Primitive Deltas". This way of manipulation is also illustrated in the following picture.
        </Text>
        <Image src={corr_asImage}/>
        <Text>
            Between the CS and AS the "Correspondence model" (Corr) encapsulates and connects the Deltas of the CS and
            AS models as visualized in the following picture.
        </Text>
        <Image src={corr_corrImage}/>
        <Text>
            The creation of Deltas of the Correspondence model and AS Deltas is triggered by the "Parsing" process.
            Parsing can either be automatically started after each user interaction or interactively at specific points
            in time, simulated by pressing the "Parse &gt;&gt;" button in the upper right corner of the first column.
        </Text>
        <Text>
            In turn, changes to the AS model are taken into account in the rendering process. Since the CS can contain
            information the AS does not contain, such as layout information, some user interaction
            may be required to add this missing information. This process is not automatically triggered by default.
        </Text>
        <Text>
            Common to all these three models (CS, Corr, AS) is the central foundation in Deltas encoding any change of
            the state graph. On this generic basis all other functionality is built on: conflict detection, versioning,
            undo/redo, etc. That is also the reason why these features can be presented in a homogeneous way for each of
            the models.
        </Text>
        <Text>
            This demo focuses on the parsing (CS &rarr; AS) and rendering (AS &rarr; CS).
        </Text>
        <Actionblock>
            1. Create a Rountangle!
        </Actionblock>
        <Resultblock>
            Below the rountangle editor, the new State graph of the CS is shown.
        </Resultblock>
        <Resultblock>
            Automatic parsing recognizes this rountangle as a state in the AS with ID = 2 and connects both via the
            Correspondence model by introducing a "connection node" with ID = 1.
        </Resultblock>
        <Resultblock>
            As visualized in the above picture, the Correspondence model contains the complete CS and AS model plus some
            more information relevant to maintain the relations between elements contained in the AS and the CS.
        </Resultblock>
        <Actionblock>
            2. Draw a second Rountangle and move and resize it such that the new rountangle completely surrounds the
            first one!
        </Actionblock>
        <Resultblock>
            The parser recognizes the (visual) containment relation between the two rountangles and translates this to a
            "has-parent" relation between the two (abstract) states. Again, you can find this relation also in the correspondence
            model.
        </Resultblock>
        <Actionblock>
            3. Create a new State in the AS by a right click in the canvas!
        </Actionblock>
        <Actionblock>
            4. Press the "&lt;&lt; Render"-button at the top!
        </Actionblock>
        <Resultblock>
            The rendering process detects missing information while it tries to create a CS model for the new state.
        </Resultblock>
        <Resultblock>
            A new dialog appears where one can position and resize the new rectangle.
        </Resultblock>
        <Resultblock>
            The system does not allow any position/size whose parsing would result in a different AS (e.g., additional or missing "hasParent" relation).
        </Resultblock>
        <Actionblock>
            5. Position the new state according to the given constraints!
        </Actionblock>
        <Resultblock>
            Your CS model is updated and the rountangles are visualized accordingly.
        </Resultblock>
        {/* TODO: remove z-index!
            TODO: deleted nodes/Rountangles are still considered in the "Missing information"-dialog
            TODO: everywhere: Arrows with directions!
        */}
    </>;

export function getDemoCorr() {
    const primitiveRegistry = new PrimitiveRegistry();
    const generateUUID = mockUuid();

    const as = newOnion({readonly: false, primitiveRegistry});
    const cs = newOnion({readonly: false, primitiveRegistry});
    const corr = newCorrespondence({cs, as, primitiveRegistry, generateUUID});

    // returns functional react component
    return function () {
        const onionAs = as.useOnion(reducer => ({
            onUserEdit: (deltas, description) => {
                const newVersion = onionAs.reducer.createAndGotoNewVersion(deltas, description);
                if (autoRender) {
                    onionCorr.reducer.renderExistingVersion(newVersion, setManualRendererState);
                }
            },
        }));
        const onionCs = cs.useOnion(reducer => ({
            onUserEdit: (deltas, description) => {
                const newVersion = reducer.createAndGotoNewVersion(deltas, description);
                if (autoParse) {
                    onionCorr.reducer.parseExistingVersion(newVersion);
                }
            },
        }));

        const onionCorr = corr.useCorrespondence(onionCs.reducer, onionAs.reducer);

        const [autoParse, setAutoParse] = React.useState<boolean>(true);
        const [autoRender, setAutoRender] = React.useState<boolean>(false);

        const [manualRendererState, setManualRendererState] = React.useState<null | ManualRendererProps>(null);

        const csTabs = ["editor", "state", "history", "deltaL1", "deltaL0"];
        const corrTabs = ["state", "history", "deltaL1", "deltaL0"];
        const asTabs = ["state", "history", "deltaL1", "deltaL0"];

        return (<div style={{minWidth: 1300}}>
            <OnionContext.Provider value={{generateUUID, primitiveRegistry}}>
            <ModalManualRenderer manualRendererState={manualRendererState}/>
            <SimpleGrid cols={3}>
                <div>
                    <Group position="apart">
                        <Title order={4}>Concrete Syntax</Title>
                        {onionCorr.components.getCaptionWithParseButton(
                            autoParse, setAutoParse, cs.getCurrentVersion())}
                    </Group>
                    <Space h="sm"/>
                    <Stack>
                        {onionCs.components.makeTabs("editor", csTabs)}
                        {onionCs.components.makeTabs("state", csTabs)}
                        <Center>
                            {onionCs.components.undoRedoButtons}
                            <Space w="sm"/>
                            <InfoHoverCard>
                                {undoButtonHelpText}
                            </InfoHoverCard>
                        </Center>
                    </Stack>
                </div>
                <div>
                    <Group position="center">
                        <Title order={4}>Correspondence</Title>
                    </Group>
                    <Space h="sm"/>
                    <Stack>
                        {onionCorr.components.makeTabs("state", corrTabs)}
                        {onionCorr.components.makeTabs("history", corrTabs)}
                        <Center>
                            {onionCorr.components.undoRedoButtons}
                            <Space w="sm"/>
                            <InfoHoverCard>
                                {undoButtonHelpText}
                                <Space h="sm"/>
                                {undoButtonHelpTextCorr}
                            </InfoHoverCard>
                        </Center>
                    </Stack>
                </div>
                <div>
                    <Group position="apart">
                        {onionCorr.components.getCaptionWithRenderButton(
                            autoRender, setAutoRender, as.getCurrentVersion(), setManualRendererState)}
                        <Title order={4}>Abstract Syntax</Title>
                    </Group>
                    <Space h="sm"/>
                    <Stack>
                        {onionAs.components.makeTabs("state", asTabs)}
                        {onionAs.components.makeTabs("history", asTabs)}
                        <Center>
                            {onionAs.components.undoRedoButtons}
                            <Space w="sm"/>
                            <InfoHoverCard>
                                {undoButtonHelpText}
                            </InfoHoverCard>
                        </Center>
                    </Stack>
                </div>
            </SimpleGrid>
            </OnionContext.Provider>
        </div>);
    }
}
