/**
 * 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 { StructureView } from '../structure-view';
import { StructureRepresentation } from 'mol-geo/representation/structure';
import { RepresentationComponent } from './representation';
import { Representation } from 'mol-geo/representation';

export interface StructureViewComponentProps {
    structureView: StructureView
}

export interface StructureViewComponentState {
    structureView: StructureView

    label: string
    modelId: number
    modelIds: { id: number, label: string }[]
    assemblyId: string
    assemblyIds: { id: string, label: string }[]
    symmetryFeatureId: number
    symmetryFeatureIds: { id: number, label: string }[]

    active: { [k: string]: boolean }
    structureRepresentations: { [k: string]: StructureRepresentation<any> }
}

export class StructureViewComponent extends React.Component<StructureViewComponentProps, StructureViewComponentState> {
    state = this.stateFromStructureView(this.props.structureView)

    private stateFromStructureView(sv: StructureView) {
        return {
            structureView: sv,

            label: sv.label,
            modelId: sv.modelId,
            modelIds: sv.getModelIds(),
            assemblyId: sv.assemblyId,
            assemblyIds: sv.getAssemblyIds(),
            symmetryFeatureId: sv.symmetryFeatureId,
            symmetryFeatureIds: sv.getSymmetryFeatureIds(),

            active: sv.active,
            structureRepresentations: sv.structureRepresentations
        }
    }

    componentWillMount() {
        this.setState(this.stateFromStructureView(this.props.structureView))
    }

    componentDidMount() {
        const sv = this.props.structureView

        this.props.structureView.updated.subscribe(() => this.setState({
            symmetryFeatureIds: sv.getSymmetryFeatureIds(),
            structureRepresentations: sv.structureRepresentations
        }))
    }

    componentWillReceiveProps(nextProps: StructureViewComponentProps) {
        if (nextProps.structureView !== this.props.structureView) {
            this.setState(this.stateFromStructureView(nextProps.structureView))

            nextProps.structureView.updated.subscribe(() => this.setState({
                symmetryFeatureIds: nextProps.structureView.getSymmetryFeatureIds(),
                structureRepresentations: nextProps.structureView.structureRepresentations
            }))
        }
    }

    async update(state: Partial<StructureViewComponentState>) {
        const sv = this.state.structureView

        if (state.modelId !== undefined) await sv.setModel(state.modelId)
        if (state.assemblyId !== undefined) await sv.setAssembly(state.assemblyId)
        if (state.symmetryFeatureId !== undefined) await sv.setSymmetryFeature(state.symmetryFeatureId)

        this.setState(this.stateFromStructureView(sv))
    }

    render() {
        const { structureView, label, modelIds, assemblyIds, symmetryFeatureIds, active, structureRepresentations } = this.state

        const modelIdOptions = modelIds.map(m => {
            return <option key={m.id} value={m.id}>{m.label}</option>
        })
        const assemblyIdOptions = assemblyIds.map(a => {
            return <option key={a.id} value={a.id}>{a.label}</option>
        })
        const symmetryFeatureIdOptions = symmetryFeatureIds.map(f => {
            return <option key={f.id} value={f.id}>{f.label}</option>
        })

        return <div>
            <div>
                <h2>{label}</h2>
            </div>
            <div>
                <div>
                    <span>Model </span>
                    <select
                        style={{width: '100px'}}
                        value={this.state.modelId}
                        onChange={(e) => {
                            this.update({ modelId: parseInt(e.target.value) })
                        }}
                    >
                        {modelIdOptions}
                    </select>
                    <span> </span>
                    <input type='range'
                        defaultValue={this.state.modelId.toString()}
                        min={Math.min(...modelIds.map(m => m.id))}
                        max={Math.max(...modelIds.map(m => m.id))}
                        step='1'
                        onInput={(e) => {
                            this.update({ modelId: parseInt(e.currentTarget.value) })
                        }}
                    >
                    </input>
                </div>
                <div>
                    <span>Assembly </span>
                    <select
                        style={{width: '150px'}}
                        value={this.state.assemblyId}
                        onChange={(e) => {
                            this.update({ assemblyId: e.target.value })
                        }}
                    >
                        {assemblyIdOptions}
                    </select>
                </div>
                <div>
                    <span>Symmetry Feature </span>
                    <select
                        style={{width: '150px'}}
                        value={this.state.symmetryFeatureId}
                        onChange={(e) => {
                            this.update({ symmetryFeatureId: parseInt(e.target.value) })
                        }}
                    >
                        {symmetryFeatureIdOptions}
                    </select>
                </div>
                <div>
                    <h4>Active</h4>
                    { Object.keys(active).map((k, i) => {
                        return <div key={i}>
                            <input
                                type='checkbox'
                                checked={active[k]}
                                onChange={(e) => {
                                    const sv = structureView
                                    if (k === 'symmetryAxes') {
                                        sv.setSymmetryAxes(e.target.checked)
                                    } else if (Object.keys(sv.structureRepresentations).includes(k)) {
                                        sv.setStructureRepresentation(k, e.target.checked)
                                    }
                                }}
                            /> {k}
                        </div>
                    } ) }
                </div>
                <div>
                    <h3>Structure Representations</h3>
                    { Object.keys(structureRepresentations).map((k, i) => {
                        if (active[k]) {
                            return <div key={i}>
                                <RepresentationComponent
                                    repr={structureRepresentations[k] as Representation<any>}
                                    viewer={structureView.viewer}
                                    app={structureView.app}
                                />
                            </div>
                        } else {
                            return ''
                        }
                    } ) }
                </div>
            </div>
        </div>;
    }
}