module Data.Tsv2csv where
import Control.Monad (liftM, when)
import Data.List(intercalate)
import Data.List.Split(splitOn)
import System.IO (hPutStrLn, stderr)
import Test.HUnit

main = do
  ss <- getContents
  putStrLn $ toCsv . fromTsv $ ss

fromTsv :: String -> [[String]]
fromTsv = map (splitOn "\t") . lines

toCsv :: [[String]] -> String
toCsv = unlines . map (intercalate ",") . map (map csvEscape)

csvEscape :: String -> String
csvEscape s
  | ','  `elem` s = s'
  | '\"' `elem` s = s'
  | '\n' `elem` s = s'
  | otherwise     = s
  where s' = ('\"' : s) ++ "\""

------------------------------------------------------------------------
-- Self tests

-- cabal repl
--   runTests

runTests :: IO ()
runTests = do
    Counts c t e f <- runTestTT tests
    when (e > 0 || f > 0) $ hPutStrLn stderr $ "Failure"

alwaysFail = TestCase $ GT @?= EQ
alwaysPass = TestCase $ EQ @?= EQ

fromTsv_oneRow = TestCase $ got @?= expected
  where got = fromTsv tsv
        tsv = "foo\tbar\tzot"
        expected = [["foo", "bar", "zot"]]

fromTsv_twoRows = TestCase $ got @?= expected
  where got = fromTsv tsv
        tsv = "foo\tbar\tzot\nfoofoo\tbarbar\tzotzot"
        expected = [["foo", "bar", "zot"], ["foofoo", "barbar", "zotzot"]]

toCsv_oneRow = TestCase $ got @?= expected
  where got = toCsv xs
        xs = [["foo", "bar", "zot"]]
        expected = "foo,bar,zot\n"

toCsv_twoRows = TestCase $ got @?= expected
  where got = toCsv xs
        xs = [["foo", "bar", "zot"], ["foofoo", "barbar", "zotzot"]]
        expected = "foo,bar,zot\nfoofoo,barbar,zotzot\n"

toCsv_withComma = TestCase $ got @?= expected
  where got = toCsv xs
        xs = [["fo,o", "bar", "z,ot"]]
        expected = "\"fo,o\",bar,\"z,ot\"\n"

toCsv_withQuote = TestCase $ got @?= expected
  where got = toCsv xs
        xs = [["fo\"o", "b\"ar", "zot"]]
        expected = "\"fo\"o\",\"b\"ar\",zot\n"

toCsv_withNewline = TestCase $ got @?= expected
  where got = toCsv xs
        xs = [["fo\no", "b\nar", "zot"]]
        expected = "\"fo\no\",\"b\nar\",zot\n"

toCsv_withTab =  TestCase $ got @?= expected
  where got = toCsv xs
        xs = [["fo\\to", "bar", "zot"]]
        expected = "fo\\to,bar,zot\n"

tests :: Test
tests = TestList [
      TestLabel "Always pass"                  alwaysPass
--    , TestLabel "Always fail"                  alwaysFail
    , TestLabel "fromTsv_oneRow"               fromTsv_oneRow
    , TestLabel "fromTsv_twoRows"              fromTsv_twoRows
    , TestLabel "toCsv_oneRow"                 toCsv_oneRow
    , TestLabel "toCsv_twoRows"                toCsv_twoRows
    , TestLabel "toCsv_withComma"              toCsv_withComma
    , TestLabel "toCsv_withQuote"              toCsv_withQuote
    , TestLabel "toCsv_withNewline"            toCsv_withNewline
    , TestLabel "toCsv_withTab"                toCsv_withTab
  ]