{- RJSONConvert
By Gregory W. Schwartz

Collects functions pertaining to converting the JSON output of R to the workable
tree. To create the input for this program from R:

@
library(data.tree)
library(jsonlite)
hc = hclust(dist(USArrests), "ave")
tree = as.Node(as.dendrogram(hc))
toJSON(as.list(tree, mode = "explicit", unname = TRUE))
@

-}

{-# LANGUAGE OverloadedStrings #-}

module RJSONConvert
    ( rJsonToTree
    , decodeRJsonTree
    , getRJsonTree
    ) where

-- Standard
import Data.Maybe
import qualified Data.Sequence as Seq
import Data.Tree
import Debug.Trace

-- Cabal
import qualified Data.Vector as V
import qualified Data.ByteString.Lazy.Char8 as C
import qualified Data.Text as T
import TextShow (showt)
import Math.TreeFun.Types
import Math.TreeFun.Tree
import Data.Aeson
import Data.Aeson.Types

-- Local
import Types

-- | Convert a R JSON format into the workable tree format
rJsonToTree :: Object -> Tree NodeLabel
rJsonToTree object =
    Node { rootLabel = getNodeLabel object
         , subForest = fmap rJsonToTree . getChildren $ object
         }

-- | Get the NodeLabel of a node
getNodeLabel :: Object -> NodeLabel
getNodeLabel object = do
    NodeLabel { nodeID = ""
              , nodeLabels = getLabel object
              }

-- | Get the label of the node
getLabel :: Object -> Labels
getLabel object = Seq.fromList
                . V.toList
                . either error id
                . flip parseEither object $ \obj -> do
                    labels <- obj .: "name"
                    return labels

-- | Get the children of a node
getChildren :: Object -> [Object]
getChildren object = either (const []) id
                   . flip parseEither object $ \obj -> do
                        children <- obj .: "children"
                        return children

-- | Get the generic AST from the file
decodeRJsonTree :: C.ByteString -> Object
decodeRJsonTree contents = fromMaybe
                             (error "Input is not a JSON object")
                             (decode contents :: Maybe Object)

-- | Get the lineage tree from a generic AST
getRJsonTree :: Object -> Tree NodeLabel
getRJsonTree object = rJsonToTree object