{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-missing-fields #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
{-# OPTIONS_GHC -fno-warn-unused-imports #-}
{-# OPTIONS_GHC -fno-warn-unused-matches #-}

-----------------------------------------------------------------
-- Autogenerated by Thrift
--                                                             --
-- DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
--  @generated
-----------------------------------------------------------------

module TestService_Fuzzer (main) where
import Module_Types
import qualified TestService_Client as Client

import Prelude ( Bool(..), Enum, Float, IO, Double, String, Maybe(..),
                 Eq, Show, Ord,
                 concat, error, fromIntegral, fromEnum, length, map,
                 maybe, not, null, otherwise, return, show, toEnum,
                 enumFromTo, Bounded, minBound, maxBound, seq,
                 (.), (&&), (||), (==), (++), ($), (-), (>>=), (>>))

import Control.Applicative (ZipList(..), (<*>))
import Control.DeepSeq
import Control.Exception
import Control.Monad ( liftM, ap, when )
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as BS
import Data.Functor ( (<$>) )
import Data.Hashable
import Data.Int
import Data.Maybe (catMaybes)
import Data.Text.Lazy.Encoding ( decodeUtf8, encodeUtf8 )
import qualified Data.Text.Lazy as LT
import Data.Typeable ( Typeable )
import qualified Data.HashMap.Strict as Map
import qualified Data.HashSet as Set
import qualified Data.Vector as Vector
import Test.QuickCheck.Arbitrary ( Arbitrary(..) )
import Test.QuickCheck ( elements )

import Thrift hiding (ProtocolExnType(..))
import qualified Thrift (ProtocolExnType(..))
import Thrift.Types
import Thrift.Serializable
import Thrift.Arbitraries

import Prelude ((>>), print)
import qualified Prelude as P
import Control.Monad (forM)
import qualified Data.List as L
import Data.Maybe (fromJust)
import qualified Data.Map as Map
import GHC.Int (Int64, Int32)
import Data.ByteString.Lazy (ByteString)
import System.Environment (getArgs)
import Test.QuickCheck (arbitrary)
import Test.QuickCheck.Gen (Gen(..))
import Thrift.FuzzerSupport


handleOptions :: ([Options -> Options], [String], [String]) -> Options
handleOptions (transformers, (serviceName:[]), []) | serviceName `P.elem` serviceNames
    = (P.foldl (P.flip ($)) defaultOptions transformers) { opt_service = serviceName } 
handleOptions (_, (serviceName:[]), []) | P.otherwise
    = P.error $ usage ++ "\nUnknown serviceName " ++ serviceName ++ ", should be one of " ++ (P.show serviceNames)
handleOptions (_, [], _) = P.error $ usage ++ "\nMissing mandatory serviceName to fuzz."
handleOptions (_, _a, []) = P.error $ usage ++ "\nToo many serviceNames, pick one."
handleOptions (_, _, e) = P.error $ usage ++ (P.show e)

main :: IO ()
main = do
    args <- getArgs
    let config = handleOptions (getOptions args)
    fuzz config

selectFuzzer :: Options -> (Options -> IO ())
selectFuzzer (Options _host _port service _timeout _framed _verbose) 
    = fromJust $ P.lookup service fuzzerFunctions

fuzz :: Options -> IO ()
fuzz config = (selectFuzzer config) config

-- Dynamic content

-- Configuration via command-line parsing

serviceNames :: [String]
serviceNames = ["init"]

fuzzerFunctions :: [(String, (Options -> IO ()))]
fuzzerFunctions = [("init", init_fuzzer)]

-- Random data generation
inf_Int64 :: IO [Int64]
inf_Int64 = infexamples (arbitrary :: Gen Int64)

-- Fuzzers and exception handlers
init_fuzzer :: Options -> IO ()
init_fuzzer opts = do
  a1 <- ZipList <$> inf_Int64
  _ <- forM (getZipList a1) init_fuzzFunc
  return ()
  where
  init_fuzzFunc a1 = let param = (a1) in
    if opt_framed opts
    then withThriftDo opts (withFramedTransport opts) (init_fuzzOnce param) (init_exceptionHandler param)
    else withThriftDo opts (withHandle opts) (init_fuzzOnce param) (init_exceptionHandler param)

init_exceptionHandler :: (Show a1) => (a1) -> IO ()
init_exceptionHandler (a1) = do
  P.putStrLn $ "Got exception on data:"
  P.putStrLn $ "(" ++ show a1 ++ ")"
init_fuzzOnce (a1) client = Client.init client a1 >> return ()

