# This script generates a list of OpenGL functions and their corresponding
# documentation page on www.opengl.org in file GLSpec/glRef.txt.
# This list is generated by checking the function names against existing
# reference and extension specification pages with the http package.
# As this process takes some time, it must be executed by hand in a 2-step
# bootstrap process, once a new GLEW version is incorporated into Tcl3D.
# 
# See the ReadmeGlew.txt file in directory GLSpec for a detailed description
# of the update and bootstrap process.

package require http
package require tcl3d

# If set to true, reads the existing outFile and uses the URL's stored there
# as cache values without checking.
set gFastMode false

# File where the list of function names and corresponding URL's is stored.
set outFile "GLSpec/glFuncUrlList.txt"

# URL of the OpenGL main page.
set gUrlHost "https://www.opengl.org"

# TODO Moved to 
# https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glAccum.xml

# Template for standard OpenGL and GLU function reference pages.
# Note, that currently only reference pages exist up to version 2.1.
set glUrlTmpl1  "sdk/docs/man/html/%s.xhtml"
set glUrlTmpl2  "sdk/docs/man2/xhtml/%s.xml"

# Template for GLUT function reference pages.
# This is not a real template, but the master page of the GLUT API reference.
set glutUrlTmpl "documentation/specs/glut/spec3/spec3.html"

# Template for OpenGL extension function specification pages.
set extUrlTmpl "registry/specs/%s/%s.txt"

# Template for OpenGL functions, where no URL has been found.
# Search on Google for the function name.
set naUrlTmpl  "http://www.google.com/search?q=%s"

# Directory to store the reference pages.
set gOutDir "../applications/OglInfo/RefPages"

# Procedure checking the existence of a specified URL.
# The check is done by comparing the returned http string against "404".
# If the URL exists, the content of the page is also stored in a file.
proc UrlExists { func urlRel } {
    global gUrlChecked gOutDir gUrlHost gFuncUrl gFastMode

    puts "  Checking $func -> $urlRel"
    if { [info exists gFuncUrl($func)] } {
        set url $gFuncUrl($func)
        if { $gFastMode } {
            return $url
        }
    } else {
        set url [format "%s/%s" $gUrlHost $urlRel]
    }
    set retVal $url
    if { [info exists gUrlChecked($url)] } {
        puts "       Using cache $gUrlChecked($url) for $url"
        set retVal $gUrlChecked($url)
    } else {
        #set token [http::geturl $url -binary 1]
        set token [http::geturl $url]
        upvar #0 $token state
        if { [string match "*404*" $state(http)] } {
            set retVal ""
        } else {
            set data [::http::data $token]
            set fileName [file join $gOutDir $urlRel]
            if { ! [file isdirectory [file dirname $fileName]] } {
                puts "Creating directory [file dirname $fileName]"
                file mkdir [file dirname $fileName]
            }
            puts "Writing file $fileName"
            set fp [open $fileName "w"]
            puts $fp $data
            close $fp
        }
        ::http::cleanup $token
        set gUrlChecked($url) $retVal
    }
    return $retVal
}

# If the reference file already exists, create a backup copy.
# Read in the already checked URL's to speed up the process.
if { [file exists $outFile] } {
    file copy -force $outFile $outFile.bak
    set fp [open $outFile "r"]
    while { [gets $fp line] >= 0 } {
        foreach { key val } [split $line] { break }
        set gFuncUrl($key) $val
    }
    close $fp
}

set outFp [open $outFile "w"]

set glAllFuncList [tcl3dOglGetFuncList]
set numFuncs [llength $glAllFuncList]

set minLength 10000
foreach func $glAllFuncList {
    set len [string length $func]
    if { $len < $minLength } {
        set minLength $len
    }
}
puts "Shortest function name has $minLength characters"
incr minLength -1

# Change the start parameter only for testing purposes.
set start 0

set glInd 1
foreach func $glAllFuncList {
    if { $glInd < $start } {
        incr glInd
        continue
    }
    set glVersion [tcl3dOglGetFuncVersion $func]
    set foundUrl false
    if { ! [string match "GL_VERSION*" $glVersion] && \
         $glVersion ne "GL_ARB_imaging" } {
        # The function is an extension function. Create links
        # to the OpenGL extension repositiory.
        set extList [split $glVersion "_"]
        set extSuffix [join [lrange $extList 2 end] "_"]
        if { [lindex $extList 1] eq "OES" } {
            # OES extension URL's are named a little bit different.
            set extSuffix [format "OES_%s" $extSuffix]
        }
        set urlRel [format $extUrlTmpl [lindex $extList 1] $extSuffix]
        set url [UrlExists $func $urlRel]
        if { $url ne "" } {
            puts $outFp "$func $url"
            puts [format "%4d of %4d: %s %s" $glInd $numFuncs $func $url]
            set foundUrl true
        }
        # Some extensions (ex. GL_EXT_multisample) started out as a WGL_*
        # extension, and are therefore available under that URL.
        if { ! $foundUrl } {
            set urlRel [format $extUrlTmpl [lindex $extList 1] "wgl_$extSuffix"]
            set url [UrlExists $func $urlRel]
            if { $url ne "" } {
                puts $outFp "$func $url"
                puts [format "%4d of %4d: %s %s" $glInd $numFuncs $func $url]
                set foundUrl true
            }
        }
    } else {
        # The function is an OpenGL standard function or a function from
        # the GL_ARB_imaging extension. Find the corresponding
        # reference page. This is done by removing characters from the end of
        # the function name until a valid reference page URL is found.
        # This is needed, because there is only one page for a class of 
        # functions, ex. page glFog.xml for glFogi, glFogiv, glFogf, glFogfv.
        set baseFunc $func
        set len [string length $func]
        set ind [expr $len -1]
        while { ! $foundUrl && $ind >= $minLength } {
            set baseFunc [string range $func 0 $ind]
            foreach urlTmpl [list $glUrlTmpl1 $glUrlTmpl2] {
                set urlRel [format $urlTmpl $baseFunc]
                set url [UrlExists $func $urlRel]
                if { $url ne "" } {
                    puts $outFp "$func $url"
                    puts [format "%4d of %4d: %s %s" $glInd $numFuncs $func $url]
                    set foundUrl true
                    break
                }
            }
            incr ind -1
        }
    }
    if { ! $foundUrl } {
        set query $func
        set naUrl [format $naUrlTmpl $query]
        puts $outFp "$func $naUrl"
        puts [format "%4d of %4d: %s %s" $glInd $numFuncs $func $naUrl]
    }
    flush $outFp
    flush stdout
    incr glInd
}

# Now search for all GLU functions.
set gluInd 1
set gluAllFuncList [tcl3dOglGetFuncList "glu"]
set numFuncs [llength $gluAllFuncList]
foreach func $gluAllFuncList {
    set urlRel [format $glUrlTmpl2 $func]
    set url [UrlExists $func $urlRel]
    if { $url ne "" } {
        puts $outFp "$func $url"
        puts [format "%4d of %4d: %s %s" $gluInd $numFuncs $func $url]
    } else {
        set naUrl [format $naUrlTmpl $func]
        puts $outFp "$func $naUrl"
        puts [format "%4d of %4d: %s %s" $gluInd $numFuncs $func $naUrl]
    }
    flush $outFp
    flush stdout
    incr gluInd
}

# Now search for all GLUT functions.
set glutInd 1
set glutAllFuncList [info commands glut*]
set numFuncs [llength $glutAllFuncList]
foreach func $glutAllFuncList {
    set urlRel $glutUrlTmpl
    set url [UrlExists $func $urlRel]
    if { $url ne "" } {
        puts $outFp "$func $url"
        puts [format "%4d of %4d: %s %s" $glutInd $numFuncs $func $url]
    }
    flush $outFp
    flush stdout
    incr glutInd
}

close $outFp
exit 0
