/*
 * 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 = writer.Flush()
	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("}\n")
	return w.Error()
}
