// Hercules plugin "{{.name}}"
//
// How to build: execute "make" *OR*
//
// 1. Update the Protocol Buffers definition as needed, regenerate {{.protogo}}
//
//     PATH=$PATH:$GOPATH/bin protoc --gogo_out={{.outdir}} --proto_path={{.outdir}} {{.proto}}
//
// 2. Build {{.shlib}}
//
//     go build -buildmode=plugin -linkshared {{.output}} {{.protogo}}
//
// Step (1) requires GoGo Protobuf https://github.com/gogo/protobuf
//
// Usage:
//
//    hercules --plugin {{.shlib}} --{{.flag}}
//    hercules --plugin {{.shlib}} -help

package {{.package}}

import (
  "io"

  "github.com/gogo/protobuf/proto"
  "gopkg.in/src-d/go-git.v4"
  "gopkg.in/src-d/hercules.v7"
)

// {{.name}} contains the intermediate state which is mutated by Consume(). It should implement
// hercules.LeafPipelineItem.
type {{.name}} struct {
  // No special branch merge logic is required
  hercules.NoopMerger
  // Process each merge commit only once
  hercules.OneShotMergeProcessor
}

// {{.name}}Result is returned by Finalize() and represents the analysis result.
type {{.name}}Result struct {
}

// Analysis' name in the graph is usually the same as the type's name, however, does not have to.
func ({{.varname}} *{{.name}}) Name() string {
  return "{{.name}}"
}

// LeafPipelineItem-s normally do not act as intermediate nodes and thus we return an empty slice.
func ({{.varname}} *{{.name}}) Provides() []string {
  return []string{}
}

// Requires returns the list of dependencies which must be supplied in Consume().
func ({{.varname}} *{{.name}}) Requires() []string {
  arr := [...]string{/* insert dependencies here */}
  return arr[:]
}

// ListConfigurationOptions tells the engine which parameters can be changed through the command
// line.
func ({{.varname}} *{{.name}}) ListConfigurationOptions() []hercules.ConfigurationOption {
  opts := [...]hercules.ConfigurationOption{ /* {
    Name:        "ParameterName",
    Description: "Parameter's description.",
    Flag:        "my-cmdline-flag",
    Type:        hercules.BoolConfigurationOption,
    Default:     false}, */
  }
  return opts[:]
}

// Flag returns the command line switch which activates the analysis.
func ({{.varname}} *{{.name}}) Flag() string {
  return "{{.flag}}"
}

// Description returns the text which explains what the analysis is doing.
func ({{.varname}} *{{.name}}) Description() string {
  return "TODO: explain what this analysis is doing."
}

// Configure applies the parameters specified in the command line. Map keys correspond to "Name".
func ({{.varname}} *{{.name}}) Configure(facts map[string]interface{}) error {
  return nil
}

// Initialize resets the internal temporary data structures and prepares the object for Consume().
func ({{.varname}} *{{.name}}) Initialize(repository *git.Repository) error {
  {{.varname}}.OneShotMergeProcessor.Initialize()
  return nil
}

// Consume is called for every commit in the sequence.
func ({{.varname}} *{{.name}}) Consume(deps map[string]interface{}) (map[string]interface{}, error) {
  if !{{.varname}}.ShouldConsumeCommit(deps) {
    return nil, nil
  }
  return nil, nil
}

// Fork clones the same item several times on branches.
func ({{.varname}} *{{.name}}) Fork(n int) []hercules.PipelineItem {
  return hercules.ForkSamePipelineItem({{.varname}}, n)
}

// Finalize produces the result of the analysis. No more Consume() calls are expected afterwards.
func ({{.varname}} *{{.name}}) Finalize() interface{} {
  result := {{.name}}Result{}
  // insert code here
  return result
}

// Serialize converts the result from Finalize() to either Protocol Buffers or YAML.
func ({{.varname}} *{{.name}}) Serialize(result interface{}, binary bool, writer io.Writer) error {
  {{.varname}}Result := result.({{.name}}Result)
  if binary {
    return {{.varname}}.serializeBinary(&{{.varname}}Result, writer)
  }
  {{.varname}}.serializeText(&{{.varname}}Result, writer)
  return nil
}

func ({{.varname}} *{{.name}}) serializeText(result *{{.name}}Result, writer io.Writer) {
  // write YAML to writer
}

func ({{.varname}} *{{.name}}) serializeBinary(result *{{.name}}Result, writer io.Writer) error {
  message := {{.name}}ResultMessage{
    // fill me
  }
  serialized, err := proto.Marshal(&message)
  if err != nil {
    return err
  }
  writer.Write(serialized)
  return nil
}

func init() {
  hercules.Registry.Register(&{{.name}}{})
}
