module SeqSim.Render exposing (view) import SeqSim.Model exposing (Model, Msg(..)) import SeqSim.Parser exposing (parse, vars, valid, varsValid, Prog, Source(..)) import SeqSim.Evaluator exposing (..) import Maybe.Extra exposing (combine) import List.Extra exposing (zip, getAt) import Tuple exposing (second) import Html exposing (Html, text, textarea, input, label, small, div, span, button, a, h1, h2, h3, h4, h5, br) import Html.Attributes exposing (class, classList, id, for, type_, value, href) import Html.Events exposing (onClick, onInput) view : Model -> List (Html Msg) view m = [ div [ class "container" ] [ h1 [] [ text "Sequential Consistency Simulator" ] , viewProgs m.programs , viewOutcomes m ] ] toolbar : Html Msg toolbar = div [ class"btn-group" ] [ button [ type_ "button" , class "btn btn-primary" , onClick AddProgram ] [ text "Add Program" ] ] viewProgs : List String -> Html Msg viewProgs ps = div [] [ h2 [] [ text "Programs" ] , toolbar , div [ class "mt-2 row row-cols-1 row-cols-md-2 row-cols-lg-4" ] <| List.indexedMap viewProg ps ] viewProg : Int -> String -> Html Msg viewProg i s = div [ class "col mb-2" ] [ div [ class "card" ] [ div [ class "card-body" ] [ h5 [ class "card-title" ] [ text <| "Program " ++ String.fromInt (i+1) ] , viewProgValidity s , textarea [ class "mt-2 mb-2 form-control", onInput (ChangeProgram i), value s ] [ ] , a [ class "btn btn-outline-danger", onClick (DeleteProgram i) ] [ text "Remove" ] ] ] ] viewProgValidity : String -> Html Msg viewProgValidity s = if valid s then span [ class "text-success" ] [ text "Valid" ] else span [ class "text-danger" ] [ text "Invalid" ] viewOutcomes : Model -> Html Msg viewOutcomes m = div [] [ h2 [] [ text "Possible Outcomes" ] , div [ class "form-group" ] [ label [ for "variables" ] [ text "Interesting Variables" ] , input [ type_ "text" , id "variables" , class "form-control" , if String.isEmpty m.variables then classList [] else if varsValid m.variables then class "is-valid" else class "is-invalid" , value m.variables , onInput ChangeVariables ] [] , small [ class "form-text text-muted" ] [ text "Enter the variables you want included in the final outcomes, separated by a comma." ] ] , viewOutcomeTable m ] viewOutcomeTable : Model -> Html Msg viewOutcomeTable m = case (vars m.variables, combine <| List.map parse m.programs) of (Just (x::xs), Just ps) -> let all = allOutcomes (x::xs) ps in div [ class "card" ] <| List.singleton <| div [ class "card-body" ] [ div [ class "row" ] [ div [ class "col border-right col-auto" ] <| List.indexedMap (viewRow (x::xs)) <| List.map second all , div [ class "col" ] <| case Maybe.andThen (\i -> getAt i all) m.selected of Nothing -> [] Just (p, o) -> [ viewProgStr p ] ] ] _ -> div [] [] viewRow : List String -> Int -> List Int -> Html Msg viewRow xs i vs = div [] [ a [ href "#", onClick (SelectOutcome i) ] [ text <| stringFromOutcome xs vs ] ] stringFromOutcome : List String -> List Int -> String stringFromOutcome xs vs = List.map2 (\x v -> x ++ " = " ++ String.fromInt v) xs vs |> String.join ", " viewProgStr : Prog -> Html Msg viewProgStr p = let sourceStr s = case s of Var x -> x Const i -> String.fromInt i in List.map (\(x, s) -> text <| x ++ " = " ++ sourceStr s) p |> List.intersperse (br [] []) |> div []