/*
 * Copyright 2018-present Open Networking Foundation

 * 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.
 */
// The template for the tester.
// This template is filled in by the
// test driver based on the configuration.

package main

import (
	"os"
	"fmt"
	//slog "log"
	"io/ioutil"
	"encoding/json"
	//"google.golang.org/grpc/grpclog"
	"github.com/opencord/voltha-go/common/log"
)

type TestCase struct {
	Title string `json:"title"`
	Result bool `json:"passed"`
	Info []string `json:"info"`
}

type TestSuite struct {
	Name string `json:"name"`
	Info []string `json:"info"`
	TestCases []TestCase `json:"testCases"`
}

type TestRun struct {
	TestSuites []TestSuite
}

func (tr * TestRun) testLog(format string, a ...interface{}) {

	tridx := len(tr.TestSuites) - 1
	tcidx := len(tr.TestSuites[tridx].TestCases) - 1

	tr.TestSuites[tridx].TestCases[tcidx].Info =
			append(tr.TestSuites[tridx].TestCases[tcidx].Info, fmt.Sprintf(format, a...))

}

func (tr * TestRun) suiteLog(format string, a ...interface{}) {

	tridx := len(tr.TestSuites) - 1

	tr.TestSuites[tridx].Info =
			append(tr.TestSuites[tridx].Info, fmt.Sprintf(format, a...))

}

func readStats(statFn string) (*TestRun, error) {
	// Check if the  stats file exists
	if _,err := os.Stat(statFn); err != nil {
		// Nothing to do, just return
		return &TestRun{}, nil
	}
	rtrn := &TestRun{}
	// The file is there, read it an unmarshal it into the stats struct
	if statBytes, err := ioutil.ReadFile(statFn); err != nil {
		log.Error(err)
		return nil, err
	} else if err := json.Unmarshal(statBytes, rtrn); err != nil {
		log.Error(err)
		return nil, err
	}
	return rtrn, nil
}

func writeStats(statFn string, stats * TestRun) error {
	// Check if the  stats file exists
	// The file is there, read it an unmarshal it into the stats struct
	if statBytes, err := json.MarshalIndent(stats, "","    "); err != nil {
		log.Error(err)
		return err
	} else if err := ioutil.WriteFile(statFn+".new", statBytes, 0644); err != nil {
		log.Error(err)
		return err
	}
	if err := os.Rename(statFn, statFn+"~"); err != nil {
		log.Error(err)
		return err
	}
	if err := os.Rename(statFn+".new", statFn); err != nil {
		log.Error(err)
		return err
	}
	return nil
}

func (tr * TestRun) appendNew() {
	tr.TestSuites = append(tr.TestSuites, TestSuite{})
}

func initStats(statFn string) error {
	s := &TestRun{}

	if statBytes, err := json.MarshalIndent(s, "","    "); err != nil {
		log.Error(err)
		return err
	} else if err := ioutil.WriteFile(statFn, statBytes, 0644); err != nil {
		log.Error(err)
		return err
	}

	return nil
}


var statFn string
var stats *TestRun
