/// <reference path="../../includes.ts"/>
/// <reference path="../../kubernetes/ts/kubernetesHelpers.ts" />

module Developer {

  export var context = '/workspaces';
  export var hash = '#' + context;
  export var pluginName = 'Developer';
  export var pluginPath = 'plugins/developer/';
  export var templatePath = pluginPath + 'html/';
  export var log:Logging.Logger = Logger.get(pluginName);

  export var jenkinsServiceName = "jenkins";
  export var jenkinsServiceNameAndPort = jenkinsServiceName + ":http";

  export var jenkinsHttpConfig = {
    headers: {
      Accept: "application/json, text/x-json, text/plain"
    }
  };

  /**
   * Returns true if the value hasn't changed from the last cached JSON version of this object
   */
  export function hasObjectChanged(value, state) {
    var json = angular.toJson(value || "");
    var oldJson = state.json;
    state.json = json;
    return !oldJson || json !== oldJson;
  }

  export function projectForScope($scope) {
    if ($scope) {
      return $scope.buildConfig || $scope.entity || ($scope.model || {}).project;
    }
    return null;
  }
  /**
   * Lets load the project versions for the given namespace
   */
  export function loadProjectVersions($scope, $element, project, env, ns, answer, caches) {
    var projectAnnotation = "project";
    var versionAnnotation = "version";

    var projectNamespace = project.$namespace;
    var projectName = project.$name;

    var cache = caches[ns];
    if (!cache) {
      cache = {};
      caches[ns] = cache;
    }

    var status = {
      rcs: [],
      pods: [],
      routes: [],
      services: []
    };

    var imageStreamTags = [];

    function updateModel() {
      var projectInfos = {};
      var model = $scope.model || {};

      angular.forEach(status.rcs, (item) => {
        var metadata = item.metadata || {};
        var name = metadata.name;
        var labels = metadata.labels || {};
        var annotations = metadata.annotations || {};
        var spec = item.spec || {};
        var selector = spec.selector;

        var project = labels[projectAnnotation];
        var version = labels[versionAnnotation];

        // lets try the S2I defaults...
        if (!project) {
          project = labels["app"];
        }
        if (!version) {
          version = annotations["openshift.io/deployment-config.latest-version"]
        }
        if (project && version && project === projectName) {
          var projects = projectInfos[project];
          if (!projects) {
            projects = {
              project: project,
              versions: {}
            };
            projectInfos[project] = projects;
          }
          var versionInfo = projects.versions[version];
          if (!versionInfo) {
            versionInfo = {
              replicationControllers: {}
            };
            projects.versions[version] = versionInfo;
          }
          if (name) {
            versionInfo.replicationControllers[name] = item;
            item.$name = name;
            if (projectNamespace && projectName) {
              item.$viewLink = UrlHelpers.join("/workspaces/", projectNamespace, "projects", projectName, "namespace", ns, "replicationControllers", name);
            } else {
              log.warn("Missing project data! " + projectNamespace + " name " + projectName);
            }

            item.$services = [];
            var rcLink = null;
            status.services.forEach((service) => {
              var repSelector = Kubernetes.getSelector(item);
              var serviceSelector = Kubernetes.getSelector(service);
              if (serviceSelector && repSelector &&
                Kubernetes.selectorMatches(serviceSelector, repSelector) &&
                Kubernetes.getNamespace(service) === Kubernetes.getNamespace(item)) {
                status.routes.forEach((route) => {
                  var serviceName = Kubernetes.getName(service);
                  if (serviceName === Kubernetes.getName(route)) {
                    service["$route"] = route;
                    service["$host"] = Core.pathGet(route, ["spec", "host"]);
                    item.$services.push(service);
                    if (!rcLink) {
                      var url = Kubernetes.serviceLinkUrl(service, true);
                      if (url) {
                        // TODO find icon etc?
                        rcLink = {
                          name: serviceName,
                          href: url
                        };
                      }
                    }
                  }
                });
              }
            });
            item["$serviceLink"] = rcLink;
          }
          item.$buildId = annotations["fabric8.io/build-id"] || item.$buildId;
          item.$buildUrl = annotations["fabric8.io/build-url"] || item.$buildUrl;
          item.$gitCommit = annotations["fabric8.io/git-commit"] || item.$gitCommit;
          item.$gitUrl = annotations["fabric8.io/git-url"] || item.$gitUrl;
          item.$gitBranch = annotations["fabric8.io/git-branch"] || item.$gitBranch;
          if (!item.$gitCommit) {
            var image = getImage(item);
            if (image) {
              if (!$scope.$isWatchImages) {
                $scope.$isWatchImages = true;
                Kubernetes.watch($scope, $element, "images", null, (data) => {
                  imageStreamTags = data;
                  checkForMissingMetadata();
                });
              } else {
                checkForMissingMetadata();
              }
            }

            function getImage(item) {
              var image = "";
              // lets see if we can find the commit id from a S2I image name
              // TODO needs this issue fixed to find it via an OpenShift annotation:
              // https://github.com/openshift/origin/issues/6241
              var containers = Core.pathGet(item, ["spec", "template", "spec", "containers"]);
              if (containers && containers.length) {
                var container = containers[0];
                if (container) {
                  image = container.image;
                }
              }
              return image;
            }

            function checkForMissingMetadata() {
              angular.forEach(projects.versions, (vi) => {
                angular.forEach(vi.replicationControllers, (item, name) => {
                  if (!item.$gitCommit) {
                    var image = getImage(item);
                    if (image) {
                      angular.forEach(imageStreamTags, (imageStreamTag) => {
                        var imageName = imageStreamTag.dockerImageReference;
                        if (imageName && imageName === image) {
                          var foundISTag = imageStreamTag;
                          var manifestJSON = imageStreamTag.dockerImageManifest;
                          if (manifestJSON) {
                            var manifest = angular.fromJson(manifestJSON) || {};
                            var history = manifest.history;
                            if (history && history.length) {
                              var v1 = history[0].v1Compatibility;
                              if (v1) {
                                var data = angular.fromJson(v1);
                                var env = Core.pathGet(data, ["config", "Env"]);
                                angular.forEach(env, (envExp) => {
                                  if (envExp) {
                                    var values = envExp.split("=");
                                    if (values.length === 2 && values[0] == "OPENSHIFT_BUILD_NAME") {
                                      var buildName = values[1];
                                      if (buildName) {
                                        item.$buildId = buildName;
                                        item.$buildUrl = Developer.projectWorkspaceLink(ns, projectName, "buildLogs/" + buildName);
                                      }
                                    }
                                  }
                                });
                                var labels = Core.pathGet(data, ["config", "Labels"]);
                                if (labels) {
                                  item.$gitCommit = labels["io.openshift.build.commit.id"] || item.$gitCommit;
                                  item.$gitCommitAuthor = labels["io.openshift.build.commit.author"] || item.$gitCommitAuthor;
                                  item.$gitCommitDate = labels["io.openshift.build.commit.date"] || item.$gitCommitDate;
                                  item.$gitCommitMessage = labels["io.openshift.build.commit.message"] || item.$gitCommitMessage;
                                  item.$gitBranch = labels["io.openshift.build.commit.ref"] || item.$gitBranch;

                                  if (!item.$gitUrl && item.$gitCommit) {
                                    item.$gitUrl = Developer.projectWorkspaceLink(ns, projectName, "wiki/commitDetail///" + item.$gitCommit);
                                  }
                                }
                              }
                            }
                          }
                        }
                      });
                    }
                  }
                });
              });
            }
          }

          if (selector) {
            var selectorText = Kubernetes.labelsToString(selector, ",");
            var podLinkUrl = UrlHelpers.join(projectLink(projectName), "namespace", ns, "pods");
            item.pods = [];
            item.$podCounters = Kubernetes.createPodCounters(selector, status.pods, item.pods, selectorText, podLinkUrl);
          }
        }
      });

      // lets check for a project name if we have lots of RCs with no pods, lets remove them!
      angular.forEach(projectInfos, (project, projectName) => {
        var rcsNoPods = [];
        var rcsWithPods = [];
        angular.forEach(project.versions, (versionInfo) => {
          var rcs = versionInfo.replicationControllers;
          angular.forEach(rcs, (item, name) => {
            var count = Kubernetes.podCounterTotal(item.$podCounters);
            if (count) {
              rcsWithPods.push(name);
            } else {
              rcsNoPods.push(() => {
                delete rcs[name];
              });
            }
          });
        });
        if (rcsWithPods.length) {
          // lets remove all the empty RCs
          angular.forEach(rcsNoPods, (fn) => {
            fn();
          });
        }
      });

      if (hasObjectChanged(projectInfos, cache)) {
        log.debug("project versions has changed!");
        answer[ns] = projectInfos;
      }
    }

    Kubernetes.watch($scope, $element, "replicationcontrollers", ns, (data) => {
      if (data) {
        status.rcs = data;
        updateModel();
      }
    });
    Kubernetes.watch($scope, $element, "services", ns, (data) => {
      if (data) {
        status.services = data;
        updateModel();
      }
    });
    Kubernetes.watch($scope, $element, "routes", ns, (data) => {
      if (data) {
        status.routes = data;
        updateModel();
      }
    });
    Kubernetes.watch($scope, $element, "pods", ns, (data) => {
      if (data) {
        status.pods = data;
        updateModel();
      }
    });
  }


}