{-# LANGUAGE DeriveDataTypeable, NamedFieldPuns #-}


module Main where


import Prelude ()
import Air.Env
import Air.Extra

import Text.JSON.Generic
import Text.JSON.Pretty (pp_value)

import Data.List (isInfixOf, find)
import Data.Maybe (fromMaybe)

import Network.Curl
import System.Directory

import Text.Printf

import ExpandURL (expand_url)
import Control.Monad (when)

import qualified Data.ByteString.Char8 as StrictByteString

data Feed = Feed
  {
    feed_date :: Integer
  , feed_summary :: String
  , feed_link :: String
  }
  deriving (Show, Eq, Data, Typeable)

instance Default Feed where
  def = Feed
    {
      feed_date = def
    , feed_summary = def
    , feed_link = def
    }

data TwitterListResponse = TwitterListResponse
  {
    text :: String
  , user :: TwitterUser
  , created_at :: String
  }
  deriving (Show, Eq, Data, Typeable)

instance Default TwitterListResponse where
  def = TwitterListResponse
    {
      text = def
    , user = def
    , created_at = def
    }

data TwitterUser = TwitterUser
  {
    screen_name :: String
  , name :: String
  }
  deriving (Show, Eq, Data, Typeable)


instance Default TwitterUser where
  def = TwitterUser
    {
      screen_name = def
    , name = def
    }


data URLCache = URLCache
  {
    original_url :: String
  , short_url :: String
  }
  deriving (Show, Eq, Data, Typeable)

dummy_feed :: Feed
dummy_feed = def
  {
    feed_summary = "google"
  , feed_link = "http://google.com"
  }


list_api_url = "https://api.twitter.com/1/lists/statuses.json?slug=peace-hime&owner_screen_name=nfjinjing&per_page=60"

list_json_path = "res/list.json"

-- Sat Jun 28 21:40:02 +0000 2008
twitter_time_format = "%a %b %d %H:%M:%S %z %Y"

download_list :: IO ()
download_list = do
  (_, r) <- curlGetString list_api_url []
  writeFile list_json_path r

read_list :: IO [TwitterListResponse]
read_list = do
  json <- readFile list_json_path
  return - decodeJSON json

write_template :: IO ()
write_template = do
  writeFile "res/list-template.json" - encodeJSON [ def :: TwitterListResponse ]

list2feeds :: TwitterListResponse -> Feed
list2feeds r = 
  let feed_date = r.created_at.parse_time twitter_time_format .t2i
      feed_summary = r.user.screen_name + " " + r.user.name + ": " + r.text
      feed_link = r.text.parse_url.fromMaybe ""
  in
  def 
    {
      feed_date
    , feed_summary
    , feed_link
    }
  
  

parse_url :: String -> Maybe String
parse_url x =
  if "http://" `isInfixOf` x
    then
      let xs = x.split "http://"
      in
      if xs.length.is 1
        then
          Just - x.words.first
        else
          Just - "http://" + xs.second.words.first
    else
      Nothing

normalize_feed :: Feed -> IO Feed
normalize_feed feed = do
  feed_original_link <- expand_url - feed.feed_link
  
  return - feed {feed_link = feed_original_link}
  
  

read_feed :: IO [Feed]
read_feed = do
  raw_feeds <- read_list ^ map list2feeds
  
  let feeds_count = raw_feeds.length
  
  raw_feeds.indexed.mapM (\(i, raw_feed) -> do
    
    
    normalized_feed <- do
      
      url_cache_string <- StrictByteString.readFile url_cache_path ^ StrictByteString.unpack
      let url_cache = url_cache_string.decodeJSON :: [URLCache]
      
      case url_cache.find (original_url > is (raw_feed.feed_link)) of
        Nothing -> do
          normalized_feed <- normalize_feed raw_feed
          
          let new_cache_item = URLCache {original_url = raw_feed.feed_link, short_url = normalized_feed.feed_link}
          
          let new_cache_string = ( new_cache_item : url_cache ) . take 200 . toJSON.pp_value.show
          
          -- puts new_cache_string
          
          StrictByteString.writeFile url_cache_path -  new_cache_string . StrictByteString.pack
          
          return - normalized_feed
          
        Just found_link -> do
          return - raw_feed {feed_link = found_link.short_url}
    
    putStr - printf "%2d/%2d" (i + 1 :: Int) (feeds_count :: Int)
    puts - ": " + normalized_feed.feed_link
    
    return normalized_feed
    )
    

url_cache_path :: String
url_cache_path = "tmp/url_cache.json"

main = do
  
  let sync_json_path = "public/sync.json"
  
  cache_exist <- doesFileExist url_cache_path
  
  when (not cache_exist) - do
    StrictByteString.writeFile url_cache_path - (([] :: [URLCache]). encodeJSON . StrictByteString.pack)
  
  download_list
  feed <- read_feed
  writeFile sync_json_path - feed.toJSON.pp_value.show
  
  removeFile list_json_path