// CollectMetrics returns filled mts table with metric values. Limits and quotas
// are colllected once per tenant. All hypervisor related statistics are collected
// in one call. This method also performs lazy initalization of plugin. Error
// is returned if initalization or any of required call failed.
func (self *NovaPlugin) CollectMetrics(mts []plugin.MetricType) ([]plugin.MetricType, error) {
	if len(mts) > 0 {
		err := self.init(mts[0])

		if err != nil {
			return nil, err
		}

	} else {
		return mts, nil
	}

	t := time.Now()

	limitsFor := map[string]bool{}
	quotasFor := map[string]bool{}
	hypervisors := false
	cluster := false

	results := make([]plugin.MetricType, len(mts))
	for _, mt := range mts {
		id, group, subgroup, _ := parseName(mt.Namespace().Strings())
		if group == GROUP_CLUSTER {
			cluster = true
			continue
		}
		if group == GROUP_HYPERVISOR {
			hypervisors = true
		} else {
			if subgroup == SUBGROUP_LIMITS {
				limitsFor[id] = true
			} else {
				quotasFor[id] = true
			}
		}
	}

	cachedLimits := map[string]map[string]interface{}{}
	for tenant, _ := range limitsFor {
		limits, err := self.collector.GetLimits(tenant)
		if err != nil {
			return nil, fmt.Errorf("cannot read limits for %v: (%v)", tenant, err)
		}
		cachedLimits[tenant] = limits
	}

	cachedQuotas := map[string]map[string]interface{}{}
	var tenantIds map[string]string = nil
	for tenant, _ := range quotasFor {
		if tenantIds == nil {
			tenantIds2, err := self.collector.GetTenants()
			if err != nil {
				return nil, fmt.Errorf("cannot get tenants list: (%v)", err)
			}
			tenantIds = tenantIds2
		}

		quotas, err := self.collector.GetQuotas(tenant, tenantIds[tenant])
		if err != nil {
			return nil, fmt.Errorf("cannot read quotas for %v: (%v)", tenant, err)
		}
		cachedQuotas[tenant] = quotas
	}

	cachedHypervisor := map[string]map[string]interface{}{}
	if hypervisors {
		hStats, err := self.collector.GetHypervisors()
		if err != nil {
			return nil, fmt.Errorf("cannot read hypervisors: (%v)", err)
		}
		cachedHypervisor = hStats
	}

	cachedClusterConfig := map[string]interface{}{}
	if cluster {
		cachedClusterConfig = self.collector.GetClusterConfig()
	}

	for i, mt := range mts {
		id, group, subgroup, metric := parseName(mt.Namespace().Strings())
		mt := plugin.MetricType{
			Namespace_: mt.Namespace(),
			Timestamp_: t,
		}
		if group == GROUP_CLUSTER && id == ID_CONFIG {
			mt.Data_ = cachedClusterConfig[metric]

		} else {
			if group == GROUP_HYPERVISOR {
				mt.Data_ = cachedHypervisor[id][metric]
			} else {
				if subgroup == SUBGROUP_LIMITS {
					mt.Data_ = cachedLimits[id][metric]
				} else {
					mt.Data_ = cachedQuotas[id][metric]
				}
			}
		}
		results[i] = mt
	}

	return results, nil
}
func gathermts(host string, filter []string) ([]plugin.MetricType, error) {
	resp, err := http.Get(fmt.Sprintf("%s/metrics", host))
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		return nil, errReqFailed
	}

	mtsmap := make(map[string]plugin.MetricType)
	scanner := bufio.NewScanner(resp.Body)

	if err != nil {
		return nil, err
	}

	for scanner.Scan() {
		txt := scanner.Text()
		if !strings.Contains(txt, "{") && !strings.Contains(txt, "#") {
			nsslice := strings.Split(txt, " ")
			mtsmap[nsslice[0]] = plugin.MetricType{
				Namespace_: core.NewNamespace("intel", "etcd", nsslice[0]),
				Data_:      nsslice[1],
				Timestamp_: time.Now(),
			}
		}
	}

	// No filter given; this was a GetMetricTypes call.
	if len(filter) == 0 {
		mts := make([]plugin.MetricType, 0, len(mtsmap)+len(derivatives))
		for _, v := range mtsmap {
			mts = append(mts, v)
		}
		for k := range derivatives {
			mts = append(mts, plugin.MetricType{Namespace_: core.NewNamespace("intel", "etcd", "derivative", k)})
		}
		return mts, nil
	}

	// Walk through filter and pluck out metrics.
	// if we find the requested metric in derivatives,
	// then derive the value from `from`.
	mts := make([]plugin.MetricType, 0, len(filter))
	for _, f := range filter {
		from, ok := derivatives[f]
		if ok {
			mt := plugin.MetricType{
				Namespace_: core.NewNamespace("intel", "etcd", "derivative", f),
				Timestamp_: time.Now(),
			}
			sum, err := strconv.ParseFloat(mtsmap[from[0]].Data_.(string), 64)
			if err != nil {
				return nil, err
			}
			count, err := strconv.ParseFloat(mtsmap[from[1]].Data_.(string), 64)
			if err != nil {
				return nil, err
			}
			mt.Data_ = sum / count
			mts = append(mts, mt)
			continue
		}

		mt, ok := mtsmap[f]
		if ok {
			mts = append(mts, mt)
		}
	}
	return mts, nil
}