module SyntaxTrees.Scala.DataDef where

import Data.Monoid.HT           (when)
import SyntaxTrees.Scala.Common (Ctor, Modifier, TypeClass)
import SyntaxTrees.Scala.FnDef  (InternalFnDef, MethodDef)
import SyntaxTrees.Scala.Type   (ArgList (..), Type, TypeCtor, TypeParam,
                                 UsingArgList)
import Utils.Foldable           (hasSome)
import Utils.String             (Empty (Empty), joinList, joinWords, str,
                                 wrapSpacedBlock, wrapSquareCsv)


data TypeDef
  = TypeDef
      { TypeDef -> TypeCtor
alias      :: TypeCtor
      , TypeDef -> [TypeParam]
typeParams :: [TypeParam]
      , TypeDef -> Type
type'      :: Type
      }

data OpaqueTypeDef
  = OpaqueTypeDef
      { OpaqueTypeDef -> TypeCtor
alias      :: TypeCtor
      , OpaqueTypeDef -> [TypeParam]
typeParams :: [TypeParam]
      , OpaqueTypeDef -> Type
type'      :: Type
      , OpaqueTypeDef -> [TypeClass]
derives    :: [TypeClass]
      }

data TraitDef
  = TraitDef
      { TraitDef -> [Modifier]
modifiers     :: [Modifier]
      , TraitDef -> TypeCtor
name          :: TypeCtor
      , TraitDef -> [TypeParam]
typeParams    :: [TypeParam]
      , TraitDef -> [ArgList]
argLists      :: [ArgList]
      , TraitDef -> [UsingArgList]
usingArgLists :: [UsingArgList]
      , TraitDef -> [Type]
extends       :: [Type]
      , TraitDef -> [InternalDef]
internalDefs  :: [InternalDef]
      }

data ClassDef
  = ClassDef
      { ClassDef -> [Modifier]
modifiers     :: [Modifier]
      , ClassDef -> TypeCtor
name          :: TypeCtor
      , ClassDef -> [TypeParam]
typeParams    :: [TypeParam]
      , ClassDef -> [ArgList]
argLists      :: [ArgList]
      , ClassDef -> [UsingArgList]
usingArgLists :: [UsingArgList]
      , ClassDef -> [Type]
extends       :: [Type]
      , ClassDef -> [InternalDef]
internalDefs  :: [InternalDef]
      }

data ObjectDef
  = ObjectDef
      { ObjectDef -> [Modifier]
modifiers    :: [Modifier]
      , ObjectDef -> TypeCtor
name         :: TypeCtor
      , ObjectDef -> [Type]
extends      :: [Type]
      , ObjectDef -> [InternalDef]
internalDefs :: [InternalDef]
      }


data EnumDef
  = EnumDef
      { EnumDef -> [Modifier]
modifiers     :: [Modifier]
      , EnumDef -> TypeCtor
name          :: TypeCtor
      , EnumDef -> [TypeParam]
typeParams    :: [TypeParam]
      , EnumDef -> [ArgList]
argLists      :: [ArgList]
      , EnumDef -> [UsingArgList]
usingArgLists :: [UsingArgList]
      , EnumDef -> [TypeClass]
derives       :: [TypeClass]
      , EnumDef -> [EnumCaseDef]
cases         :: [EnumCaseDef]
      }

data EnumCaseDef
  = EnumCaseDef
      { EnumCaseDef -> Ctor
name          :: Ctor
      , EnumCaseDef -> [ArgList]
argLists      :: [ArgList]
      , EnumCaseDef -> [UsingArgList]
usingArgLists :: [UsingArgList]
      , EnumCaseDef -> [Type]
extends       :: [Type]
      , EnumCaseDef -> [InternalFnDef]
internalDefs  :: [InternalFnDef]
      }


data CaseClassDef
  = CaseClassDef
      { CaseClassDef -> [Modifier]
modifiers     :: [Modifier]
      , CaseClassDef -> TypeCtor
name          :: TypeCtor
      , CaseClassDef -> [TypeParam]
typeParams    :: [TypeParam]
      , CaseClassDef -> [ArgList]
argLists      :: [ArgList]
      , CaseClassDef -> [UsingArgList]
usingArgLists :: [UsingArgList]
      , CaseClassDef -> [TypeClass]
derives       :: [TypeClass]
      , CaseClassDef -> [Type]
extends       :: [Type]
      , CaseClassDef -> [InternalFnDef]
internalDefs  :: [InternalFnDef]
      }

data CaseObjectDef
  = CaseObjectDef
      { CaseObjectDef -> [Modifier]
modifiers    :: [Modifier]
      , CaseObjectDef -> TypeCtor
name         :: TypeCtor
      , CaseObjectDef -> [TypeClass]
derives      :: [TypeClass]
      , CaseObjectDef -> [Type]
extends      :: [Type]
      , CaseObjectDef -> [InternalFnDef]
internalDefs :: [InternalFnDef]
      }

data ExtensionDef
  = ExtensionDef
      { ExtensionDef -> [TypeParam]
typeParams    :: [TypeParam]
      , ExtensionDef -> [ArgList]
argLists      :: [ArgList]
      , ExtensionDef -> [UsingArgList]
usingArgLists :: [UsingArgList]
      , ExtensionDef -> [MethodDef]
methodDefs    :: [MethodDef]
      }


data InternalDef
  = Fn InternalFnDef
  | TypeAlias TypeDef
  | OpaqueType OpaqueTypeDef
  | Trait TraitDef
  | Class ClassDef
  | Object ObjectDef
  | Enum EnumDef
  | EnumCase EnumCaseDef
  | CaseClass CaseClassDef
  | CaseObject CaseObjectDef
  | Extension ExtensionDef


instance Show TypeDef where
  show :: TypeDef -> String
show (TypeDef TypeCtor
x [TypeParam]
y Type
z) =
    [String] -> String
joinWords [String
"type",
               forall a. Show a => a -> String
show TypeCtor
x,
               forall a. Show a => [a] -> String
wrapSquareCsv [TypeParam]
y,
               String
"=",
               forall a. Show a => a -> String
show Type
z]

instance Show OpaqueTypeDef where
  show :: OpaqueTypeDef -> String
show (OpaqueTypeDef TypeCtor
x [TypeParam]
y Type
z [TypeClass]
t) =
    [String] -> String
joinWords [String
"opaque type",
               forall a. Show a => a -> String
show TypeCtor
x,
               forall a. Show a => [a] -> String
wrapSquareCsv [TypeParam]
y,
               String
"=",
               forall a. Show a => a -> String
show Type
z,
               forall a. Show a => String -> String -> [a] -> String
joinList String
"derives" String
"," [TypeClass]
t]

instance Show TraitDef where
  show :: TraitDef -> String
show (TraitDef [Modifier]
x TypeCtor
y [TypeParam]
z [ArgList]
t [UsingArgList]
u [Type]
v [InternalDef]
w) =
    forall a b.
(Show a, Show b) =>
String
-> [Modifier]
-> a
-> [TypeParam]
-> [ArgList]
-> [UsingArgList]
-> [TypeClass]
-> [Type]
-> [b]
-> String
showStructure String
"trait" [Modifier]
x TypeCtor
y [TypeParam]
z [ArgList]
t [UsingArgList]
u [] [Type]
v [InternalDef]
w

instance Show ClassDef where
  show :: ClassDef -> String
show (ClassDef [Modifier]
x TypeCtor
y [TypeParam]
z [ArgList]
t [UsingArgList]
u [Type]
v [InternalDef]
w) =
    forall a b.
(Show a, Show b) =>
String
-> [Modifier]
-> a
-> [TypeParam]
-> [ArgList]
-> [UsingArgList]
-> [TypeClass]
-> [Type]
-> [b]
-> String
showStructure String
"class" [Modifier]
x TypeCtor
y [TypeParam]
z [ArgList]
t [UsingArgList]
u [] [Type]
v [InternalDef]
w

instance Show ObjectDef where
  show :: ObjectDef -> String
show (ObjectDef [Modifier]
x TypeCtor
y [Type]
z [InternalDef]
t) =
    forall a b.
(Show a, Show b) =>
String
-> [Modifier]
-> a
-> [TypeParam]
-> [ArgList]
-> [UsingArgList]
-> [TypeClass]
-> [Type]
-> [b]
-> String
showStructure String
"object" [Modifier]
x TypeCtor
y [] [] [] [] [Type]
z [InternalDef]
t

instance Show EnumDef where
  show :: EnumDef -> String
show (EnumDef [Modifier]
x TypeCtor
y [TypeParam]
z [ArgList]
t [UsingArgList]
u [TypeClass]
v [EnumCaseDef]
w) =
    forall a b.
(Show a, Show b) =>
String
-> [Modifier]
-> a
-> [TypeParam]
-> [ArgList]
-> [UsingArgList]
-> [TypeClass]
-> [Type]
-> [b]
-> String
showStructure String
"enum" [Modifier]
x TypeCtor
y [TypeParam]
z [ArgList]
t [UsingArgList]
u [TypeClass]
v [] [EnumCaseDef]
w

instance Show EnumCaseDef where
  show :: EnumCaseDef -> String
show (EnumCaseDef Ctor
x [ArgList]
y [UsingArgList]
z [Type]
t [InternalFnDef]
u) =
    forall a b.
(Show a, Show b) =>
String
-> [Modifier]
-> a
-> [TypeParam]
-> [ArgList]
-> [UsingArgList]
-> [TypeClass]
-> [Type]
-> [b]
-> String
showStructure String
"case" [] Ctor
x [] [ArgList]
y [UsingArgList]
z [] [Type]
t [InternalFnDef]
u

instance Show CaseClassDef where
  show :: CaseClassDef -> String
show (CaseClassDef [Modifier]
x TypeCtor
y [TypeParam]
z [ArgList]
t [UsingArgList]
u [TypeClass]
v [Type]
w [InternalFnDef]
r) =
    forall a b.
(Show a, Show b) =>
String
-> [Modifier]
-> a
-> [TypeParam]
-> [ArgList]
-> [UsingArgList]
-> [TypeClass]
-> [Type]
-> [b]
-> String
showStructure String
"case class" [Modifier]
x TypeCtor
y [TypeParam]
z [ArgList]
t [UsingArgList]
u [TypeClass]
v [Type]
w [InternalFnDef]
r

instance Show CaseObjectDef where
  show :: CaseObjectDef -> String
show (CaseObjectDef [Modifier]
x TypeCtor
y [TypeClass]
z [Type]
t [InternalFnDef]
u) =
    forall a b.
(Show a, Show b) =>
String
-> [Modifier]
-> a
-> [TypeParam]
-> [ArgList]
-> [UsingArgList]
-> [TypeClass]
-> [Type]
-> [b]
-> String
showStructure String
"case object" [Modifier]
x TypeCtor
y [] [] [] [TypeClass]
z [Type]
t [InternalFnDef]
u

instance Show ExtensionDef where
  show :: ExtensionDef -> String
show (ExtensionDef [TypeParam]
x [ArgList]
y [UsingArgList]
z [MethodDef]
t) =
    forall a b.
(Show a, Show b) =>
String
-> [Modifier]
-> a
-> [TypeParam]
-> [ArgList]
-> [UsingArgList]
-> [TypeClass]
-> [Type]
-> [b]
-> String
showStructure String
"extension" [] Empty
Empty [TypeParam]
x [ArgList]
y [UsingArgList]
z [] [] [MethodDef]
t



showStructure :: (Show a, Show b) => String -> [Modifier] -> a -> [TypeParam]
                 -> [ArgList] -> [UsingArgList] -> [TypeClass] -> [Type] -> [b]
                 -> String
showStructure :: forall a b.
(Show a, Show b) =>
String
-> [Modifier]
-> a
-> [TypeParam]
-> [ArgList]
-> [UsingArgList]
-> [TypeClass]
-> [Type]
-> [b]
-> String
showStructure  String
x [Modifier]
y a
z [TypeParam]
t [ArgList]
u [UsingArgList]
v [TypeClass]
w [Type]
r [b]
s =
  [String] -> String
joinWords [String
x,
             forall a. Show a => String -> [a] -> String
str String
" " [Modifier]
y,
             forall a. Show a => a -> String
show a
z,
             forall a. Show a => [a] -> String
wrapSquareCsv [TypeParam]
t,
             forall a. Show a => String -> [a] -> String
str String
" " [ArgList]
u,
             forall a. Show a => String -> [a] -> String
str String
" " [UsingArgList]
v,
             forall a. Show a => String -> String -> [a] -> String
joinList String
"derives" String
", " [TypeClass]
w,
             forall a. Show a => String -> String -> [a] -> String
joinList String
"extends" String
", " [Type]
r,
             String
sep forall a. [a] -> [a] -> [a]
++ forall a. Show a => [a] -> String
wrapSpacedBlock [b]
s]
  where
    sep :: String
sep = forall m. Monoid m => Bool -> m -> m
when (String
x forall a. Eq a => a -> a -> Bool
/= String
"extension" Bool -> Bool -> Bool
&& forall (t :: * -> *) a. Foldable t => t a -> Bool
hasSome [b]
s) String
": "

instance Show InternalDef where
  show :: InternalDef -> String
show (Fn InternalFnDef
x)         = forall a. Show a => a -> String
show InternalFnDef
x
  show (TypeAlias TypeDef
x)  = forall a. Show a => a -> String
show TypeDef
x
  show (OpaqueType OpaqueTypeDef
x) = forall a. Show a => a -> String
show OpaqueTypeDef
x
  show (Trait TraitDef
x)      = forall a. Show a => a -> String
show TraitDef
x
  show (Class ClassDef
x)      = forall a. Show a => a -> String
show ClassDef
x
  show (Object ObjectDef
x)     = forall a. Show a => a -> String
show ObjectDef
x
  show (Enum EnumDef
x)       = forall a. Show a => a -> String
show EnumDef
x
  show (EnumCase EnumCaseDef
x)   = forall a. Show a => a -> String
show EnumCaseDef
x
  show (CaseClass CaseClassDef
x)  = forall a. Show a => a -> String
show CaseClassDef
x
  show (CaseObject CaseObjectDef
x) = forall a. Show a => a -> String
show CaseObjectDef
x
  show (Extension ExtensionDef
x)  = forall a. Show a => a -> String
show ExtensionDef
x