open Dash.NET
open System

let dslLayout = 
    Html.div [
        Attr.children [
            Html.p [ Attr.children "Enter a composite number to see its prime factors" ]
            Input.input "num" [
                Input.Attr.inputType InputType.Number
                Input.Attr.debounce true
                Input.Attr.min 1
                Input.Attr.step 1
            ]
            Html.p [ Attr.id "err"; Attr.style [ Css.color "red" ] ]
            Html.p [ Attr.id "out" ]
        ]
    ]

let primeFactors num =
    let rec pf n i out =
        if i * i <= n then
            if n % i = 0 then
                pf (n/i) i (i::out)
            else
                if i = 2 then 
                    pf n (i+1) out
                else
                    pf n 2 out
        else
            n::out
    pf num 2 []

let updateOutputsCallback =
    Callback.multiOut (
        "num" @. Value,
        [ "out" @. Children
          "err" @. Children ],
        fun (numberValue: Nullable<int>) -> 
            match numberValue |> Option.ofNullable with
            | None -> 
                []
            | Some n ->
                match primeFactors n with
                | [] -> 
                    []
                | [f] -> 
                    [ "out" @. Children => sprintf "%d is prime!" n ]
                | factors -> 
                    let factorsString =
                        factors
                        |> List.map string
                        |> List.reduce (sprintf "%s * %s")
                    [ "err" @. Children => sprintf "%d is %s" n factorsString ]
    )

[<EntryPoint>]
let main args =
    DashApp.initDefault()
    |> DashApp.withLayout dslLayout
    |> DashApp.addCallback updateOutputsCallback
    |> DashApp.run args