-----------------------------------------------------------------------------
-- |
-- Module      :  Static.Resources
-- Copyright   :  (c) Scrive 2012
-- License     :  BSD-style (see the LICENSE file in the distribution)
--
-- Maintainer  :  mariusz@scrive.com
-- Stability   :  development
-- Portability :  portable
--
-- Put resources.spec into your public HTTP directory. List there your css and js files. Devide them over some sets.
--
-- Sample resources.spec:
--
-- > set mainPage
-- >  css mainPage.css
-- >  js  mainPage.js
-- >  js  jQuery.js
--
-- Usage:
--
-- > do
-- > rs <- getResourceSetsForImport Development "public/resources.js"
-- > return "<html><head>"++(htmlImportList "mainPage" rs)++"</head><body/></html>"
--

module Static.Resources (
                               -- * Main interface
                                 htmlImportList
                               , getResourceSetsForImport
                               , cleanResourceFiles
                               -- *Parsing specification
                               , ResourceSpec
                               , parseSpec
                               -- * Check if your spec file is compleate and consistent with FS
                               , check
                               --  | Generation
                               , ImportType(..)
                               , ResourceSetsForImport(..)
                               , generateResources
                        ) where

import Static.Resources.Types
import Static.Resources.Spec
import Static.Resources.Checker 
import Static.Resources.Generation
import Static.Resources.Import

import Control.Monad
import Control.Monad.Error
import Data.Either.Utils
import Data.Functor
import System.Directory
import Data.List

-- | Make 'ResourceSetsForImport' ready. It will generate agregated css and js files if needed.
--   It will change directory to one of spec file. It agregates will be placed there.
--   When done it will change back to the oryginal dir

getResourceSetsForImport :: ImportType -> FilePath -> IO (Either String ResourceSetsForImport)
getResourceSetsForImport it fp = do
    putStrLn "Starting static resource generation."
    sdir <- getCurrentDirectory
    spec <- parseSpec fp
    setCurrentDirectory $ reverse $ dropWhile (/= '/') $ reverse $ fp
    cleanResourceFiles spec
    res <- runErrorT $ do
        when (null $ sets spec) $ throwError "No resource sets are defined"
        checkRes <- lift $ check spec
        when (isLeft checkRes) $ throwError ("Error while checking spec. Error : " ++ fromLeft checkRes)
        lift $ generateResources it spec
    case res of
         Left s -> putStrLn $ "Static resource generation failed. " ++ s
         Right (ResourceSetsForImport rs) -> putStrLn $ "Static resource generation done. Generated " ++ show (length rs) ++ " sets."
    setCurrentDirectory sdir
    return res    
  where
    isLeft (Left _) = True
    isLeft _ = False


-- | Cleans all files that could be created by this system based on spec. It requires current directory to be in specification file directory
cleanResourceFiles :: ResourceSpec -> IO ()
cleanResourceFiles spec = do
     af <- getDirectoryContents "."
     forM_ (af) $ \fn ->
        when ((".css" `isSuffixOf` fn || ".js" `isSuffixOf` fn ) && any (\sn -> sn `isPrefixOf` fn ) (name <$> sets spec)) $
            removeFile fn