import * as React from 'react';
import { Button, TextField, Grid, Box, ExpansionPanel, ExpansionPanelSummary, ExpansionPanelDetails, Typography, Table, TableHead, TableRow, TableCell, TableBody, Container } from '@material-ui/core';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import { chosenAlphabet, inputLoad, writerToOutput, regexp, myAlert } from '../../basicLayout';

export interface ICaesarCipherProps {
    idInput: string,
    idOutput: string,
    idSwitch: string
}

export interface ICaesarCipherState {
    caesarOutput: string
}

export default class CaesarCipher extends React.Component<ICaesarCipherProps, ICaesarCipherState> {
    constructor(props: ICaesarCipherProps) {
        super(props);

        this.state = {
            caesarOutput: ""
        }
    }

    private moveLoad(): number {
        if (document.getElementById("numberField") != null) {
            if ((document.getElementById(this.props.idSwitch) as HTMLInputElement).checked)
                return -(document.getElementById("numberField") as HTMLInputElement).valueAsNumber;
            return (document.getElementById("numberField") as HTMLInputElement).valueAsNumber;
        }
        else {
            myAlert('Something wrong within moveLoad function!', 'error', 'Element \'Numberfield\' = null');
            return NaN;
        }
    }

    public CaesarCipher(input: string[], move: number): string {
        var message: string = "";
        var caesarAlphabet: string[] = this.alphabetMove(move);

        input.forEach(element => {
            var upperCase = false;
            if(element.match(regexp)) {
                if (element === element.toUpperCase()) {
                    upperCase = true;
                    element = element.toLowerCase();
                }
                element = caesarAlphabet[chosenAlphabet.indexOf(element)];
    
                if (upperCase)
                    element = element.toUpperCase();
            }
            
            message += element;
        });

        //WRITE TO OUTPUT FIELD
        return message;
    }

    public alphabetMove(move: number): string[] {
        var movedAlphabet: string = '';

        if (move > (chosenAlphabet.length - 1) || move < (-chosenAlphabet.length + 1))
            move = move % chosenAlphabet.length;
        
        // MOVE OF THE ALPHABET FOR TABLE
        chosenAlphabet.forEach((element: string) => {
            var tmpMove = move;
            for (var i = 0; i < chosenAlphabet.length; i++) {
                if (element === chosenAlphabet[i]) {
                    if (tmpMove >= 0) {
                        if ((i + tmpMove) > (chosenAlphabet.length - 1)) {
                            tmpMove = tmpMove + i - chosenAlphabet.length;
                            i = 0;
                        }
                        element = chosenAlphabet[i + tmpMove];
                        break;
                    } else {
                        if ((i + tmpMove) < 0) {
                            tmpMove = tmpMove + i + chosenAlphabet.length;
                            i = 0;
                        }
                        element = chosenAlphabet[i + tmpMove];
                        break;
                    }
                } else continue;
            }
            movedAlphabet += element;
        });
        
        return movedAlphabet.split('');
    }

    private createRowData(move: any) {
        // LOAD AND PREPARATION OF THE MOVE OF THE ALPHABET FOR TABLE
        if (document.getElementById("numberField") && !isNaN((document.getElementById("numberField") as HTMLInputElement).valueAsNumber)) {
            move = (document.getElementById("numberField") as HTMLInputElement).valueAsNumber;
        }
        else
            move = 3;
        
        var movedAlphabet: string[] = this.alphabetMove(move);
        return movedAlphabet;
    }

    public render() {
        var move: number = 0;
        // CONSTANT FOR ROWS OF THE TABLE
        const row = this.createRowData(move);
        const tableCellsAlphabet = chosenAlphabet.map(e =>
            <TableCell key={e} align="center" component="th" scope="row" style={{ padding: 3 }}>
                {e}
            </TableCell>
        );
        const tableCellsMovedAlphabet = row.map((e: any) =>
            <TableCell key={e} align="center" component="th" scope="row" style={{ padding: 3 }}>
                {e}
            </TableCell>
        );

        return (
            <div>
                <Grid
                    container
                    className='rowGrid'
                >
                    <Box my={2}>
                        <TextField
                            required
                            id="numberField"
                            label="Key"
                            type="number"
                            defaultValue='3'
                            helperText="Movement key (alphabet movement)."
                            InputLabelProps={{
                                shrink: true,
                            }}
                            onChange={ () => {
                                this.forceUpdate();
                            }}
                            className='numberField'
                        />
                    </Box>
                    <Container>
                        <Button
                            size="large"
                            variant="contained"
                            color="secondary"
                            autoFocus
                            onClick={ () => {
                                this.forceUpdate();

                                if (isNaN((document.getElementById("numberField") as HTMLInputElement).valueAsNumber)) {
                                    var tmp = myAlert("Move not defined! Please define alphabet move:", 'enter', '3');
                                    if(tmp != null) 
                                        (document.getElementById("numberField") as HTMLInputElement).valueAsNumber = Number(tmp);
                                    else
                                        return;
                                }

                                move = this.moveLoad();
                                writerToOutput(this.CaesarCipher(inputLoad().split(""), move));
                            }}
                        >Caesar GO!</Button>
                    </Container>
                </Grid>

                <Box my={5} boxShadow={3}>
                    <Table className="table">
                        <TableHead>
                            <TableRow>
                                {tableCellsAlphabet}
                            </TableRow>
                        </TableHead>
                        <TableBody>
                            <TableRow>
                                {tableCellsMovedAlphabet}
                            </TableRow>
                        </TableBody>
                    </Table>
                </Box>

                <Box marginTop={10}>
                    <ExpansionPanel>
                        <ExpansionPanelSummary
                            id="aboutCaesarCipher"
                            expandIcon={<ExpandMoreIcon />}
                        >
                            <Typography
                                color="secondary"
                                className='heading'
                            ><b>ABOUT Caesar Cipher</b></Typography>
                        </ExpansionPanelSummary>
                        <ExpansionPanelDetails>
                            <Grid container className='columnGrid'>
                                <Typography style={{color: '#808080'}} align='left' component={"div"}>
                                    <p>
                                        <b>Caesar Cipher</b> is simple <i>monoalphabetic substitution cipher</i>. 
                                    </p>
                                    <p>
                                        Caesar cipher uses as substitution alphabet derived by a number of positions "movement" in the primarly used alphabet. 
                                        This movement can be seen in the table above. The "true" Caesar cipher uses movement key equal to 3.
                                    </p>
                                </Typography>

                                <Grid container className='columnGrid'>
                                    <img
                                        src="http://www.stud.feec.vutbr.cz/~xrysav29/cipher_pics/caesar_encryption.PNG"
                                        alt="Caesar encryption"
                                        width="60%"/>
                                </Grid>
                                <Typography variant='caption' style={{ color: '#808080' }} align='center'>
                                    <b>Img 1.:</b> <i>Encryption of plaintext using Caesar cipher.</i>
                                </Typography>
                            </Grid>
                        </ExpansionPanelDetails>
                    </ExpansionPanel>
                </Box>
            </div >
        );
    }
}