content: /**
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you 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.
   */
  package com.alibaba.jstorm.ui.model;
  
  import backtype.storm.generated.ErrorInfo;
  import backtype.storm.generated.MetricSnapshot;
  import com.alibaba.jstorm.metric.MetricDef;
  import com.alibaba.jstorm.ui.utils.UIMetricUtils;
  import com.alibaba.jstorm.utils.JStormUtils;
  import com.fasterxml.jackson.annotation.JsonIgnore;
  import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
  import com.fasterxml.jackson.databind.annotation.JsonSerialize;
  
  import java.beans.Transient;
  import java.util.*;
  
  /**
   * @author Jark (wuchong.wc@alibaba-inc.com)
   */
  public class UIComponentMetric extends UIBasicMetric {
      protected String componentName;
      protected int parallel;
      protected String type;
      protected List<ErrorEntity> errors;
      protected String sortedKey;
  
      // <metricName, <parentCompName, value>>
      protected Map<String, Map<String, String>> subMetricMap = new HashMap<>();
      // <metricName@parentCompName, value>, this is used to iterate in jsp
      protected Map<String, String> subMetrics = new HashMap<>();
      protected Set<String> parentComponent;
  
      public static final String[] HEAD = {MetricDef.EMMITTED_NUM, MetricDef.ACKED_NUM, MetricDef.FAILED_NUM, MetricDef.SEND_TPS,
              MetricDef.RECV_TPS, MetricDef.PROCESS_LATENCY, MetricDef.DESERIALIZE_TIME, MetricDef.SERIALIZE_TIME,
              MetricDef.EXECUTE_TIME, MetricDef.COLLECTOR_EMIT_TIME, MetricDef.TUPLE_LIEF_CYCLE, MetricDef.ACKER_TIME};
  
      public UIComponentMetric(String componentName) {
          this.componentName = componentName;
      }
  
      public UIComponentMetric(String componentName, int parallel, String type) {
          this.componentName = componentName;
          this.parallel = parallel;
          this.type = type;
      }
  
      public void setMetricValue(MetricSnapshot snapshot, String parentComp, String metricName) {
          if (parentComp != null) {
              String value = UIMetricUtils.getMetricRawValue(snapshot);
              putSubMetricMap(metricName, parentComp, value);
          } else {
              String value = UIMetricUtils.getMetricValue(snapshot);
              setValue(metricName, value);
          }
      }
  
  
      public void mergeValue() {
          Set<String> set = new HashSet<>();
          for (Map.Entry<String, Map<String, String>> entry : subMetricMap.entrySet()) {
              String metricName = entry.getKey();
  //            String compName = entry.getKey().split("@")[1];
              if (getValue(metricName) == null) {
                  // only when the value is not be set yet, we set the merged value
                  String value = merge(metricName, entry.getValue());
                  setValue(metricName, value);
              }
              //add all the component names to the set
              set.addAll(entry.getValue().keySet());
              // fill the subMetrics , format <metricName@parentCompName, value>
              for(Map.Entry<String, String> en : entry.getValue().entrySet()){
                  String compName = en.getKey();
                  String v = en.getValue();
                  String value;
                  if(v.contains(".")){
                      value = UIMetricUtils.format(JStormUtils.parseDouble(v));
                  }else{
                      value = UIMetricUtils.format(JStormUtils.parseLong(v));
                  }
                  subMetrics.put(metricName+"@"+compName, value);
              }
          }
          parentComponent = set;
      }
  
      protected String merge(String metricName, Map<String, String> list) {
          double value = 0d;
  
          if (metricName.equals(MetricDef.EMMITTED_NUM) || metricName.equals(MetricDef.ACKED_NUM)
                  || metricName.equals(MetricDef.FAILED_NUM)) {
              for (String s : list.values()) {
                  value += JStormUtils.parseDouble(s);
              }
              return UIMetricUtils.format((long) value);
          } else {
              for (String s : list.values()) {
                  value += JStormUtils.parseDouble(s);
              }
              if (list.size() > 0) value = value / list.size();
              return UIMetricUtils.format(value);
          }
      }
  
  
      public void putSubMetricMap(String metricName, String parentComp, String value) {
  //        String key = metricName + "@" + parentComp;
  //        subMetricMap.put(key, value);
          if (subMetricMap.containsKey(metricName)) {
              Map<String, String> map = subMetricMap.get(metricName);
              map.put(parentComp, value);
          } else {
              Map<String, String> map = new HashMap<>();
              map.put(parentComp, value);
              subMetricMap.put(metricName, map);
          }
      }
  
      public void setParallel(int parallel) {
          this.parallel = parallel;
      }
  
      public void setType(String type) {
          this.type = type;
      }
  
      public String getComponentName() {
          return componentName;
      }
  
      public int getParallel() {
          return parallel;
      }
  
      public String getType() {
          return type;
      }
  
  
      @JsonIgnore
      public Map<String, String> getSubMetrics() {
          return subMetrics;
      }
  
      @JsonIgnore
      public Set<String> getParentComponent() {
          return parentComponent;
      }
  
      public List<ErrorEntity> getErrors() {
          return errors;
      }
  
      public void setErrors(List<ErrorInfo> errors) {
          if (errors == null){
              this.errors = null;
              return;
          }
          this.errors = new ArrayList<>();
          for (ErrorInfo info : errors){
              ErrorEntity err = new ErrorEntity(info.get_errorTimeSecs(), info.get_error());
              this.errors.add(err);
          }
      }
  
      @JsonIgnore
      public String getSortedKey() {
          return sortedKey;
      }
  
      public void setSortedKey(String sortedKey) {
          this.sortedKey = sortedKey;
      }
  }
  