/*
 * Copyright 2015-2018 Klarna Bank AB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

import React from 'react';
import { Tabs, Tab, FormGroup, InputGroup, FormControl, DropdownButton, MenuItem, Alert } from 'react-bootstrap';
import { Link } from 'react-router-dom';
import ReactDiff from './diff.js';
import ReactTable from './table.js';
import { fetchAPI } from './actions.js';
var $ = require('jquery');

export class AssetView extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            key: "data",
            power: "Unknown",
        };
    }
    handleSelect(key) {
        if (key === "back")
            this.props.history.goBack();
        else
            this.setState({key: key});
    }
    componentDidMount() {
        if (typeof this.asset !== "undefined")
            fetchAPI({url: "/asset/" + encodeURIComponent(this.asset.id) + "/ipmi/"})
              .then((power) => this.setState({power: power ? power['power_state'] : "Unknown"}));
    }
    render() {
        this.asset = this.props.assets.filter((asset) => { return asset.service_tag === this.props.match.params.service_tag; })[0];
        var extraProps = {
            asset: this.asset,
        };
        if (typeof this.asset === "undefined") {
            if (this.props.assets.length > 0)
                return (
                    <Alert bsStyle="danger">
                        <p>The asset with service tag {this.props.match.params.service_tag} was not found.</p>
                    </Alert>
                );
            else
                return (<div></div>);
        }
        else
            return (
                <Tabs id="asset_tabs" activeKey={this.state.key} onSelect={this.handleSelect.bind(this)}>
                    <Tab eventKey="back" title="&larr; Back"></Tab>
                    <Tab eventKey="data" title="Data">
                        <p>Service tag: {this.asset.service_tag}</p>
                        <p>Power state: {this.state.power}</p>
                        <p>only here for debug</p>
                        <pre>{JSON.stringify(this.asset, null, 2)}</pre>
                    </Tab>
                    <Tab eventKey="ipmi" title="Actions">
                        <div></div>
                        <div>
                            <AssetManagementLink {...this.props} {...extraProps}/>
                            <AssetWarranty {...this.props} {...extraProps}/>
                        </div>
                        <div></div>
                        <div><AssetPowerManagement {...this.props} {...extraProps}/></div>
                        <div></div>
                        <div><AssetMaintenance {...this.props} {...extraProps}/></div>
                        <div></div>
                        <div><AssetDelete {...this.props} {...extraProps}/></div>
                    </Tab>
                    <Tab eventKey="log" title="Log">
                        <h3>Log</h3>
                        <AssetHistory {...this.props} {...extraProps}/>
                    </Tab>
                    <Tab eventKey="events" title="Events">
                        <h3>Events</h3>
                        <AssetEvents {...this.props} {...extraProps}/>
                    </Tab>
                </Tabs>
            );
    }
}

class AssetManagementLink extends React.Component {
    render() {
        if (this.props.asset.asset_type === 'server')
            if (this.props.asset.hasOwnProperty('oob') && this.props.asset.hasOwnProperty('vendor') && this.props.asset.vendor === 'Dell Inc.')
                return (
                    <a href={'/gui/asset/' + encodeURIComponent(this.props.asset.service_tag) + '/console/'} className="btn btn-primary" role="button">Console</a>
                );
            else if (this.props.user.is_superuser || this.props.user.is_console_user)
                return (<a href={'/gui/asset/' + encodeURIComponent(this.props.asset.service_tag) + '/management/'} className="btn btn-primary" role="button">Management</a>);
            else
                return (<span/>);
        else if (this.props.asset.asset_type === 'vm' && this.props.asset.asset_subtype === 'libvirt')
            return (
                <a href={'/gui/asset/' + encodeURIComponent(this.props.asset.service_tag) + '/console/'} className="btn btn-primary" role="button">Console</a>
                );
        else
            return (<span/>);
    }
}

class AssetHistoryEntry extends React.Component {
    constructor(props) {
        super(props);
        this.state = {diff: false};
    }
    render() {
        var button_label = "Show diff";
        var diff = null;
        if (this.state.diff) {
            button_label = "Hide diff";
            var inputa = $.extend({}, this.props.prev_entry.object);
            var inputb = $.extend({}, this.props.entry.object);
            diff = (<ReactDiff before={inputa} after={inputb} />);
        }
        var button = (<button type="button" className="btn btn-primary" onClick={this.handleClick.bind(this)}>{button_label}</button>);
        return (
            <span>
                {this.props.entry.timestamp}: {this.props.entry.username} performed action {this.props.entry.message}<br />
                {button}<br />
                {diff}
            </span>
        );
    }
    handleClick() {
        this.setState({diff: !this.state.diff});
    }
}

class AssetHistory extends React.Component {
    constructor(props) {
        super(props);
        this.state = {log: []};
    }
    componentDidMount() {
        fetchAPI({url: "/asset/" + encodeURIComponent(this.props.asset.id) + "/history/"})
            .then((log) => {
                log.sort(function (a, b) {
                    var x = a['timestamp'];
                    var y = b['timestamp'];
                    return ((x > y) ? 1 : ((x < y) ? -1 : 0));
                });
                this.setState({log: log});
            });
    }
    render() {
        var logs = [];
        for (var i = 0; i < this.state.log.length; i++) {
            var entry = this.state.log[i];
            var prev_entry = this.state.log[i - 1];
            if (entry.username === null)
                entry.username = 'Socrates';
            logs.push(<li key={entry.id}><AssetHistoryEntry entry={entry} prev_entry={prev_entry} /></li>);
        }
        return (<ol>{logs}</ol>);
    }
}

class AssetPowerManagement extends React.Component {
    constructor(props) {
        super(props);
        this.state = {log: ""};
    }
    onChange(event) {
        this.setState({
            log: event.target.value,
        });
    }
    render() {
        if (this.props.asset.asset_type === 'server' || this.props.asset.asset_type === 'vm')
            return (
                <FormGroup>
                    <InputGroup>
                        <FormControl type="text" placeholder="Log message..." onChange={this.onChange.bind(this)} />
                        <DropdownButton componentClass={InputGroup.Button} id="asset_power_action" title="Action" bsStyle="warning">
                            <MenuItem key="1" onClick={this.powerOn.bind(this)}>Power on</MenuItem>
                            <MenuItem key="2" onClick={this.reboot.bind(this)}>Reboot</MenuItem>
                            <MenuItem key="3" onClick={this.rebootPXE.bind(this)}>Reboot to PXE</MenuItem>
                            <MenuItem key="4" onClick={this.powerOff.bind(this)}>Power off</MenuItem>
                        </DropdownButton>
                    </InputGroup>
                </FormGroup>
            );
        else
            return (<span/>);
    }
    sendIpmi(action) {
        if (this.state.log === "") {
            alert("Please fill out log");
            return;
        }
        fetchAPI({
            url: "/asset/" + encodeURIComponent(this.props.asset.service_tag) +
                 "/ipmi/",
            data: {log: this.state.log, action: action}
        }).then((data) => {
        });
    }
    powerOn() {
        return this.sendIpmi("poweron");
    }
    reboot() {
        return this.sendIpmi("reboot");
    }
    rebootPXE() {
        return this.sendIpmi("reboot_pxe");
    }
    powerOff() {
        return this.sendIpmi("shutdown");
    }
}

class AssetMaintenance extends React.Component {
    constructor(props) {
        super(props);
        this.state = {maintenance: false, log: ""};
    }
    componentDidMount() {
        this.setState({
            maintenance: this.props.asset.hasOwnProperty("maintenance") && this.props.asset.maintenance,
            log: "",
            version: this.props.asset.version,
        });
    }
    onChange(event) {
        this.setState({
            maintenance: this.state.maintenance,
            log: event.target.value,
            version: this.state.version,
        });
    }
    render() {
        if (this.state.maintenance)
            return (
                <div className="input-group">
                    <input type="text" className="form-control" placeholder="Log message..." onChange={this.onChange.bind(this)} />
                    <span className="input-group-btn">
                        <button className="btn btn-primary" onClick={this.unsetMaintenance.bind(this)}>Unset Maintenance</button>
                    </span>
                </div>
            );
        else
            return (
                <div className="input-group">
                    <input type="text" className="form-control" placeholder="Log message..." onChange={this.onChange.bind(this)} />
                    <span className="input-group-btn">
                        <button className="btn btn-primary" onClick={this.setMaintenance.bind(this)}>Set Maintenance</button>
                    </span>
                </div>
            );
    }
    registerMaintenance(maintenance) {
        if (this.state.log === "") {
            alert("Please fill out log");
            return;
        }
        fetchAPI({
            method: "PATCH",
            url: "/asset/" + encodeURIComponent(this.props.asset.service_tag),
            data: {maintenance: maintenance, log: this.state.log, version: this.state.version},
        }).then((data) => {
            this.setState({maintenance: maintenance, version: data.version});
        });
    }
    setMaintenance() {
        this.registerMaintenance(true);
    }
    unsetMaintenance() {
        this.registerMaintenance(false);
    }
}

class AssetWarranty extends React.Component {
    render() {
        if (this.props.asset.hasOwnProperty('vendor') && this.props.asset.vendor === "Dell Inc.") {
            return(
                <button className="btn btn-primary" onClick={this.updateWarranty.bind(this)}>Update warranty</button>
                  );
        } else {
            return(<span/>);
        }
    }
    updateWarranty() {
        fetchAPI({url: "/warrantylookup/" + encodeURIComponent(this.props.asset.service_tag)});
    }
}

class AssetEvents extends React.Component {
    constructor(props) {
        super(props);
        this.state = {events: []};
    }
    componentDidMount() {
        var url;
        url = "/event/feed/" + encodeURIComponent(this.props.asset.service_tag);
        fetchAPI({
            url: url,
        }).then((events) => {
            if (typeof events === "undefined")
                return;
            events.sort(function (a, b) {
                var x = a['timestamp'];
                var y = b['timestamp'];
                return ((x > y) ? 1 : ((x < y) ? -1 : 0));
            });
            this.setState({events: events});
        });
    }
    render() {
        var events = [];
        this.state.events.forEach(function (event) {
            events.push(<li key={event.id}>{event.timestamp}: {event.event}</li>);
        });
        return (<ol>{events}</ol>);
    }
}

class AssetDelete extends React.Component {
    constructor(props) {
        super(props);
        this.state = {log: ""};
    }
    onChange(event) {
        this.setState({
            log: event.target.value,
        });
    }
    render() {
        return (
            <div className="input-group">
                <input type="text" className="form-control" placeholder="Log message..." onChange={this.onChange.bind(this)} />
                <span className="input-group-btn">
                    <button className="btn btn-primary" onClick={this.deleteAsset.bind(this)}>Delete</button>
                </span>
            </div>
        );
    }
    deleteAsset(maintenance) {
        if (this.state.log === "") {
            alert("Please fill out log");
            return;
        }
        fetchAPI({
            method: "DELETE",
            url: "/asset/" + encodeURIComponent(this.props.asset.service_tag),
            data: {log: this.state.log},
        }).then((data) => {
            this.props.history.goBack();
        });
    }
}

export class AssetsView extends React.Component {
    onRowClick(row) {
        return "/gui/asset/" + encodeURIComponent(row.service_tag);
    }
    render() {
        return (
            <ReactTable columns={["service_tag", "owner", "state", "model", "provision.hostname"]}
                availableColumns={{
                    "service_tag": "Service tag",
                    "owner": "Owner",
                    "state": "State",
                    "model": "Model",
                    "provision.hostname": "Hostname",
                    "parent": "Parent",
                    "provision.os": "OS",
                    "provision.vlan.cidr": "VLAN",
                    "asset_type": "Type",
                }} data={this.props.assets} rowsPerPage={20} onRowClick={this.onRowClick} history={this.props.history} />
        );
    }
}

function range(start, stop, step) {
    var ret = [];
    for (var i = start; i !== stop; i += step)
        ret.push(i);
    return ret;
}

class Asset extends React.Component {
    render() {
        var label = this.props.asset.service_tag;
        if (this.props.asset.state === "in-use" && this.props.asset.hasOwnProperty("provision"))
            label = this.props.asset.provision.hostname;
        return (
            <div>
                <Link to={"/gui/asset/" + encodeURIComponent(this.props.asset.service_tag)} className="rackspace_label">{label}</Link>
            </div>
        );
    }
}

class Rack extends React.Component {
    render() {
        var assets = [];
        var positions = range(this.props.asset.positions, 0, -1);
        var filtered_assets = this.props.assets.filter((asset) => {
            return asset.parent === this.props.asset.service_tag;
        });
        for (var i = 0; i < positions.length; i++) {
            var position = positions[i];
            var columns = [React.createElement("th", {key: "th"}, "" + position)];
            for (var j = 0; j < filtered_assets.length; j++) {
                var asset = filtered_assets[j];
                var top_pos = Math.max.apply(null, asset.parent_position);
                var bottom_pos = Math.min.apply(null, asset.parent_position);
                if (position === top_pos) {
                    columns.push(
                        <td key={asset.service_tag} rowSpan={top_pos - bottom_pos + 1} className={"rackspace_asset rackspace_" + asset.asset_type}>
                            <Asset asset={asset} user={this.props.user} />
                        </td>
                    );
                }
            }
            assets.push(React.createElement("tr", {key: "" + position}, columns));
        }
        return (
            <table className="rackspace_rack">
                <caption><a name={this.props.asset.service_tag}>{this.props.asset.service_tag}</a></caption>
                <tbody>
                    {assets}
                </tbody>
            </table>
        );
    }
}

class Zone extends React.Component {
    render() {
        var assets = this.props.assets.filter((asset) => {
            return asset.parent === this.props.asset.service_tag &&
                asset.asset_type === 'rack';
        }).sort(function (a, b) {
            if (a.hasOwnProperty('parent_position') && b.hasOwnProperty('parent_position'))
                return Math.max.apply(null, b.parent_position) - Math.max.apply(null, a.parent_position);
            else
                return 0;
        }).map((asset) => {
            return (
                <Rack key={asset.service_tag} assets={this.props.assets} asset={asset} user={this.props.user} />
            );
        });
        return (
            <div>
                <h3><a name={this.props.asset.service_tag}>Zone {this.props.asset.service_tag}</a></h3>
                {assets}
            </div>
        );
    }
}

class Site extends React.Component {
    render() {
        var assets = this.props.assets.filter((asset) => {
            return asset.parent === this.props.asset.service_tag &&
                ['zone', 'rack'].indexOf(asset.asset_type) !== -1;
        }).sort(function (a, b) {
            if (a.hasOwnProperty('parent_position') && b.hasOwnProperty('parent_position'))
                return Math.max.apply(null, b.parent_position) - Math.max.apply(null, a.parent_position);
            else
                return 0;
        }).map((asset) => {
            if (asset.asset_type === 'zone')
                return (
                    <Zone key={asset.service_tag} assets={this.props.assets} asset={asset} user={this.props.user} />
                );
            else if (asset.asset_type === 'rack')
                return (
                    <Rack key={asset.service_tag} assets={this.props.assets} asset={asset} user={this.props.user} />
                );
            else
                return (<div></div>);
        });
        return (
            <div>
                <h3><a name={this.props.asset.service_tag}>Site {this.props.asset.service_tag}</a></h3>
                {assets}
            </div>
        );
    }
}

export class RackspaceView extends React.Component {
    render() {
        var assets = this.props.assets.filter(function(asset) {
            return !asset.parent && ['site', 'zone', 'rack'].indexOf(asset.asset_type) !== -1;
        }).sort(function (a, b) {
            if (a.hasOwnProperty('parent_position') && b.hasOwnProperty('parent_position'))
                return Math.max.apply(null, b.parent_position) - Math.max.apply(null, a.parent_position);
            else
                return 0;
        }).map(function(asset) {
            if (asset.asset_type === 'site')
                return (
                    <Site key={asset.service_tag} assets={this.props.assets} asset={asset} user={this.props.user} />
                );
            else if (asset.asset_type === 'zone')
                return (
                    <Zone key={asset.service_tag} assets={this.props.assets} asset={asset} user={this.props.user} />
                );
            else if (asset.asset_type === 'rack')
                return (
                    <Rack key={asset.service_tag} assets={this.props.assets} asset={asset} user={this.props.user} />
                );
            else
                return (<div></div>);
        }.bind(this));
        return (
            <div>
                <h2>Rackspace</h2>
                {assets}
            </div>
        );
    }
}
