module RunLengthEncoding (encode, decode) where

import String exposing (fromChar)
import List exposing (head, tail)
import Maybe exposing (withDefault)
import Regex


{-
To the unaware: this was written by a very green elmer, so don't consider
it an idiomatic exemplar to emulate.
-}


encode : String -> String
encode string =
  String.toList string
    |> List.foldr countChars []
    |> List.map stringifyCounts
    |> String.join ""


countChars : a -> List ( number, a ) -> List ( number, a )
countChars current counted =
  case head counted of
    Just ( count, previous ) ->
      if previous == current then
        ( count + 1, current ) :: withDefault [] (tail counted)
      else
        ( 1, current ) :: counted

    Nothing ->
      [ ( 1, current ) ]


stringifyCounts : ( number, Char ) -> String
stringifyCounts ( count, char ) =
  if count > 1 then
    toString count ++ fromChar char
  else
    fromChar char


decode : String -> String
decode string =
  string
    |> Regex.find Regex.All (Regex.regex "(\\d+)|(\\D)")
    |> List.map .match
    |> List.foldl expandCounts ( "", Nothing )
    |> fst


expandCounts : String -> ( String, Maybe Int ) -> ( String, Maybe Int )
expandCounts match ( result, count ) =
  case count of
    Just number ->
      ( result ++ String.repeat number match, Nothing )

    Nothing ->
      case String.toInt match of
        Ok number ->
          ( result, Just number )

        Err _ ->
          ( result ++ match, Nothing )