content: {-# LANGUAGE PackageImports #-}
  -- Copyright (c) 2008--2011 Andres Loeh
  -- Copyright (c) 2010--2021 Mikolaj Konarski and others (see git history)
  -- This file is a part of the computer game Allure of the Stars
  -- and is released under the terms of the GNU Affero General Public License.
  -- For license and copyright information, see the file LICENSE.
  --
  -- | The main source code file of Allure of the Stars.
  -- Module "TieKnot" is separated to make it usable in tests.
  module Main
    ( main
    ) where
  
  import Prelude ()
  
  import Game.LambdaHack.Core.Prelude
  
  import           Control.Concurrent.Async
  import qualified Control.Exception as Ex
  import qualified GHC.IO.Encoding as SIO
  import qualified Options.Applicative as OA
  import qualified System.IO as SIO
  
  #ifndef USE_JSFILE
  import qualified GHC.IO.Handle
  import           System.FilePath
  
  import Game.LambdaHack.Common.File (tryCreateDir)
  import Game.LambdaHack.Common.Misc
  #endif
  
  import Game.LambdaHack.Server (serverOptionsPI)
  
  -- For the case of flattened .cabal file, to avoid ambiguity.
  import "Allure" TieKnot
  
  -- | Parse commandline options, tie the engine, content and clients knot,
  -- run the game and handle exit.
  main :: IO ()
  main = do
    -- Correct unset or some other too primitive encodings.
    let enc = SIO.localeEncoding
    when (show enc `elem` ["ASCII", "ISO-8859-1", "ISO-8859-2"]) $
      SIO.setLocaleEncoding SIO.utf8
    -- This test is faulty with JS, because it reports the browser console
    -- is not a terminal, but then we can't open files to contain the logs.
    -- Also it bloats the outcome JS file, so disabled.
  #ifndef USE_JSFILE
    -- Special case hack, when the game is started not on a console.
    -- Without this, any attempt to output on stdout crashes a Windows exe
    -- (at least on Windows Vista) launched from the desktop or start menu.
    -- This is very crude and results in the inability to, e.g., process
    -- the output of @--help@ through a unix pipe. However, this should be
    -- effective on all Windows version, without the need to test all.
    isTerminal <- SIO.hIsTerminalDevice SIO.stdout
    unless isTerminal $ do
      dataDir <- appDataDir
      tryCreateDir dataDir
      fstdout <- SIO.openFile (dataDir </> "stdout.txt") SIO.WriteMode
      fstderr <- SIO.openFile (dataDir </> "stderr.txt") SIO.WriteMode
      GHC.IO.Handle.hDuplicateTo fstdout SIO.stdout
      GHC.IO.Handle.hDuplicateTo fstderr SIO.stderr
  #else
    -- Work around display of one character per line.
    SIO.hSetBuffering SIO.stderr SIO.LineBuffering
  #endif
    -- Fail here, not inside server code, so that savefiles are not removed,
    -- because they are not the source of the failure.
    !serverOptions <- OA.execParser serverOptionsPI
    resOrEx :: Either Ex.SomeException () <- Ex.try $ tieKnot serverOptions
    let unwrapEx e = case Ex.fromException e of
          Just (ExceptionInLinkedThread _ ex) -> unwrapEx ex
          _ -> e
    case resOrEx of
      Right () -> return ()
      Left ex -> Ex.throwIO $ unwrapEx ex
                   -- we are in the main thread, so now really exit
  