content: {-# LANGUAGE DeriveAnyClass #-}
  {-# LANGUAGE DeriveGeneric #-}
  {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  {-# LANGUAGE StandaloneDeriving #-}
  {-# LANGUAGE TypeFamilies #-}
  {-# LANGUAGE UndecidableInstances #-}
  {-# LANGUAGE NoImplicitPrelude #-}
  
  module Data.Graph.Labelled.Type where
  
  import qualified Algebra.Graph.Labelled.AdjacencyMap as LAM
  import Data.Aeson
  import qualified Data.Map.Strict as Map
  import Relude
  
  -- | Instances of this class can be used as a vertex in a graph.
  class Vertex v where
    type VertexID v :: Type
  
    -- | Get the vertex ID associated with this vertex.
    --
    -- This relation is expected to be bijective.
    vertexID :: v -> VertexID v
  
  -- | An edge and vertex labelled graph
  --
  -- The `v` must be an instance of `Vertex`; as such `v` is considered the vertex
  -- label, with the actual vertex (bijectively) derived from it.
  data LabelledGraph v e = LabelledGraph
    { graph :: LAM.AdjacencyMap e (VertexID v),
      vertices :: Map (VertexID v) v
    }
    deriving (Generic)
  
  deriving instance (Eq e, Eq v, Eq (VertexID v)) => Eq (LabelledGraph v e)
  
  deriving instance
    ( Ord e,
      Show e,
      Show v,
      Ord (VertexID v),
      Show (VertexID v)
    ) =>
    Show (LabelledGraph v e)
  
  instance (ToJSONKey (VertexID v), ToJSON v, ToJSON e) => ToJSON (LabelledGraph v e) where
    toJSON (LabelledGraph g vs) =
      toJSON $
        object
          [ "adjacencyMap" .= LAM.adjacencyMap g,
            "vertices" .= vs
          ]
  
  instance (FromJSONKey (VertexID v), Ord (VertexID v), Eq e, Monoid e, FromJSON v, FromJSON e) => FromJSON (LabelledGraph v e) where
    parseJSON =
      withObject "LabelledGraph" $ \lg ->
        LabelledGraph
          <$> (fmap mkGraph $ lg .: "adjacencyMap")
          <*> lg .: "vertices"
      where
        mkGraph = LAM.fromAdjacencyMaps . Map.toList
  