// Copyright 2016 Google Inc. All Rights Reserved.
//
// 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.

package csv

// events.go processes the CSV generated by csv.go, and creates a map from metric to events.

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/google/battery-historian/checkinutil"
)

// Event stores the details contained in a CSV line.
type Event struct {
	Type       string
	Start, End int64
	Value      string
	Opt        string
}

// ExtractEvents returns all events matching any of the given metrics names.
// If a metric has no matching events, the map will contain a nil slice for that metric.
// Errors encountered during parsing will be collected into an errors slice and will continue parsing remaining events.
func ExtractEvents(csvInput string, metrics []string) (map[string][]Event, []error) {
	records := checkinutil.ParseCSV(csvInput)
	if records == nil {
		return nil, []error{errors.New("nil result generated by ParseCSV")}
	}
	events := make(map[string][]Event, len(metrics))
	// Only store metrics requested.
	for _, m := range metrics {
		events[m] = nil
	}

	var errs []error
	for i, parts := range records {
		if len(parts) == 0 {
			continue
		}
		desc := parts[0]
		metricEvents, ok := events[desc]
		if !ok {
			// Ignore non matching metrics.
			continue
		}
		e, err := eventFromRecord(parts)
		if err != nil {
			errs = append(errs, fmt.Errorf("record %v: %v", i, err))
			continue
		}
		events[desc] = append(metricEvents, e)
	}
	return events, errs
}

// eventFromRecord parses the parts and either returns an event if in the correct format, else an error.
// Parts expected are desc,metricType,start,end,value,opt.
func eventFromRecord(parts []string) (Event, error) {
	if len(parts) != 6 {
		return Event{}, fmt.Errorf("non matching %v, len was %v", parts, len(parts))
	}
	start, err := strconv.ParseInt(parts[2], 10, 64)
	if err != nil {
		return Event{}, err
	}
	end, err := strconv.ParseInt(parts[3], 10, 64)
	if err != nil {
		return Event{}, err
	}
	return Event{
		Type:  parts[1],
		Start: start,
		End:   end,
		Value: parts[4],
		Opt:   parts[5],
	}, nil
}
