/**
 * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
 *
 * @author Alexander Rose <alexander.rose@weirdbyte.de>
 */

import * as React from 'react'
import { StructureRepresentation, StructureProps } from 'mol-geo/representation/structure';
import Viewer from 'mol-view/viewer';
import { VisualQuality, VisualQualityNames } from 'mol-geo/representation/util';
import { ColorThemeProps, ColorThemeName, ColorThemeNames, ColorTheme } from 'mol-view/theme/color';
import { Color } from 'mol-util/color';
import { Progress } from 'mol-task';

export interface StructureRepresentationComponentProps {
    viewer: Viewer
    representation: StructureRepresentation<StructureProps>
}

export interface StructureRepresentationComponentState {
    label: string
    visible: boolean
    alpha: number
    quality: VisualQuality
    colorTheme: ColorThemeProps

    flatShaded?: boolean
    resolutionFactor?: number
    probeRadius?: number
    isoValue?: number
}

export class StructureRepresentationComponent extends React.Component<StructureRepresentationComponentProps, StructureRepresentationComponentState> {
    state = {
        label: this.props.representation.label,
        visible: this.props.representation.props.visible,
        alpha: this.props.representation.props.alpha,
        quality: this.props.representation.props.quality,
        colorTheme: this.props.representation.props.colorTheme,

        flatShaded: (this.props.representation.props as any).flatShaded,
        resolutionFactor: (this.props.representation.props as any).resolutionFactor,
        probeRadius: (this.props.representation.props as any).probeRadius,
        isoValue: (this.props.representation.props as any).isoValue,
    }

    componentWillMount() {
        const repr = this.props.representation

        this.setState({
            ...this.state,
            label: repr.label,
            visible: repr.props.visible,
            alpha: repr.props.alpha,
            quality: repr.props.quality,
            colorTheme: repr.props.colorTheme,

            flatShaded: (repr.props as any).flatShaded,
            resolutionFactor: (repr.props as any).resolutionFactor,
            probeRadius: (repr.props as any).probeRadius,
            isoValue: (repr.props as any).isoValue,
        })
    }

    async update(state: Partial<StructureRepresentationComponentState>) {
        const repr = this.props.representation
        const props: Partial<StructureProps> = {}

        if (state.visible !== undefined) props.visible = state.visible
        if (state.quality !== undefined) props.quality = state.quality
        if (state.alpha !== undefined) props.alpha = state.alpha
        if (state.colorTheme !== undefined) props.colorTheme = state.colorTheme

        if (state.flatShaded !== undefined) (props as any).flatShaded = state.flatShaded
        if (state.resolutionFactor !== undefined) (props as any).resolutionFactor = state.resolutionFactor
        if (state.probeRadius !== undefined) (props as any).probeRadius = state.probeRadius
        if (state.isoValue !== undefined) (props as any).isoValue = state.isoValue

        await repr.createOrUpdate(props).run(
            progress => console.log(Progress.format(progress))
        )
        this.props.viewer.add(repr)
        this.props.viewer.draw(true)
        console.log(this.props.viewer.stats)

        console.log(
            'drawCount',
            repr.renderObjects[0].values.drawCount.ref.version,
            repr.renderObjects[0].values.drawCount.ref.value,
            'dColorType',
            repr.renderObjects[0].values.dColorType.ref.version,
            repr.renderObjects[0].values.dColorType.ref.value
        )

        const newState = {
            ...this.state,
            visible: repr.props.visible,
            quality: repr.props.quality,
            alpha: repr.props.alpha,
            colorTheme: repr.props.colorTheme,

            flatShaded: (repr.props as any).flatShaded,
            resolutionFactor: (repr.props as any).resolutionFactor,
            probeRadius: (repr.props as any).probeRadius,
            isoValue: (repr.props as any).isoValue,
        }
        this.setState(newState)
    }

    render() {
        const { label, visible, quality, alpha, colorTheme } = this.state

        const ct = ColorTheme(colorTheme)

        if (ct.legend && ct.legend.kind === 'scale-legend') {
            // console.log(`linear-gradient(to right, ${ct.legend.colors.map(c => Color.toStyle(c)).join(', ')})`)
        }

        return <div>
            <div>
                <h4>{label}</h4>
            </div>
            <div>
                <div>
                    <span>Visible </span>
                    <button onClick={(e) => this.update({ visible: !visible }) }>
                        {visible ? 'Hide' : 'Show'}
                    </button>
                </div>
                { this.state.flatShaded !== undefined ? <div>
                    <span>Flat Shaded </span>
                    <button onClick={(e) => this.update({ flatShaded: !this.state.flatShaded }) }>
                        {this.state.flatShaded ? 'Deactivate' : 'Activate'}
                    </button>
                </div> : '' }
                <div>
                    <span>Quality </span>
                    <select value={quality} onChange={(e) => this.update({ quality: e.target.value as VisualQuality }) }>
                        {VisualQualityNames.map(name => <option key={name} value={name}>{name}</option>)}
                    </select>
                </div>
                <div>
                    <span>Opacity </span>
                    <input type='range'
                        defaultValue={alpha.toString()}
                        min='0'
                        max='1'
                        step='0.05'
                        onInput={(e) => this.update({ alpha: parseFloat(e.currentTarget.value) })}
                    >
                    </input>
                </div>
                { this.state.resolutionFactor !== undefined ? <div>
                    <span>Resolution Factor </span>
                    <input type='range'
                        defaultValue={this.state.resolutionFactor.toString()}
                        min='4'
                        max='9'
                        step='1'
                        onInput={(e) => this.update({ resolutionFactor: parseInt(e.currentTarget.value) })}
                    >
                    </input>
                </div> : '' }
                { this.state.isoValue !== undefined ? <div>
                    <span>Iso Value </span>
                    <input type='range'
                        defaultValue={this.state.isoValue.toString()}
                        min='0.1'
                        max='3'
                        step='0.1'
                        onInput={(e) => this.update({ isoValue: parseFloat(e.currentTarget.value) })}
                    >
                    </input>
                </div> : '' }
                { this.state.probeRadius !== undefined ? <div>
                    <span>Probe Radius </span>
                    <input type='range'
                        defaultValue={this.state.probeRadius.toString()}
                        min='0'
                        max='10'
                        step='0.1'
                        onInput={(e) => this.update({ probeRadius: parseFloat(e.currentTarget.value) })}
                    >
                    </input>
                </div> : '' }
                <div>
                    <span>Color Theme </span>
                    <select value={colorTheme.name} onChange={(e) => this.update({ colorTheme: { name: e.target.value as ColorThemeName } }) }>
                        {ColorThemeNames.map(name => <option key={name} value={name}>{name}</option>)}
                    </select>
                    {ct.description ? <div><i>{ct.description}</i></div> : ''}
                    {
                        ct.legend && ct.legend.kind === 'scale-legend'
                            ? <div
                                style={{
                                    width: '100%',
                                    height: '30px',
                                    background: `linear-gradient(to right, ${ct.legend.colors.map(c => Color.toStyle(c)).join(', ')})`
                                }}
                            >
                                <span style={{float: 'left', padding: '6px', color: 'white', fontWeight: 'bold', backgroundColor: 'rgba(0, 0, 0, 0.2)'}}>{ct.legend.min}</span>
                                <span style={{float: 'right', padding: '6px', color: 'white', fontWeight: 'bold', backgroundColor: 'rgba(0, 0, 0, 0.2)'}}>{ct.legend.max}</span>
                            </div>
                        : ct.legend && ct.legend.kind === 'table-legend'
                            ? <div>
                                {ct.legend.table.map((value, i) => {
                                    const [name, color] = value
                                    return <div key={i} style={{minWidth: '60px', marginRight: '5px', display: 'inline-block'}}>
                                        <div style={{width: '30px', height: '20px', backgroundColor: Color.toStyle(color), display: 'inline-block'}}></div>
                                        {name}
                                    </div>
                                })}
                            </div>
                        : ''
                    }
                </div>
            </div>
        </div>;
    }
}