
/*
 * 
 *   Copyright 2016 RIFT.IO Inc
 *
 *   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.
 *
 */
import React from 'react';
import d3 from 'd3';
import DashboardCard from '../dashboard_card/dashboard_card.jsx';

export default class TopologyL2Graph extends React.Component {
    constructor(props) {
        super(props);
        this.data = props.data;
        this.selectedID = 0;
        this.nodeCount = 0;
        this.network_coding = {}
        this.nodeEvent = props.nodeEvent || null;
    }
    componentDidMount(){
        var weight = 400;
        var handler = this;
        this.force = d3.layout.force()
            .size([this.props.width, this.props.height])
            .charge(-weight)
            .linkDistance(weight)
            .on("tick", this.tick.bind(this));

        this.drag = this.force.drag()
            .on("dragstart", function(d) {
                handler.dragstart(d, handler);
            });

    }
    componentWillUnmount() {
        d3.select('svg').remove();
    }
    componentWillReceiveProps(props) {
        if(!this.svg) {
            // NOTE: We may need to revisit how D3 accesses DOM elements
             this.svg = d3.select(document.querySelector('#topologyL2')).append("svg")
            .attr("width", this.props.width)
            .attr("height", this.props.height)
            .classed("topology", true);
        }

        if (props.data.links.length > 0) {
            this.network_coding = this.create_group_coding(props.data.network_ids.sort());
            this.update(props.data);
        }
    }

    create_group_coding(group_ids) {
        var group_coding = {};
        group_ids.forEach(function(element, index, array) {
            group_coding[element] = index+1;
        });
        return group_coding;
    }
    getNetworkCoding(network_id) {
        var group = this.network_coding[network_id];
        if (group != undefined) {
            return group;
        } else {
            return 0;
        }
    }

    drawLegend(graph) {
        // Hack to prevent multiple legends being displayed
        this.svg.selectAll(".legend").remove();

        var showBox = false;
        var svg = this.svg;
        var item_count = (graph.network_ids) ? graph.network_ids.length : 0;
        var pos = {
            anchorX: 5,
            anchorY: 5,
            height: 40,
            width: 200,
            items_y: 35,
            items_x: 7,
            item_height: 25
        };
        pos.height += item_count * pos.item_height;
        var legend_translate = "translate("+pos.anchorX+","+pos.anchorY+")";

        var legend = svg.append("g")
            .attr("class", "legend")
            .attr("transform", legend_translate);

        var legend_box = (showBox) ? legend.append("rect")
                .attr("x", 0)
                .attr("y", 0)
                .attr("height", pos.height)
                .attr("width", pos.width)
                .style("stroke", "black")
                .style("fill", "none") : null;

        legend.append("text")
            .attr("x", 5)
            .attr("y", 15)
            .text("Network color mapping:");

        legend.selectAll("g").data(graph.network_ids)
            .enter()
            .append("g")
            .each(function(d, i) {
                var colors = ["green", "orange", "red" ];
                var g = d3.select(this);
                var group_number = i+1;
                g.attr('class', "node-group-" + group_number);

                g.append("circle")
                    .attr("cx", pos.items_x + 3)
                    .attr("cy", pos.items_y + i * pos.item_height)
                    .attr("r", 6);

                g.append("text")
                    .attr("x", pos.items_x + 25)
                    .attr("y", pos.items_y + (i * pos.item_height + 4))
                    .attr("height", 20)
                    .attr("width", 80)
                    .text(d);
            })
    }

    update(graph) {
        var svg = this.svg;
        var handler = this;
        this.force
            .nodes(graph.nodes)
            .links(graph.links)
            .start();

        this.link = svg.selectAll(".link")
            .data(graph.links)
            .enter().append("line")
                .attr("class", "link");

        this.gnodes = svg.selectAll('g.gnode')
            .data(graph.nodes)
            .enter()
            .append('g')
            .classed('gnode', true)
            .attr('data-network', function(d) { return d.network; })
            .attr('class', function(d) {
                return d3.select(this).attr('class') + ' node-group-'+ handler.getNetworkCoding(d.network);
            });

        this.node = this.gnodes.append("circle")
            .attr("class", "node")
            .attr("r", this.props.radius)
            .on("dblclick", function(d) {
                handler.dblclick(d, handler)
            })
            .call(this.drag)
            .on('click', function(d) {
                handler.click.call(this, d, handler)
            });
        var labels = this.gnodes.append("text")
            .attr("text-anchor", "middle")
            .attr("fill", "black")
            .attr("font-size", "12")
            .attr("y", "-10")
            .text(function(d) { return d.name; });
        this.drawLegend(graph);
    }

    tick = () => {
        this.link.attr("x1", function(d) { return d.source.x; })
               .attr("y1", function(d) { return d.source.y; })
               .attr("x2", function(d) { return d.target.x; })
               .attr("y2", function(d) { return d.target.y; });

        this.gnodes.attr("transform", function(d) {
            return 'translate(' + [d.x, d.y] + ')';
        });

    }

    click(d, topo) {
        console.log("TopologyL2Graph.click called");
        // 'This' is the svg circle element
        var gnode = d3.select(this.parentNode);

        topo.svg.selectAll("text").transition()
            .duration(topo.props.nodeText.transitionTime)
            .attr("font-size", topo.props.nodeText.size)
            .attr("fill", topo.props.nodeText.color)

        // Set focus node text properties
        d3.select(this.parentNode).selectAll('text').transition()
            .duration(topo.props.nodeText.transitionTime)
            .attr("font-size", topo.props.nodeText.focus.size)
            .attr("fill", topo.props.nodeText.focus.color);

        // Perform detail view
        topo.selectedID = d.id;
        if (topo.nodeEvent) {
            topo.nodeEvent(d.id);
        }
        // set record view as listener
    }

    dblclick(d, topo) {
        this.d3.select(this).classed("fixed", d.fixed = false);
    }

    dragstart(d) {
        //d3.select(this).classed("fixed", d.fixed = true);
    }

    render() {
        return ( <DashboardCard showHeader={true} title="Topology L2 Graph">
                <div id="topologyL2"></div>
                </DashboardCard>)
    }
}

TopologyL2Graph.defaultProps = {
    width: 700,
    height: 500,
    maxLabel: 150,
    duration: 500,
    radius: 6,
    data: {
        nodes: [],
        links: [],
        network_ids: []
    },
    nodeText: {
        size: 12,
        color: 'black',
        focus: {
            size: 14,
            color: 'blue'
        },
        transitionTime: 250
    }
}
