module Language.Docker.Syntax where

import Data.ByteString.Char8 (ByteString)
import Data.Maybe
import Data.String
import Text.Read

type Image = String

type Tag = String

data Ports
    = Ports [Integer]
    | PortStr String
    deriving (Show, Eq, Ord)

instance IsString Ports where
    fromString p =
        case readMaybe p of
            Just i -> Ports [i]
            Nothing ->
                let rs = map readMaybe (words p)
                in if all isJust rs
                       then Ports (catMaybes rs)
                       else PortStr p

type Directory = String

data BaseImage
    = UntaggedImage Image
    | TaggedImage Image
                  Tag
    | DigestedImage Image
                    ByteString
    deriving (Eq, Ord, Show)

-- | Type of the Dockerfile AST
type Dockerfile = [InstructionPos]

type Source = String

type Destination = String

type Arguments = [String]

type Pairs = [(String, String)]

-- | All commands available in Dockerfiles
data Instruction
    = From BaseImage
    | Add Source
          Destination
    | User String
    | Label Pairs
    | Stopsignal String
    | Copy Source
           Destination
    | Run Arguments
    | Cmd Arguments
    | Shell Arguments
    | Workdir Directory
    | Expose Ports
    | Volume String
    | Entrypoint Arguments
    | Maintainer String
    | Env Pairs
    | Arg String
    | Healthcheck String
    | Comment String
    | OnBuild Instruction
    | EOL
    deriving (Eq, Ord, Show)

type Filename = String

type Linenumber = Int

-- | 'Instruction' with additional location information required for creating
-- good check messages
data InstructionPos =
    InstructionPos Instruction
                   Filename
                   Linenumber
    deriving (Eq, Ord, Show)

instruction :: InstructionPos -> Instruction
instruction (InstructionPos i _ _) = i

sourcename :: InstructionPos -> Filename
sourcename (InstructionPos _ fn _) = fn