###############################################################################
#
# docTool.eagle --
#
# Extensible Adaptable Generalized Logic Engine (Eagle)
# Documentation Generation Tool (UNFINISHED)
#
# Copyright (c) 2007-2012 by Joe Mistachkin.  All rights reserved.
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: $
#
###############################################################################

package require Eagle

proc usage { error } {
  if {[string length $error] > 0} then {puts stdout $error}
  puts stdout "usage: [file tail [info nameofexecutable]]\
[file tail [info script]] <fileName> <directory>"
}

if {[llength $argv] == 2} then {
  #
  # NOTE: Get the file name to read.
  #
  set templateFileName [lindex $argv 0]

  #
  # NOTE: Make sure the file name provided is not obviously invalid.
  #
  if {[string length $templateFileName] > 0 && \
      [file exists $templateFileName]} then {
    #
    # NOTE: Get the output directory name.
    #
    set outputDirectory [lindex $argv 1]

    if {[string length $outputDirectory] > 0 && \
        [file isdirectory $outputDirectory]} then {
      #
      # NOTE: These types are not intended to be used directly.
      #
      set skipTypes [list *._Attributes.* \
                          *._Commands.* \
                          *._Comparers.* \
                          *._Functions.* \
                          *._Hosts.* \
                          *._Lambdas.* \
                          *._Messages.* \
                          *._Objects.* \
                          *._ObjectTypes.* \
                          *._Operators.* \
                          *._Packages.* \
                          *._Plugins.* \
                          *._Procedures.* \
                          *._Tests.* \
                          *._Wrappers.* \
                          *.Private.*]

      #
      # NOTE: Read all the data out of the text (template) file.
      #
      set templateData [readFile $templateFileName]

      #
      # NOTE: Normalize to Unix line-endings.
      #
      set templateData [string map [list \r\n \n] $templateData]; # Unix.

      #
      # NOTE: We will be using reflection extensively.
      #
      object import System.Reflection

      #
      # NOTE: We need some routines from the test suite harness.
      #
      package require Eagle.Test

      #
      # NOTE: Get all the types from the primary Eagle assembly.
      #
      object foreach -alias type \
          [object invoke -create Assembly.GetExecutingAssembly GetTypes] {

        if {[llength [info commands $type]] == 0} then {
          debug break
        }

        #
        # NOTE: Only consider public types.  Also, skip public types that are
        #       not intended to be used directly.
        #
        if {[$type IsPublic] && \
            ![$type ContainsGenericParameters] && \
            [inverseLsearchGlob false $skipTypes [$type ToString]] == -1} then {
          #
          # NOTE: Now, get all the public members of this type.
          #
          # -flags +DeclaredOnly
          set members [object members -signatures \
              [$type AssemblyQualifiedName]]

          #
          # NOTE: Iterate over every member of this class.
          #
          foreach member $members {
            #
            # NOTE: Set the requirements for this member.  For now, we assume
            #       that all members require the "not yet released" Eagle 1.0
            #       RTM.
            #
            set minimumVersion 1.0
            set compileOptions [list]

            #
            # NOTE: Set the basic information about this member.
            #
            set className [$type ToString]
            set namespaceName [$type Namespace]

            set className [string range $className \
                [expr {[string length $namespaceName] + 1}] end]

            set memberType [getDictionaryValue $member memberType]
            set memberName [getDictionaryValue $member memberName]
            set returnType [getDictionaryValue $member returnType]

            #
            # NOTE: Set the documentation page title.
            #
            set title [appendArgs "The Eagle Project: " [$type ToString] \
                . $memberName]

            #
            # NOTE: At some point, these will be populated based on attributes
            #       on the member.
            #
            set notes ""
            set example ""

            #
            #
            #
            set parameters [list]

            #
            # NOTE: Query the parameters for this method.
            #
            if {$memberType eq "Method"} then {
              #
              # NOTE: Grab the parameter types.
              #
              set parameterTypes [getDictionaryValue $member parameterTypes]
              set parameterCount [llength $parameterTypes]

              if {$parameterCount > 0} then {
                #
                # NOTE:
                #
                set parameterTypeArray [object invoke -create -alias Array \
                    CreateInstance Type $parameterCount]

                for {set index 0} {$index < $parameterCount} {incr index} {
                  set parameterType [lindex $parameterTypes $index]

                  if {[string length $parameterType] > 0} then {
                    $parameterTypeArray SetValue [object invoke Type GetType \
                        $parameterType] $index
                  }
                }

                #
                # NOTE: Get the object for this method/property.
                #
                set method [object invoke -alias $type GetMethod $memberName \
                    $parameterTypeArray]

                #
                #
                #
                if {[string length $method] > 0} then {
                  #
                  #
                  #
                  set parameters [list]

                  object foreach -alias parameter \
                      [$method -alias GetParameters] {
                    set direction [list]

                    if {[$parameter IsIn]} then {
                      lappend direction in
                    }

                    if {[$parameter IsOut]} then {
                      lappend direction out
                    }

                    if {[$parameter IsRetval]} then {
                      lappend direction retval
                    }

                    set parameterNamespace [$parameter ParameterType.Namespace]

                    set parameterTypeName [$parameter ParameterType.ToString]
                    set parameterTypeName [string range $parameterTypeName \
                        [expr {[string length $parameterNamespace] + 1}] end]

                    #
                    #
                    #
                    lappend parameters [list $direction \
                         $parameterTypeName [$parameter Name]]
                  }
                } else {
                  #
                  #
                  #
                }
              } else {
                #
                #
                #
              }
            }

            #
            # NOTE: Create a documentation file for every member.
            #
            set outputFileName [file normalize [file join $outputDirectory \
                [appendArgs [$type ToString] . $memberName \
                [file extension $templateFileName]]]]

            #
            # NOTE: Perform the template replacements.  If an error is raised
            #       here, it will cause the tool to abort, which is fine.
            #
            if {[catch {set outputData [subst $templateData]} error]} then {
              error $errorInfo
            }

            #
            # NOTE: Write the output file with the results of the template.
            #
            # writeFile $outputFileName [string map [list \n \r\n] $outputData]
            # puts stdout [string map [list \n \r\n] $outputData]

            #
            # NOTE: Show how we tagged it.
            #
            # puts stdout [appendArgs "wrote \"" $outputFileName \".]
          }
        }
      }
    } else {
      usage "invalid directory name and/or directory must exist"
    }
  } else {
    usage "invalid file name and/or file must exist"
  }
} else {
  usage ""
}
