<Query Kind="FSharpProgram" />

// ------------------------------

open System
open System.Text.RegularExpressions
open System.Net
open System.Net.Cache
open System.Threading

// ------------------------------

// unit -> int
let tid () = Thread.CurrentThread.ManagedThreadId

// ------------------------------

let duration f = 
    let timer = new Stopwatch ()
    timer.Start ()
    let res = f ()
    timer.Stop ()
    printfn "... duration: %i ms" 
            timer.ElapsedMilliseconds
    res

// ------------------------------

// list<string*string> 
let urlList = [ ("Microsoft", "http://www.microsoft.com/")
                ("MSDN", "http://msdn.microsoft.com/")
                ("Bing", "http://www.bing.com")
              ]
              @ 
              [for i in 1..10 -> 
                ("Google", "https://www.google.co.nz/?#q=xyz"+i.ToString())]

// ------------------------------

// (string*string) -> (string*int)
let fetchSync (name:string, url:string) : string*int =  
    try
        printfn "\r\n... [%d] fetchSync (1): %s %s" (tid()) name url

        let uri = new System.Uri(url)
        let webClient = new WebClient()
        
        let html = webClient.DownloadString(uri)
        
        printfn "... [%d] fetchSync (2): (%s, %d):\r\n%s ..." 
            (tid()) name html.Length (Regex.Replace(html.Substring(0,200), @"\s+", " "))
        name, html.Length
        
    with ex -> 
        printfn "*** [%d] fetchSync: %s" (tid()) (ex.Message)
        name, 0

// fetchSyncAll : unit -> list<string*int>
let fetchSyncAll () =
    urlList                    // list<string*string>          
    |> List.map fetchSync      // list<string*int>

// ------------------------------

// (string*string) -> Async<string*int>
let fetchAsync (name:string, url:string) : Async<string*int> =  
    async { 
        try
            printfn "\r\n--- [%d] fetchAsync (1): %s %s" (tid()) name url

            let uri = new System.Uri(url)
            let webClient = new WebClient()
            
            let! html = webClient.      // two changes
                         AsyncDownloadString(uri)
                         // DownloadStringTaskAsync(uri)
                         // |> Async.AwaitTask
            
            printfn "\r\n+++ [%d] fetchAsync (2): (%s, %d):\r\n%s ...\r\n" 
                (tid()) name html.Length (Regex.Replace(html.Substring(0,200), @"\s+", " "))
            return name, html.Length
            
        with ex -> 
            printfn "*** [%d] fetchAsync: %s" (tid()) (ex.Message)
            return name, 0
    }

// fetchAsyncAll : unit -> (string*int)[]
let fetchAsyncAll () =
    urlList                     // list<string*string>          
    |> List.map fetchAsync      // list<Async<string*int>>
    |> Async.Parallel           // Async<(string*int)[]>
    |> Async.RunSynchronously   // (string*int)[]

// ------------------------------
// main

let TIME = true

printfn "... [%d] main0" (tid())

let s = if TIME then duration fetchSyncAll else fetchSyncAll ()
printfn "\r\n... [%d] main1 fetchSyncAll: %A" (tid()) s             // list<string*int>

let z = if TIME then duration fetchAsyncAll else fetchAsyncAll ()
printfn "\r\n... [%d] main3 fetchAsyncAll: %A" (tid()) z             // (string*int)[]

// ------------------------------

//Console.WriteLine ("\r\n<enter> to exit");
//Console.ReadLine () |> ignore

// ------------------------------