{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE RankNTypes        #-}
{-# LANGUAGE StrictData        #-}

{-|
Module      : Headroom.FileSupport.Types
Description : Data types for "Headroom.FileSupport" module
Copyright   : (c) 2019-2021 Vaclav Svejcar
License     : BSD-3-Clause
Maintainer  : vaclav.svejcar@gmail.com
Stability   : experimental
Portability : POSIX

Data types for "Headroom.FileSupport" module in separated module
(to avoid cyclic dependencies).
-}

module Headroom.FileSupport.Types
  ( -- * Data Types
    FileSupport(..)
  , SyntaxAnalysis(..)
    -- * Smart Constructors
  , defaultFileSupport
    -- * Function Type Aliases
  , ExtractTemplateDataFn
  , ExtractVariablesFn
  )
where

import           Headroom.Configuration.Types        ( HeaderSyntax )
import           Headroom.FileSupport.TemplateData   ( TemplateData(..) )
import           Headroom.FileType.Types             ( FileType )
import           Headroom.Header.Types               ( HeaderTemplate )
import           Headroom.SourceCode                 ( SourceCode )
import           Headroom.Template                   ( Template )
import           Headroom.Variables.Types            ( Variables )
import           RIO


-- | Set of functions that every file support needs to implement.
data FileSupport = FileSupport
  { FileSupport -> SyntaxAnalysis
fsSyntaxAnalysis      :: SyntaxAnalysis
  , FileSupport
-> forall a. Template a => a -> HeaderSyntax -> TemplateData
fsExtractTemplateData :: ExtractTemplateDataFn
  , FileSupport -> ExtractVariablesFn
fsExtractVariables    :: ExtractVariablesFn
  , FileSupport -> FileType
fsFileType            :: FileType
  }


-- | Set of functions used to analyze source code.
data SyntaxAnalysis = SyntaxAnalysis
  { SyntaxAnalysis -> Text -> Bool
saIsCommentStart :: Text -> Bool
  , SyntaxAnalysis -> Text -> Bool
saIsCommentEnd   :: Text -> Bool
  }


-- | Type of a function that extracts additional template data from template.
type ExtractTemplateDataFn
  =  forall a
   . Template a
  => a
  -- ^ template to use for extraction
  -> HeaderSyntax
  -- ^ copyright header syntax
  -> TemplateData
  -- ^ extracted template data


-- | Type of a function that extracts variables from analyzed source code file.
type ExtractVariablesFn
  =  HeaderTemplate
  -- ^ header template
  -> Maybe (Int, Int)
  -- ^ header position as @(startLine, endLine)@
  -> SourceCode
  -- ^ analyzed source code file
  -> Variables
  -- ^ extracted variables


-- | Default implementation of 'FileSupport' that doesn't extract any variables
-- or template data.
defaultFileSupport :: FileType
                   -- ^ type of the source code file
                   -> SyntaxAnalysis
                   -- ^ function that analyzes source code
                   -> FileSupport
                   -- ^ resulting 'FileSupport'
defaultFileSupport :: FileType -> SyntaxAnalysis -> FileSupport
defaultFileSupport FileType
fileType SyntaxAnalysis
syntaxAnalysis = FileSupport :: SyntaxAnalysis
-> (forall a. Template a => a -> HeaderSyntax -> TemplateData)
-> ExtractVariablesFn
-> FileType
-> FileSupport
FileSupport
  { fsSyntaxAnalysis :: SyntaxAnalysis
fsSyntaxAnalysis      = SyntaxAnalysis
syntaxAnalysis
  , fsExtractTemplateData :: forall a. Template a => a -> HeaderSyntax -> TemplateData
fsExtractTemplateData = (HeaderSyntax -> TemplateData) -> a -> HeaderSyntax -> TemplateData
forall a b. a -> b -> a
const ((HeaderSyntax -> TemplateData)
 -> a -> HeaderSyntax -> TemplateData)
-> (TemplateData -> HeaderSyntax -> TemplateData)
-> TemplateData
-> a
-> HeaderSyntax
-> TemplateData
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TemplateData -> HeaderSyntax -> TemplateData
forall a b. a -> b -> a
const (TemplateData -> a -> HeaderSyntax -> TemplateData)
-> TemplateData -> a -> HeaderSyntax -> TemplateData
forall a b. (a -> b) -> a -> b
$ TemplateData
NoTemplateData
  , fsExtractVariables :: ExtractVariablesFn
fsExtractVariables    = (Maybe (Int, Int) -> SourceCode -> Variables) -> ExtractVariablesFn
forall a b. a -> b -> a
const ((Maybe (Int, Int) -> SourceCode -> Variables)
 -> ExtractVariablesFn)
-> (Variables -> Maybe (Int, Int) -> SourceCode -> Variables)
-> Variables
-> ExtractVariablesFn
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SourceCode -> Variables)
-> Maybe (Int, Int) -> SourceCode -> Variables
forall a b. a -> b -> a
const ((SourceCode -> Variables)
 -> Maybe (Int, Int) -> SourceCode -> Variables)
-> (Variables -> SourceCode -> Variables)
-> Variables
-> Maybe (Int, Int)
-> SourceCode
-> Variables
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Variables -> SourceCode -> Variables
forall a b. a -> b -> a
const (Variables -> ExtractVariablesFn)
-> Variables -> ExtractVariablesFn
forall a b. (a -> b) -> a -> b
$ Variables
forall a. Monoid a => a
mempty
  , fsFileType :: FileType
fsFileType            = FileType
fileType
  }