/*
 * This file is part of Cockpit.
 *
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * Cockpit is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * Cockpit is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
 */

(function() {
    var angular = require('angular');
    require('angular-route');
    require('kubernetes-topology-graph/dist/topology-graph.js');

    require('./kube-client');
    require('./details');

    require('../views/topology-page.html');

    var icons = {
        Pod: '#vertex-Pod',
        ReplicationController: '#vertex-ReplicationController',
        Node: '#vertex-Node',
        Service: '#vertex-Service',
        DeploymentConfig: "#vertex-DeploymentConfig",
        Route: "#vertex-Route"
    };

    angular.module('kubernetes.topology', [
        'ngRoute',
        'kubernetesUI',
        'kubeClient',
        'kubernetes.details'
    ])

            .config(['$routeProvider',
                function($routeProvider) {
                    $routeProvider.when('/topology/:namespace?', {
                        templateUrl: 'views/topology-page.html',
                        controller: 'TopologyCtrl'
                    });
                }
            ])

            .controller('TopologyCtrl', [
                '$scope',
                '$window',
                'kubeLoader',
                'kubeSelect',
                'KubeDiscoverSettings',
                'itemActions',
                function($scope, $window, loader, select, discoverSettings, actions) {
                    $scope.items = { };
                    $scope.relations = [ ];
                    $scope.selected = null;

                    var ready = false;

                    function link_for_item(kind, namespace, name) {
                        var rel = select().kind(kind)
                                .name(name)
                                .namespace(namespace)
                                .one();
                        if (rel)
                            return rel.metadata.selfLink;
                    }

                    function rels_for_item(item) {
                        var rels = { };
                        var endpoints, subsets;
                        var link;

                        /* Lookup which node this pod is scheduled on */
                        if (item.kind === "Node") {
                            rels = select().kind("Pod")
                                    .host(item.metadata.name);

                            /* Kubernetes tells us about endpoints, which are service to pod mappings */
                        } else if (item.kind === "Service") {
                            endpoints = select().kind("Endpoints")
                                    .namespace(item.metadata.namespace)
                                    .name(item.metadata.name)
                                    .one() || { };
                            subsets = endpoints.subsets || [ ];
                            subsets.forEach(function(subset) {
                                var addresses = subset.addresses || [ ];
                                addresses.forEach(function(address) {
                                    if (address.targetRef && address.targetRef.kind == "Pod")
                                        link = link_for_item("Pod", address.targetRef.namespace,
                                                             address.targetRef.name);
                                    if (link)
                                        rels[link] = {};
                                });
                            });

                            /* For ReplicationControllers we just do the selection ourselves */
                        } else if (item.kind === "ReplicationController") {
                            rels = select().kind("Pod")
                                    .namespace(item.metadata.namespace);
                            if (item.spec.selector)
                                rels = rels.label(item.spec.selector);
                        } else if (item.kind === "DeploymentConfig") {
                            rels = select().kind("ReplicationController")
                                    .namespace(item.metadata.namespace)
                                    .label({ "openshift.io/deployment-config.name" : item.metadata.name });
                            /* For Routes just build it out */
                        } else if (item.kind === "Route" && item.spec.to) {
                            link = link_for_item(item.spec.to.kind, item.metadata.namespace,
                                                 item.spec.to.name);
                            if (link)
                                rels[link] = {};
                        }
                        return rels;
                    }

                    loader.watch("Node", $scope);
                    loader.watch("Pod", $scope);
                    loader.watch("ReplicationController", $scope);
                    loader.watch("Service", $scope);
                    loader.watch("Endpoints", $scope);

                    discoverSettings().then(function(settings) {
                        if (settings.flavor === "openshift") {
                            loader.watch("DeploymentConfig", $scope);
                            loader.watch("Route", $scope);
                        }
                    });

                    loader.listen(function(changed, removed) {
                        var selected_meta;
                        var relations = [];
                        var item;
                        var key;

                        $scope.items = select();
                        if ($scope.selected) {
                            selected_meta = $scope.selected.metadata || {};
                            item = select().kind($scope.selected.kind)
                                    .name(selected_meta.name);
                            if (selected_meta.namespace)
                                item = item.namespace(selected_meta.namespace);
                            $scope.selected = item.one();
                        }

                        for (key in $scope.items) {
                            var pkey;
                            var rels = rels_for_item($scope.items[key]);
                            for (pkey in rels)
                                relations.push({ source: key, target: pkey });
                        }

                        $scope.relations = relations;
                    }, $scope);

                    $scope.$on("select", function(ev, item) {
                        $scope.$applyAsync(function () {
                            $scope.selected = item;
                        });
                    });

                    /* Make a copy since we modify */
                    $scope.kinds = angular.copy(icons);

                    /* All the actions available on the $scope */
                    angular.extend($scope, actions);

                    function resized() {
                        $scope.height = { height: (window.innerHeight - 60) + "px" };
                        if (ready)
                            $scope.$digest();
                    }

                    angular.element($window).bind('resize', resized);
                    resized();

                    ready = true;
                }
            ]);
}());
