module Panes exposing (..)

import Data exposing (Id)
import Html exposing (Html)
import Triple exposing (Triple)
import History exposing (History)
import PaneMeta exposing (PaneMeta)
import Network.Messages exposing (SendMessage, ReceiveMessage)
import Data.Schema
import Http
import Notification exposing (Notification, NotificationEdit)

type Event
    = Open History
    | RemoveHistory History
    | OpenFile Id
    | OpenAddPerson Id String
    | OpenAddDatabase
    | OpenDatabaseAccess String
    | Send SendMessage
    | SetUpdated
    | CloseModal Int
    | EditSearchHistoryQuery String -- this will only edit if the newest entry in the history is a search
    | AttributeHistory AttributeHistoryInit
    | Upload Id (Maybe Id)
    | AddUpload PaneMeta.FileUpload
    | RemoveUpload String
    | AddHttpError Http.Error
    | SetNotification Notification
    | EditNotifcation NotificationEdit
    | EnterRegisterAccount String (Maybe String) -- database key

type alias PaneData state =
    { meta: PaneMeta
    , state: state
    }

type alias AttributeHistoryInit =
    { person: Id
    , data: Data.Attribute
    , schema: Data.Schema.Attribute
    }

type alias Init init state msg =
    PaneMeta -> init -> Triple state (Cmd msg) (List Event)

type alias View state msg =
    PaneData state -> Html msg

{-| Get the title of the Panel.
> **Only used for Modal Panels!**
-}
type alias Title state =
    PaneData state -> String

type alias Update state msg =
    msg -> PaneData state -> Triple state (Cmd msg) (List Event)

type alias Apply state msg =
    ReceiveMessage -> PaneData state -> Triple state (Cmd msg) (List Event)

type alias Save state =
    state -> List Event

type alias Subscription state msg =
    PaneData state -> Sub msg


type alias RawComponent init model msg = Component init model msg model msg

type alias Component init intModel intMsg exModel exMsg =
    { init: Init init exModel exMsg
    , view: View intModel exMsg
    , title: Title intModel
    , update: intMsg -> PaneData intModel 
        -> Triple exModel (Cmd exMsg) (List Event)
    , apply: Network.Messages.ReceiveMessage -> PaneData intModel
        -> Triple exModel (Cmd exMsg) (List Event)
    , save: Save intModel
    , subscription: Subscription intModel exMsg
    }

map : (c1 -> c2) -> (d1 -> d2) 
    -> Component init a b c1 d1 -> Component init a b c2 d2
map mapModel mapMsg comp =
    { init = \meta init -> comp.init meta init
        |> Triple.mapAll mapModel (Cmd.map mapMsg) identity
    , view = Html.map mapMsg
        << comp.view
    , title = comp.title
    , update = \msg data -> comp.update msg data
        |> Triple.mapAll mapModel (Cmd.map mapMsg) identity
    , apply = \msg data -> comp.apply msg data
        |> Triple.mapAll mapModel (Cmd.map mapMsg) identity
    , save = comp.save
    , subscription = Sub.map mapMsg << comp.subscription
    }

type alias ComponentWithModel model msg =
    { view: PaneMeta -> Html msg
    , title: PaneMeta -> String
    , apply: Network.Messages.ReceiveMessage -> PaneMeta
        -> Triple model (Cmd msg) (List Event)
    , save: () -> List Event
    , subscription: PaneMeta -> Sub msg
    }

attachModel : intModel -> Component init intModel intMsg exModel exMsg
    -> ComponentWithModel exModel exMsg
attachModel model comp =
    { view = \meta -> comp.view <| PaneData meta model
    , title = \meta -> comp.title <| PaneData meta model
    , apply = \mes meta -> comp.apply mes <| PaneData meta model
    , save = \() -> comp.save model
    , subscription = \meta -> comp.subscription <| PaneData meta model
    }
