module Language.SQL.Keyword.Internal.Type (
  
  Keyword (..), word, wordShow,
  
  fromDString, toDString,
  DString, dString, showDString, isEmptyDString
  ) where
import Data.String (IsString(..))
import Data.List (find)
import Data.Semigroup (Semigroup (..))
import Data.Monoid (Monoid (..))
newtype DString = DString (String -> String)
dString :: String -> DString
dString =  DString . (++)
showDString :: DString -> String
showDString (DString f) = f []
isEmptyDString :: DString -> Bool
isEmptyDString = null . showDString
instance Eq DString where
  x == y = showDString x == showDString y
instance Show DString where
  show = showDString
instance Read DString where
  readsPrec _ s = [(dString s, [])]
dappend :: DString -> DString -> DString
DString f `dappend` DString g = DString $ f . g
instance Semigroup DString where
  (<>) = dappend
instance Monoid DString where
  mempty  = DString id
  mappend = (<>)
data Keyword = SELECT | ALL | DISTINCT | ON
             | GROUP | COUNT | SUM | AVG | MAX | MIN | EVERY | ANY | SOME
             | CUBE | ROLLUP | GROUPING | SETS | HAVING
             | FOR
             | ORDER | BY | ASC | DESC | NULLS | LAST
             | OFFSET
             | LIMIT
             | FETCH | FIRST | NEXT | PERCENT
             | ROW | ROWS | ONLY | TIES
             | UNION | EXCEPT | INTERSECT
             | DELETE | USING | RETURNING
             | FROM | AS | WITH
             | JOIN | INNER | LEFT | RIGHT | FULL | NATURAL | OUTER
             | UPDATE | SET | DEFAULT
             | WHERE
             | INSERT | INTO | VALUES
             | MERGE
             | OVER | PARTITION
             | DENSE_RANK | RANK | ROW_NUMBER
             | PERCENT_RANK | CUME_DIST
             | LAG | LEAD | FIRST_VALUE | LAST_VALUE
             | CASE | END | WHEN | ELSE | THEN
             | LIKE | SIMILAR
             | AND | OR | NOT
             | EXISTS
             | IS | NULL | IN
             | DATE | TIME | TIMESTAMP | TIMESTAMPTZ | INTERVAL
             | Sequence !DString
             deriving (Read, Show)
             
fromDString :: DString -> Keyword
fromDString =  Sequence
toDString :: Keyword -> DString
toDString = d  where
  d (Sequence ds) = ds
  d  w            = dString $ show w
word :: String -> Keyword
word =  fromDString . dString
instance IsString Keyword where
  fromString s' = found (find ((== "") . snd) (reads s')) s'  where
   found  Nothing      s = word s
   found (Just (w, _)) _ = w
kappend :: Keyword -> Keyword -> Keyword
a `kappend` b = fromDString $ toDString a `append'` toDString b
  where
    append' p q
      | isEmptyDString p = q
      | isEmptyDString q = p
      | otherwise        = p <> dspace <> q
    dspace :: DString
    dspace =  dString " "
instance Semigroup Keyword where
  (<>) = kappend
instance Monoid Keyword where
  mempty  = fromDString mempty
  mappend = (<>)
wordShow :: Keyword -> String
wordShow =  d  where
  d (Sequence s)   = showDString s
  d w              = show w
instance Eq Keyword where
  x == y = wordShow x == wordShow y