{-|
 -
Description : Entry-point of executable
Copyright   : (c) Eric Mertens, 2016
License     : ISC
Maintainer  : emertens@gmail.com

Entry point into glirc. This module sets up VTY and launches the client.
-}
module Main where

import Control.Exception
import Control.Lens
import Control.Monad
import Data.List (nub)
import Data.Text (Text)
import System.Exit
import System.IO
import Graphics.Vty
import Graphics.Vty.Platform.Unix (mkVty)

import Client.Configuration
import Client.EventLoop
import Client.Options
import Client.State
import Client.State.Extensions
import Client.State.Focus

import Exports ()

-- | Main action for IRC client
main :: IO ()
main =
  do opts <- getOptions
     let mbPath = view optConfigFile opts
     (path,cfg) <- loadConfiguration' mbPath
     withClientState path cfg $ \st0 ->
       withVty $ \vty ->
         do st1 <- clientStartExtensions    st0
            st2 <- initialNetworkLogic opts st1
            st3 <- updateTerminalSize vty   st2
            eventLoop vty st3

initialNetworkLogic :: Options -> ClientState -> IO ClientState
initialNetworkLogic opts st = addInitialNetworks (nub networks) st
  where
    networks
      | view optNoConnect opts = view optInitialNetworks opts
      | otherwise              = view optInitialNetworks opts ++ clientAutoconnects st

-- | Load configuration and handle errors along the way.
loadConfiguration' :: Maybe FilePath -> IO (FilePath, Configuration)
loadConfiguration' mbPath =
  do cfgRes <- loadConfiguration mbPath
     case cfgRes of
       Right x -> return x
       Left (ConfigurationReadFailed e) ->
         report "Failed to open configuration:" e
       Left (ConfigurationParseFailed p e) ->
         report ("Failed to parse configuration file: " ++ p) e
       Left (ConfigurationMalformed p e) ->
         report ("Malformed configuration file: " ++ p ++ "\n(try --config-format)") e
  where
    report problem msg =
      do hPutStrLn stderr problem
         hPutStrLn stderr msg
         exitFailure

-- | Create connections for the given networks.
-- Set the client focus to the first network listed.
addInitialNetworks ::
  [Text] {- networks -} ->
  ClientState           ->
  IO ClientState
addInitialNetworks [] st = return st
addInitialNetworks (n:ns) st =
  do st' <- foldM (\st_ n -> addConnection 0 Nothing Nothing n st_) st (n:ns)
     return $! set clientFocus (NetworkFocus n) st'

-- | Initialize a 'Vty' value and run a continuation. Shutdown the 'Vty'
-- once the continuation finishes.
withVty :: (Vty -> IO a) -> IO a
withVty = bracket buildVty shutdown

-- | Generate the initial 'Vty' value and enable the features glirc uses.
buildVty :: IO Vty
buildVty =
 do vty <- mkVty defaultConfig
    setMode (outputIface vty) BracketedPaste True
    setMode (outputIface vty) Focus True
    pure vty
