import Text.ParserCombinators.ReadP
import Control.Monad (guard)

data Field a = Field { fieldName :: String
                     , fieldSize :: Int
                     , fieldValue :: Maybe a}

instance Show a => Show (Field a) where
  show (Field n s a) = case a of
    Nothing -> n ++ "\t" ++ show s
    Just x -> n ++ "\t" ++ show s ++ "\t" ++ show x

newtype Data a = Data { fields :: [Field a] }

instance Show a => Show (Data a) where
  show (Data fs) = "NAME\tSIZE\tVALUE\n" ++ unlines (show <$> fs)

instance Read (Data a) where
  readsPrec _ = readP_to_S parseData 

parseData = do n <- parseHeader               
               guard (n `elem` [8,16,32,64]) 
               Data . concat <$> many1 (parseRow n)
  where
    parseRow n = do
      fs <- char '|' *> many parseField <* char '\n'
      guard $ sum (fieldSize <$> fs) == n 
      m <- parseHeader
      guard $ m == n 
      return fs

    parseHeader = do
      char '+'
      n <- length <$> many1 (string "
      char '\n'
      return n

    parseField = do
      s1 <- many (char ' ')
      f <- munch1 $ not . (`elem` " |")
      s2 <- many (char ' ')
      char '|'
      let n = (length (s1 ++ f ++ s2) + 1) `div` 3
      return $ Field f n Nothing


readData :: Data a -> [b] -> Data [b]
readData d = Data . go (fields d)
  where
    go fs [] = (\f -> f {fieldValue = Nothing}) <$> fs
    go (f:fs) s =
      let (x, xs) = splitAt (fieldSize f) s
      in f {fieldValue = Just x}: go fs xs


diagram = unlines
  ["+
  ,"|                      ID                       |"
  ,"+
  ,"|QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |"
  ,"+
  ,"|                    QDCOUNT                    |"
  ,"+
  ,"|                    ANCOUNT                    |"
  ,"+
  ,"|                    NSCOUNT                    |"
  ,"+
  ,"|                    ARCOUNT                    |"
  ,"+

dataSample = concat
  ["011110000100011101111011101111110101010010010110",
   "111000010010111000011011111100010110100110100100"]