-- Copyright 2018 Evan Laforge
-- This program is distributed under the terms of the GNU General Public
-- License 3.0, see COPYING or http://www.gnu.org/licenses/gpl-3.0.txt

-- | DSL functions to add tags to Sections.
module Solkattu.Dsl.Section (
    section
    , startOn, endOn, eddupu
    -- * tags
    , commentS, dateS
    , devel, ending, var, local
    , times, x2, x3, x4
    , variations
    , withTypeS
) where
import qualified Util.CallStack as CallStack
import qualified Util.Num as Num
import qualified Solkattu.Korvai as Korvai
import Solkattu.Korvai (Section, section)
import qualified Solkattu.Metadata as Metadata
import qualified Solkattu.S as S
import qualified Solkattu.Solkattu as Solkattu
import qualified Solkattu.Tags as Tags

import Global


-- | Set expected starting and ending time.  Useful for eddupu, or sections
-- which are split in the middle of an avartanam.
startOn, endOn :: S.Duration -> Section sollu -> Section sollu
startOn :: forall sollu. Duration -> Section sollu -> Section sollu
startOn Duration
dur Section sollu
section = Section sollu
section { sectionStart :: Duration
Korvai.sectionStart = Duration
dur }
endOn :: forall sollu. Duration -> Section sollu -> Section sollu
endOn Duration
dur Section sollu
section = Section sollu
section { sectionEnd :: Duration
Korvai.sectionEnd = Duration
dur }

-- | Like 'endOn', but also mark this section with eddupu.
eddupu :: S.Duration -> Section sollu -> Section sollu
eddupu :: forall sollu. Duration -> Section sollu -> Section sollu
eddupu Duration
dur = Text -> Text -> Section sollu -> Section sollu
forall sollu. Text -> Text -> Section sollu -> Section sollu
withTag Text
Tags.eddupu (Duration -> Text
forall a. Pretty a => a -> Text
pretty Duration
dur) (Section sollu -> Section sollu)
-> (Section sollu -> Section sollu)
-> Section sollu
-> Section sollu
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Duration -> Section sollu -> Section sollu
forall sollu. Duration -> Section sollu -> Section sollu
endOn Duration
dur

-- * tags

-- | Separate date for a section, mostly just so I can find its recording.
-- Unlike the korvai date it's just text.
dateS :: CallStack.Stack => Int -> Int -> Int -> Section sollu -> Section sollu
dateS :: forall sollu.
Stack =>
Int -> Int -> Int -> Section sollu -> Section sollu
dateS Int
y Int
m Int
d = (Text -> Section sollu -> Section sollu)
-> (Day -> Section sollu -> Section sollu)
-> Either Text Day
-> Section sollu
-> Section sollu
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Text -> Section sollu -> Section sollu
forall a. Stack => Text -> a
Solkattu.throw ((Section sollu -> Section sollu)
-> Day -> Section sollu -> Section sollu
forall a b. a -> b -> a
const ((Section sollu -> Section sollu)
 -> Day -> Section sollu -> Section sollu)
-> (Section sollu -> Section sollu)
-> Day
-> Section sollu
-> Section sollu
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Section sollu -> Section sollu
forall sollu. Text -> Text -> Section sollu -> Section sollu
withTag Text
Tags.date Text
date) (Either Text Day -> Section sollu -> Section sollu)
-> Either Text Day -> Section sollu -> Section sollu
forall a b. (a -> b) -> a -> b
$
    Int -> Int -> Int -> Either Text Day
Metadata.checkDate Int
y Int
m Int
d
    where date :: Text
date = Int -> Text
forall a. Show a => a -> Text
showt Int
y Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"-" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Int -> Text
forall a. Show a => Int -> a -> Text
Num.zeroPad Int
2 Int
m Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"-" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Int -> Text
forall a. Show a => Int -> a -> Text
Num.zeroPad Int
2 Int
d

commentS :: Text -> Section sollu -> Section sollu
commentS :: forall sollu. Text -> Section sollu -> Section sollu
commentS = Text -> Text -> Section sollu -> Section sollu
forall sollu. Text -> Text -> Section sollu -> Section sollu
withTag Text
Tags.comment

devel, ending :: sollu -> Section sollu
devel :: forall sollu. sollu -> Section sollu
devel = Text -> Section sollu -> Section sollu
forall sollu. Text -> Section sollu -> Section sollu
withTypeS Text
Tags.development (Section sollu -> Section sollu)
-> (sollu -> Section sollu) -> sollu -> Section sollu
forall b c a. (b -> c) -> (a -> b) -> a -> c
. sollu -> Section sollu
forall sollu. sollu -> Section sollu
Korvai.section
ending :: forall sollu. sollu -> Section sollu
ending = Text -> Section sollu -> Section sollu
forall sollu. Text -> Section sollu -> Section sollu
withTypeS Text
Tags.ending (Section sollu -> Section sollu)
-> (sollu -> Section sollu) -> sollu -> Section sollu
forall b c a. (b -> c) -> (a -> b) -> a -> c
. sollu -> Section sollu
forall sollu. sollu -> Section sollu
Korvai.section

var :: Section sollu -> Section sollu
var :: forall sollu. Section sollu -> Section sollu
var = Text -> Section sollu -> Section sollu
forall sollu. Text -> Section sollu -> Section sollu
withTypeS Text
Tags.variation

-- | On a transcription, this section is a local variation, not in the original
-- transcription.
local :: Section sollu -> Section sollu
local :: forall sollu. Section sollu -> Section sollu
local = Text -> Text -> Section sollu -> Section sollu
forall sollu. Text -> Text -> Section sollu -> Section sollu
withTag Text
"local" Text
""

-- | Performance instruction to repeat this section.
times :: Int -> Section sollu -> Section sollu
times :: forall sollu. Int -> Section sollu -> Section sollu
times Int
n = Text -> Text -> Section sollu -> Section sollu
forall sollu. Text -> Text -> Section sollu -> Section sollu
withTag Text
Tags.times (Int -> Text
forall a. Show a => a -> Text
showt Int
n)

x2, x3, x4 :: Section sollu -> Section sollu
x2 :: forall sollu. Section sollu -> Section sollu
x2 = Int -> Section sollu -> Section sollu
forall sollu. Int -> Section sollu -> Section sollu
times Int
2
x3 :: forall sollu. Section sollu -> Section sollu
x3 = Int -> Section sollu -> Section sollu
forall sollu. Int -> Section sollu -> Section sollu
times Int
3
x4 :: forall sollu. Section sollu -> Section sollu
x4 = Int -> Section sollu -> Section sollu
forall sollu. Int -> Section sollu -> Section sollu
times Int
4

withTypeS :: Text -> Section sollu -> Section sollu
withTypeS :: forall sollu. Text -> Section sollu -> Section sollu
withTypeS = Text -> Text -> Section sollu -> Section sollu
forall sollu. Text -> Text -> Section sollu -> Section sollu
withTag Text
Tags.type_

withTag :: Text -> Text -> Section sollu -> Section sollu
withTag :: forall sollu. Text -> Text -> Section sollu -> Section sollu
withTag Text
k Text
v = Tags -> Section sollu -> Section sollu
forall a. Tags -> Section a -> Section a
Korvai.addSectionTags (Text -> Text -> Tags
Tags.tag Text
k Text
v)

-- * util

variations :: [sollu] -> [Section sollu]
variations :: forall sollu. [sollu] -> [Section sollu]
variations = (sollu -> Section sollu) -> [sollu] -> [Section sollu]
forall a b. (a -> b) -> [a] -> [b]
map (Section sollu -> Section sollu
forall sollu. Section sollu -> Section sollu
var (Section sollu -> Section sollu)
-> (sollu -> Section sollu) -> sollu -> Section sollu
forall b c a. (b -> c) -> (a -> b) -> a -> c
. sollu -> Section sollu
forall sollu. sollu -> Section sollu
Korvai.section)

{- NOTE [solkattu-sections]
    sections are syntactically noisy
    . I have to put 'section' on everything, just so I can have one with
      e.g. 'x2'.
    . Also they break maps, like 'map (nadai 6)' has to become
      'map (fmap (nadai 6))'
    . The simplest thing is to put the section data inside Sequence, and
      then pull it out, like Alignment.
    . It means I could embed section metadata in sollus and have it show up
      in multiple sections, or multiple times.  That seems not right,
      because they really are per-section, and in fact the point of sections
      is to have that stuff.
    . Or a ToSection class, but that just means I could use 'x2' and omit
      'section', but that's not worth it.
    . The ideal is an implicit 'section' on each element of the list,
      unless there is one.  Like automatic coercion, or dynamic types.  But
      haskell doesn't have either.
    . Maybe I just shorten 'section' to 's' and live with it.
-}