module ProjectM36.Relation.Show.Gnuplot where
import ProjectM36.Base
import ProjectM36.Relation
import ProjectM36.Tuple
import ProjectM36.AtomFunctions.Primitive
import qualified ProjectM36.Attribute as A
import qualified Data.Vector as V

import qualified Graphics.Gnuplot.Plot.ThreeDimensional as Plot3D
import qualified Graphics.Gnuplot.Graph.ThreeDimensional as Graph3D

import qualified Graphics.Gnuplot.Plot.TwoDimensional as Plot2D
import qualified Graphics.Gnuplot.Graph.TwoDimensional as Graph2D

import qualified Graphics.Gnuplot.Advanced as GPA

--this module support plotting relations containing integer attributes with arity 1,2, or 3 only
--nested relations?

data PlotError = InvalidAttributeCountError |
                 InvalidAttributeTypeError
                 deriving (Int -> PlotError -> ShowS
[PlotError] -> ShowS
PlotError -> String
(Int -> PlotError -> ShowS)
-> (PlotError -> String)
-> ([PlotError] -> ShowS)
-> Show PlotError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PlotError] -> ShowS
$cshowList :: [PlotError] -> ShowS
show :: PlotError -> String
$cshow :: PlotError -> String
showsPrec :: Int -> PlotError -> ShowS
$cshowsPrec :: Int -> PlotError -> ShowS
Show)

--plotRelation :: Relation -> Either PlotError

intFromAtomIndex :: Int -> RelationTuple -> Int --warning- clips or overflows Integer -> Int
intFromAtomIndex :: Int -> RelationTuple -> Int
intFromAtomIndex Int
index RelationTuple
tup = Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Int) -> Int -> Int
forall a b. (a -> b) -> a -> b
$ Atom -> Int
castInt (Atom -> Int) -> Atom -> Int
forall a b. (a -> b) -> a -> b
$ RelationTuple -> Vector Atom
tupleAtoms RelationTuple
tup Vector Atom -> Int -> Atom
forall a. Vector a -> Int -> a
V.! Int
index

graph1DRelation :: Relation -> Plot2D.T Int Int
graph1DRelation :: Relation -> T Int Int
graph1DRelation Relation
rel = T Int Int Int -> [Int] -> T Int Int
forall x y a. (C x, C y, C a) => T x y a -> [a] -> T x y
Plot2D.list T Int Int Int
forall y. C y => T Int y y
Graph2D.listPoints ([Int] -> T Int Int) -> [Int] -> T Int Int
forall a b. (a -> b) -> a -> b
$ Relation -> [Int]
points1DRelation Relation
rel

points1DRelation :: Relation -> [Int]
points1DRelation :: Relation -> [Int]
points1DRelation = (RelationTuple -> [Int] -> [Int]) -> [Int] -> Relation -> [Int]
forall a. (RelationTuple -> a -> a) -> a -> Relation -> a
relFold RelationTuple -> [Int] -> [Int]
folder []
  where
    folder :: RelationTuple -> [Int] -> [Int]
folder RelationTuple
tup [Int]
acc = Int -> RelationTuple -> Int
intFromAtomIndex Int
0 RelationTuple
tup Int -> [Int] -> [Int]
forall a. a -> [a] -> [a]
: [Int]
acc

graph2DRelation :: Relation -> Plot2D.T Int Int
graph2DRelation :: Relation -> T Int Int
graph2DRelation Relation
rel = T Int Int (Int, Int) -> [(Int, Int)] -> T Int Int
forall x y a. (C x, C y, C a) => T x y a -> [a] -> T x y
Plot2D.list T Int Int (Int, Int)
forall x y. (C x, C y) => T x y (x, y)
Graph2D.points (Relation -> [(Int, Int)]
points2DRelation Relation
rel)

points2DRelation :: Relation -> [(Int, Int)]
points2DRelation :: Relation -> [(Int, Int)]
points2DRelation = (RelationTuple -> [(Int, Int)] -> [(Int, Int)])
-> [(Int, Int)] -> Relation -> [(Int, Int)]
forall a. (RelationTuple -> a -> a) -> a -> Relation -> a
relFold RelationTuple -> [(Int, Int)] -> [(Int, Int)]
folder []
  where
    folder :: RelationTuple -> [(Int, Int)] -> [(Int, Int)]
folder RelationTuple
tup [(Int, Int)]
acc = (Int -> RelationTuple -> Int
intFromAtomIndex Int
0 RelationTuple
tup, Int -> RelationTuple -> Int
intFromAtomIndex Int
1 RelationTuple
tup) (Int, Int) -> [(Int, Int)] -> [(Int, Int)]
forall a. a -> [a] -> [a]
: [(Int, Int)]
acc

graph3DRelation :: Relation -> Plot3D.T Int Int Int
graph3DRelation :: Relation -> T Int Int Int
graph3DRelation Relation
rel =
  T Int Int Int (Int, Int, Int) -> [(Int, Int, Int)] -> T Int Int Int
forall x y z a. (C x, C y, C z, C a) => T x y z a -> [a] -> T x y z
Plot3D.cloud T Int Int Int (Int, Int, Int)
forall x y z. (C x, C y, C z) => T x y z (x, y, z)
Graph3D.points ([(Int, Int, Int)] -> T Int Int Int)
-> [(Int, Int, Int)] -> T Int Int Int
forall a b. (a -> b) -> a -> b
$ Relation -> [(Int, Int, Int)]
points3DRelation Relation
rel

points3DRelation :: Relation -> [(Int, Int, Int)]
points3DRelation :: Relation -> [(Int, Int, Int)]
points3DRelation = (RelationTuple -> [(Int, Int, Int)] -> [(Int, Int, Int)])
-> [(Int, Int, Int)] -> Relation -> [(Int, Int, Int)]
forall a. (RelationTuple -> a -> a) -> a -> Relation -> a
relFold RelationTuple -> [(Int, Int, Int)] -> [(Int, Int, Int)]
folder []
  where
    folder :: RelationTuple -> [(Int, Int, Int)] -> [(Int, Int, Int)]
folder RelationTuple
tup [(Int, Int, Int)]
acc = (Int -> RelationTuple -> Int
intFromAtomIndex Int
0 RelationTuple
tup, Int -> RelationTuple -> Int
intFromAtomIndex Int
1 RelationTuple
tup, Int -> RelationTuple -> Int
intFromAtomIndex Int
2 RelationTuple
tup) (Int, Int, Int) -> [(Int, Int, Int)] -> [(Int, Int, Int)]
forall a. a -> [a] -> [a]
: [(Int, Int, Int)]
acc

{-
sample1DRelation = case mkRelationFromList (A.attributesFromList [Attribute "x" IntAtomType]) [[IntAtom 2], [IntAtom 3]] of
  Right rel -> rel
  Left _ -> undefined

sample2DRelation = case mkRelationFromList (A.attributesFromList [Attribute "x" IntAtomType, Attribute "y" IntAtomType]) [[IntAtom 2, IntAtom 3],
                                                                                                                          [IntAtom 2, IntAtom 4]] of
                     Right rel -> rel
                     Left _ -> undefined

sample3DRelation = case mkRelationFromList (A.attributesFromList [Attribute "x" IntAtomType, Attribute "y" IntAtomType, Attribute "z" IntAtomType]) [[IntAtom 2, IntAtom 3, IntAtom 3],
                             [IntAtom 2, IntAtom 4, IntAtom 4]] of
                     Right rel -> rel
                     Left _ -> undefined

-}

plotRelation :: Relation -> IO (Maybe PlotError)
plotRelation :: Relation -> IO (Maybe PlotError)
plotRelation Relation
rel = let attrTypes :: Vector AtomType
attrTypes = Int -> AtomType -> Vector AtomType
forall a. Int -> a -> Vector a
V.replicate (Relation -> Int
arity Relation
rel) AtomType
IntAtomType in
  if Vector AtomType
attrTypes Vector AtomType -> Vector AtomType -> Bool
forall a. Eq a => a -> a -> Bool
/= Attributes -> Vector AtomType
A.atomTypes (Relation -> Attributes
attributes Relation
rel) then
    Maybe PlotError -> IO (Maybe PlotError)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe PlotError -> IO (Maybe PlotError))
-> Maybe PlotError -> IO (Maybe PlotError)
forall a b. (a -> b) -> a -> b
$ PlotError -> Maybe PlotError
forall a. a -> Maybe a
Just PlotError
InvalidAttributeTypeError
  else
    case Relation -> Int
arity Relation
rel of
      Int
1 -> T Int Int -> IO ExitCode
forall gfx. C gfx => gfx -> IO ExitCode
GPA.plotDefault (Relation -> T Int Int
graph1DRelation Relation
rel) IO ExitCode -> IO (Maybe PlotError) -> IO (Maybe PlotError)
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Maybe PlotError -> IO (Maybe PlotError)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe PlotError
forall a. Maybe a
Nothing
      Int
2 -> T Int Int -> IO ExitCode
forall gfx. C gfx => gfx -> IO ExitCode
GPA.plotDefault (Relation -> T Int Int
graph2DRelation Relation
rel) IO ExitCode -> IO (Maybe PlotError) -> IO (Maybe PlotError)
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Maybe PlotError -> IO (Maybe PlotError)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe PlotError
forall a. Maybe a
Nothing
      Int
3 -> T Int Int Int -> IO ExitCode
forall gfx. C gfx => gfx -> IO ExitCode
GPA.plotDefault (Relation -> T Int Int Int
graph3DRelation Relation
rel) IO ExitCode -> IO (Maybe PlotError) -> IO (Maybe PlotError)
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Maybe PlotError -> IO (Maybe PlotError)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe PlotError
forall a. Maybe a
Nothing
      Int
_ -> Maybe PlotError -> IO (Maybe PlotError)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe PlotError -> IO (Maybe PlotError))
-> Maybe PlotError -> IO (Maybe PlotError)
forall a b. (a -> b) -> a -> b
$ PlotError -> Maybe PlotError
forall a. a -> Maybe a
Just PlotError
InvalidAttributeCountError


{-
--PNG
savePlottedRelation :: String -> Relation -> IO ()
savePlottedRelation path rel = case plotRelation rel of
  Left err -> putStrLn (show err)
  Right (Left g2d) -> plot' [] (PNG path) g2d >> return ()
  Right (Right g3d) -> plot' [] (PNG path) g3d >> return ()
-}