github.com/hzck/speedroute@v0.0.0-20201115191102-403b7d0e443f/parser/jsonconverter.go (about)

     1  // Package parser manages JSON/XML object and converts them into a graph.
     2  package parser
     3  
     4  import (
     5  	"encoding/json"
     6  	"io/ioutil"
     7  
     8  	m "github.com/hzck/speedroute/model"
     9  )
    10  
    11  type rewardRef struct {
    12  	RewardID string `json:"rewardId"`
    13  	Quantity *int   `json:"quantity"`
    14  }
    15  
    16  type graph struct {
    17  	Rewards []reward `json:"rewards"`
    18  	Nodes   []node   `json:"nodes"`
    19  	Edges   []edge   `json:"edges"`
    20  	StartID string   `json:"startId"`
    21  	EndID   string   `json:"endId"`
    22  }
    23  
    24  type reward struct {
    25  	ID     string `json:"id"`
    26  	Unique bool   `json:"unique"`
    27  	IsA    string `json:"isA"`
    28  }
    29  
    30  type node struct {
    31  	ID          string      `json:"id"`
    32  	Rewards     []rewardRef `json:"rewards"`
    33  	Revisitable bool        `json:"revisitable"`
    34  }
    35  
    36  type weight struct {
    37  	Time         string      `json:"time"`
    38  	Requirements []rewardRef `json:"requirements"`
    39  }
    40  
    41  type edge struct {
    42  	From    string   `json:"from"`
    43  	To      string   `json:"to"`
    44  	Weights []weight `json:"weights"`
    45  }
    46  
    47  // CreateGraphFromFile takes a path as a parameter and creates rewards, nodes and edges before
    48  // returning a pointer to a graph.
    49  func CreateGraphFromFile(path string) (*m.Graph, error) {
    50  	file, err := ioutil.ReadFile(path)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  
    55  	var g graph
    56  	err = json.Unmarshal(file, &g)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	rewards := make(map[string]*m.Reward)
    62  	// ugly loop to make sure to handle different ordered rewards
    63  	for rewardAdded := true; rewardAdded; {
    64  		rewardAdded = false
    65  		for _, r := range g.Rewards {
    66  			if rewards[r.ID] == nil && (r.IsA == "" || rewards[r.IsA] != nil) {
    67  				rewards[r.ID] = m.CreateReward(r.ID, r.Unique, rewards[r.IsA])
    68  				rewardAdded = true
    69  			}
    70  		}
    71  	}
    72  
    73  	nodes := make(map[string]*m.Node)
    74  	for _, n := range g.Nodes {
    75  		node := m.CreateNode(n.ID, n.Revisitable)
    76  		for _, rewardRef := range n.Rewards {
    77  			// duplicate code
    78  			node.AddReward(rewards[rewardRef.RewardID], getPointerValueOrOne(rewardRef.Quantity))
    79  		}
    80  		nodes[node.ID()] = node
    81  	}
    82  
    83  	for _, e := range g.Edges {
    84  		edge := m.CreateEdge(nodes[e.From], nodes[e.To])
    85  		for _, w := range e.Weights {
    86  			time, err := parseTime(w.Time)
    87  			if err != nil {
    88  				return nil, err
    89  			}
    90  			weight := m.CreateWeight(time)
    91  			for _, rewardRef := range w.Requirements {
    92  				// duplicate code
    93  				weight.AddRequirement(rewards[rewardRef.RewardID], getPointerValueOrOne(rewardRef.Quantity))
    94  			}
    95  			edge.AddWeight(weight)
    96  		}
    97  	}
    98  	return m.CreateGraph(nodes[g.StartID], nodes[g.EndID]), nil
    99  }
   100  
   101  func getPointerValueOrOne(ptr *int) int {
   102  	if ptr != nil {
   103  		return *ptr
   104  	}
   105  	return 1
   106  }
   107  
   108  // CreateJSONFromRoutedPath takes an array of edges and creates an array of the included nodes,
   109  // and marshals it as json data in a byte array.
   110  func CreateJSONFromRoutedPath(path []*m.Edge) ([]byte, error) {
   111  	if len(path) == 0 {
   112  		return json.Marshal(path)
   113  	}
   114  	result := make([]string, len(path)+1)
   115  	result[0] = path[0].From().ID()
   116  	for i := 1; i < len(result); i++ {
   117  		result[i] = path[i-1].To().ID()
   118  	}
   119  	return json.Marshal(result)
   120  }