/*
 * 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 main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"org/apache/htrace/common"
	"os"
	"sort"
)

// Create a dotfile from a json file.
func jsonSpanFileToDotFile(jsonFile string, dotFile string) error {
	spans, err := readSpansFile(jsonFile)
	if err != nil {
		return errors.New(fmt.Sprintf("error reading %s: %s",
			jsonFile, err.Error()))
	}
	var file *OutputFile
	file, err = CreateOutputFile(dotFile)
	if err != nil {
		return errors.New(fmt.Sprintf("error opening %s for write: %s",
			dotFile, err.Error()))
	}
	defer func() {
		if file != nil {
			file.Close()
		}
	}()
	writer := bufio.NewWriter(file)
	err = spansToDot(spans, writer)
	if err != nil {
		return err
	}
	err = file.Close()
	file = nil
	return err
}

// Create output in dotfile format from a set of spans.
func spansToDot(spans common.SpanSlice, writer io.Writer) error {
	sort.Sort(spans)
	idMap := make(map[common.SpanId]*common.Span)
	for i := range spans {
		span := spans[i]
		if idMap[span.Id] != nil {
			fmt.Fprintf(os.Stderr, "There were multiple spans listed which "+
				"had ID %s.\nFirst:%s\nOther:%s\n", span.Id.String(),
				idMap[span.Id].ToJson(), span.ToJson())
		} else {
			idMap[span.Id] = span
		}
	}
	childMap := make(map[common.SpanId]common.SpanSlice)
	for i := range spans {
		child := spans[i]
		for j := range child.Parents {
			parent := idMap[child.Parents[j]]
			if parent == nil {
				fmt.Fprintf(os.Stderr, "Can't find parent id %s for %s\n",
					child.Parents[j].String(), child.ToJson())
			} else {
				children := childMap[parent.Id]
				if children == nil {
					children = make(common.SpanSlice, 0)
				}
				children = append(children, child)
				childMap[parent.Id] = children
			}
		}
	}
	w := NewFailureDeferringWriter(writer)
	w.Printf("digraph spans {\n")
	// Write out the nodes with their descriptions.
	for i := range spans {
		w.Printf(fmt.Sprintf(`  "%s" [label="%s"];`+"\n",
			spans[i].Id.String(), spans[i].Description))
	}
	// Write out the edges between nodes... the parent/children relationships
	for i := range spans {
		children := childMap[spans[i].Id]
		sort.Sort(children)
		if children != nil {
			for c := range children {
				w.Printf(fmt.Sprintf(`  "%s" -> "%s";`+"\n",
					spans[i].Id.String(), children[c].Id))
			}
		}
	}
	w.Printf("}")
	return w.Error()
}
