{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Web.Last.Types where

import Control.Monad.Reader
import Control.Monad.Error
import Control.Monad.State

import System.IO.Unsafe

{-
  An api key must be provided in order to do anything.
  A user is only needed for certain api calls, namely
  ones that actually involve any writes.
-}
data LastState = LastState {apiKey :: APIKey,
                            secret :: Secret,
                            tok :: Maybe Token}
               deriving (Show,Eq)

type APIKey = String
type Token = String
type Secret = String

newtype Last a = Last {lastM :: ErrorT String
                                 (StateT LastState IO) a}
  deriving (Monad,MonadIO,Functor,MonadState LastState,
            MonadError String)

data Login = Login {loginName :: String,
                    password :: String}
          deriving (Eq,Show)

data LastFMError = LastFMError {errorNo :: Int,
                                message :: String}
    deriving (Show,Eq)

data Ranked a = Ranked String a -- !!! Read in a Int instead of a String
        deriving (Eq,Show,Ord)

data Track = Track {trackName :: String,
                    trackMBID :: String,
                    trackUrl :: String,
                    trackArtistName :: String,
                    trackArtistMBID :: Maybe String}
         deriving (Eq,Show,Ord)

data TrackInfo = TrackInfo {playCount :: String,
                            trackDuration :: Maybe String,
                            streamable :: Maybe StreamProp,
                            trackArtist :: Artist,
                            trackAlbum :: Album,
                            trackImages :: [Image],
                            trackListeners :: Maybe String,
                            trackPlaycount :: Maybe String,
                            trackTopTags :: Maybe [Tag],
                            trackWiki :: Maybe Wiki}
         deriving (Eq,Show,Ord)

data StreamProp = StreamProp String String
           deriving (Eq,Show,Ord)

data Artist = Artist {artistName :: String,
                      artistMBID :: Maybe String,
                      artistURL :: String}
            deriving (Eq,Show,Ord)

data ArtistInfo = ArtistInfo {artistImages :: [Image],
                              similarArtists :: [(Artist,[Image])],
                              artistListeners :: String,
                              artistPlaycount :: String,
                              artistWiki :: Wiki}
            deriving (Eq,Show,Ord)

data Image = Image {imageUrl :: String,
                    size :: String}
           deriving (Eq,Show,Ord)

data Event = Event {eventId :: String,
                    title :: String,
                    headliner :: String,
                    otherArtist :: [String],
                    venue :: Venue,
                    startDate :: String,
                    startTime :: Maybe String, -- How many other keys will have missing values?
                    description :: String,
                    eventImages :: [Image],
                    attendance :: String,
                    reviews :: String,
                    tag :: String,
                    eventUrl :: String}
           deriving (Show,Eq,Ord)

data Venue = Venue {venueName :: String,
                    venueID :: Maybe String,
                    venueLocation :: Location,
                    venueUrl :: String}
          deriving (Show,Eq,Ord)

data Location = Location {geoPoint :: GeoPoint,
                          country :: String,
                          city :: String,
                          street :: String,
                          postalcode :: String,
                          timezone :: Maybe String}
             deriving (Show,Eq,Ord)

data GeoPoint = GeoPoint {lat :: String,
                          long :: String}
             deriving (Show,Eq,Ord)

data Album = Album {albumName :: String,
                    albumArtist :: String,
                    albumArtistMBID :: Maybe String,
                    albumID :: Maybe String,
                    albumMBID :: Maybe String,
                    albumUrl :: String}
             deriving (Show,Eq,Ord)

data AlbumInfo = AlbumInfo {releaseDate :: String,
                            albumImages :: [Image],
                            albumListeners :: String,
                            albumPlaycount :: String,
                            albumTopTags :: String,
                            albumWiki :: Maybe Wiki}
            deriving (Show,Eq,Ord)

data Wiki = Wiki {published :: String,
                  summary :: String,
                  content :: String}
               deriving (Show,Eq,Ord)

data OpenSearch a = OpenSearch {searchQuery :: Query,
                                results :: [a]}
                  deriving (Show,Eq,Ord)

data Query = Query {queryText :: String,
                    role :: String,
                    searchTerms :: String,
                    startPage :: String}
           deriving (Show,Eq,Ord)

data Shout = Shout {shoutBody :: String,
                    shoutAuthor :: String,
                    shoutDate :: String}
           deriving (Show,Eq,Ord)

data User = User {userName :: String,
                  realName :: Maybe String,
                  userUrl :: String}
           deriving (Show,Eq,Ord)

data Playlist = Playlist {playlistTitle :: String,
                          playlistAnnotation :: String,
                          playlistCreator :: String,
                          playlistDate :: String,
                          playlistItems :: [PlaylistItem]}
           deriving (Show,Eq,Ord)

data PlaylistItem = PlaylistItem {itemTitle :: String,
                                  itemIdentifier :: String,
                                  itemAlbum :: String,
                                  itemCreator :: String,
                                  itemDuration :: String,
                                  itemInfo :: String,
                                  itemImageUrl :: Maybe String}
           deriving (Show,Eq,Ord)

data Weighted a = Weighted String a
           deriving (Show,Eq,Ord)

data Tag = Tag {tagName :: String,
                tagUrl :: String}
           deriving (Show,Eq,Ord)

data Paged a = Paged {pages :: [Last [a]]}

instance Show (Paged a) where
    show _ = "<Paged>"
