package flowserver

import (
	"encoding/json"
	"flow"
)

// Node that will contain registry src
type Node struct {
	ID   string            `json:"id"`
	Src  string            `json:"src"`
	Prop map[string]string `json:"prop"`
}

// Link that joins two nodes
type Link struct {
	From string `json:"from"`
	To   string `json:"to"`
	In   int    `json:"in"`
}

// FlowDocument flow document
type FlowDocument struct {
	Nodes []Node `json:"nodes"`
	Links []Link `json:"links"`
}

// FlowBuild build a flowGraph
func FlowBuild(rawData []byte) (*flow.Flow, error) {
	doc := FlowDocument{[]Node{}, []Link{}}
	err := json.Unmarshal(rawData, &doc)
	if err != nil {
		return nil, err
	}

	f := flow.New()
	nodeMap := map[string]Node{}
	for _, n := range doc.Nodes {
		nodeMap[n.ID] = n
	}
	inputMap := map[string]flow.Operation{}

	ninput := 0
	for _, n := range doc.Nodes {
		// Find link refered as To
		param := make([]interface{}, 10) // 10 is temporary to test out operations
		lastParamID := -1
		for _, l := range doc.Links {
			if l.To != n.ID {
				continue
			}
			if l.In > lastParamID {
				lastParamID = l.In
			}
			// Define operators here
			from := nodeMap[l.From]
			switch from.Src {
			case "Input":
				inOp, ok := inputMap[n.ID]
				if !ok {
					inOp = f.In(ninput)
					inputMap[n.ID] = inOp
					ninput++
				}
				param[l.In] = inOp // By id perhaps
			case "Variable":
				param[l.In] = f.Var(from.ID, from.Prop["init"])
			case "Const":
				param[l.In] = f.Const(from.Prop["value"])
			default:
				param[l.In] = f.Res(from.ID)
			}
		}
		param = param[:lastParamID+1]
		if n.Src == "Input" || n.Src == "Variable" || n.Src == "Const" {
			continue
		}
		f.DefOp(n.ID, n.Src, param...)
	}
	return f, nil
}
