#
# $Log: not supported by cvs2svn $
# Revision 1.18  2011/12/20 03:22:59  soliday
# Minor revision to clean up a few details.
#
# Revision 1.17  2011/11/21 21:02:08  soliday
# Fixed a bug with last change.
#
# Revision 1.16  2011/11/21 20:57:41  soliday
# Added full pathnames to executables when run from the web server.
#
# Revision 1.15  2011/11/21 20:41:36  soliday
# Modified the APSGetValidICMSTechReportCategories and APSGetValidICMSTechReportSubCategories
# procedures so they read the categories out of an SDDS file.
#
# Revision 1.14  2011/11/14 14:39:54  soliday
# Fixed a bug related to setting xTopicLevels 1 and 2.
#
# Revision 1.13  2011/10/25 19:28:21  soliday
# I now use four topic levels instead of two. For the purposes of Tech Notes, the
# top two levels will always be Technical Documentation and Technical Notes.
#
# Revision 1.12  2011/10/25 19:02:06  soliday
# Added the option of returning the Info URL after submitting a document.
#
# Revision 1.11  2011/08/23 16:28:46  soliday
# Added the APSICMSQueryTopicLevels procedure.
#
# Revision 1.10  2011/08/19 14:38:46  soliday
# It now allows setting the xProject field.
#
# Revision 1.9  2011/08/17 13:45:05  soliday
# Fixed an issue submitting a revision when the title has changed.
#
# Revision 1.8  2011/08/11 19:33:23  soliday
# Added APSICMSQueryRevisionNumber
#
# Revision 1.7  2011/08/10 19:28:28  soliday
# Added APSICMSDocInfoToSDDS which can be used to extract the a single document's
# info into an SDDS file.
#
# Revision 1.6  2011/08/10 15:19:28  soliday
# Added APSICMSQueryVaultFileSize which can be used by automated cronjobs to
# test if a PDF file has changed size and can then decide to re-upload it to ICMS.
#
# Revision 1.5  2011/08/10 14:42:43  soliday
# Updated APSSubmitFileToICMS so that you can submit different doc types.
#
# Revision 1.4  2011/08/08 20:33:20  soliday
# Lots of changes.
# Added APSICMSTechReportToSDDS which can query the ICMS
# data tags for multiple documents and place them into an SDDS file.
# Added APSICMSUpdateDocInfoFromSDDS which can take an SDDS file and update
# the ICMS data tags for multiple documents.
# Added APSICMSQueryDocNameAndRevision which will query ICMS using various fields
# to identify if a document already exists in ICMS. This is needed for submitting
# revisions.
# Updated APSSubmitFileToICMS to support submitting revisions.
#
# Revision 1.3  2011/08/01 17:55:21  soliday
# Added more Tech Report categories and sub-categories based on Borland's
# new list.
#
# Revision 1.2  2011/07/26 20:55:24  soliday
# Improved the APSSubmitFileToICMS procedure so that more options can be set
# such as: group, division, comments, category and subcategory. Also created
# APSPromptSTDINforICMSinfo which prompts the user for the various values
# prior to calling APSSubmitFileToICMS.
#
# Revision 1.1  2011/05/04 15:11:53  soliday
# Functions in this file are used to summit reports to the ANL ICMS content
# server.
#
#

proc APSSubmitFileToICMSHelp {} {
    return "Usage: APSSubmitFileToICMS \n\
-dDocTitle <title>\n\
-xDocAuthor <authors>\n\
-xTopicLevel3 <category>\n\
-xTopicLevel4 <subcategory>\n\
-xComments <comments>\n\
-xDocDate <date>\n\
-xDivision <division>\n\
-xGroup <group>\n\
-primaryFile <filename>\n\
-icmsPassword <string>\n\
-icmsUsername <string>\n\
-dRevLabel <revision number>\n\
-dDocAccount <security account>\n\
-dSecurityGroup <security group>\n\
You can use APSPromptSTDINforICMSinfo to prompt the user for the values to the various arguments first."
}

proc APSSubmitFileToICMS {args} {
    global env
    set alternateFile ""
    set dDocAccount "APSShare/AcceleratorOperationsPhysics"
    set dDocAuthor "$env(USER)"
    set dDocName ""
    set dDocTitle ""
    set dDocType "Report"
    set dRevLabel 1
    set dSecurityGroup "APS"
    set extraProps ""
    set icmsPassword ""
    set icmsUsername ""
    set primaryFile ""
    set xComments ""
    set xDocAuthor "$env(USER)"
    set xDocDate ""
    set xDivision "ASD"
    set xGroup "AOP"
    set xProject ""
    set xTopicLevel1 "Technical Documentation"
    set xTopicLevel2 "Technical Notes"
    set xTopicLevel3 ""
    set xTopicLevel4 ""
    set returnURL 0

    APSStrictParseArguments {dDocAccount dDocAuthor dDocName dDocTitle dDocType dRevLabel dSecurityGroup icmsUsername icmsPassword primaryFile returnURL xComments xDocAuthor xDocDate xDivision xGroup xProject xTopicLevel1 xTopicLevel2 xTopicLevel3 xTopicLevel4}

    package require WS::Client
    package require base64
    
    #Do not allow titles that end in ", Rev. 1"
    set i [string last ", Rev." $dDocTitle]
    if {$i != -1} {
        set dDocTitle [string range $dDocTitle 0 [expr $i - 1]]
    }

    foreach opt "primaryFile dDocTitle icmsUsername icmsPassword" {
        if {[string length [set $opt]] == 0} {
            return -code error "APSSubmitFileToICMS: Please supply the $opt option"
        }
    }
    if {![file exists $primaryFile]} {
        return -code error "APSSubmitFileToICMS: Unable to open $primaryFile"
    }
    set fid [open $primaryFile rb]
    set data [read $fid]
    close $fid

    set authentication [list Basic [base64::encode ${icmsUsername}:${icmsPassword}]]
    if {[catch {::WS::Client::GetAndParseWsdl https://icmsdocs.aps.anl.gov/docs/groups/world/documents/data/checkin.wsdl [list Authorization $authentication]} results]} {
        return -code error "APSSubmitFileToICMS: invalid ICMS username or password"
    }
    
    ::WS::Client::CreateStubs CheckIn
    
    set primaryFile [list fileName $primaryFile fileContent [::base64::encode $data]]
    
    if {$xDocDate != ""} {
        if {[catch {clock scan $xDocDate} sec]} {
            return -code error "APSSubmitFileToICMS: invalid date format"
        } else {
            set xDocDate [clock format $sec -format {%D %l:%M %p}]
        }
    } else {
        set xDocDate [clock format [clock seconds] -format {%D %l:%M %p}]
    }

    set CustomDocMetaData [list property [list "name xDocAuthor value \"$xDocAuthor\"" \
                                            "name xDivision value \"$xDivision\"" \
                                            "name xGroup value \"$xGroup\"" \
                                            "name xProject value \"$xProject\"" \
                                            "name xComments value \"$xComments\"" \
                                            "name xTopicLevel1 value \"$xTopicLevel1\"" \
                                            "name xTopicLevel2 value \"$xTopicLevel2\"" \
                                            "name xTopicLevel3 value \"$xTopicLevel3\"" \
                                            "name xTopicLevel4 value \"$xTopicLevel4\"" \
                                            "name xDocDate value \"$xDocDate\""]]

    set extraProps [list property [list "name dRevLabel value \"$dRevLabel\""]]

    if {[llength $dDocName]} {
        if {[catch {APSICMSQueryRevisionNumber -icmsPassword $icmsPassword -icmsUsername $icmsUsername -dDocName $dDocName} revision]} {
            return -code error "APSSubmitFileToICMS: Could not find previous document to attach new revision to. $docNameAndRevision"
        } else {
            if {$dRevLabel <= $revision} {
                return -code error "APSSubmitFileToICMS: The revision number given is too low."
            }
            if {[catch {::CheckIn::CheckOutByName $dDocName $extraProps} results]} {
                return -code error "APSSubmitFileToICMS: $results"
            }
            
            set statusCode [dict get [dict get [dict get $results CheckOutByNameResult] StatusInfo] statusCode]
            
            if {$statusCode != 0} {
                set statusMessage [dict get [dict get [dict get $results CheckOutByNameResult] StatusInfo] statusMessage]
                return -code error $statusMessage
            }
        }
    } else {
        if {[catch {APSICMSQueryDocNameAndRevision -icmsPassword $icmsPassword -icmsUsername $icmsUsername -dDocTitle $dDocTitle -xDivision $xDivision -xGroup $xGroup} docNameAndRevision]} {
            if {$dRevLabel > 0} {
                return -code error "APSSubmitFileToICMS: Could not find previous document to attach new revision to. $docNameAndRevision"
            }
        } else {
            set dDocName [lindex $docNameAndRevision 0]
            set revision [lindex $docNameAndRevision 1]
            if {$dRevLabel <= $revision} {
                return -code error "APSSubmitFileToICMS: The revision number given is too low."
            }
            
            if {[catch {::CheckIn::CheckOutByName $dDocName $extraProps} results]} {
                return -code error "APSSubmitFileToICMS: $results"
            }
            
            set statusCode [dict get [dict get [dict get $results CheckOutByNameResult] StatusInfo] statusCode]
            
            if {$statusCode != 0} {
                set statusMessage [dict get [dict get [dict get $results CheckOutByNameResult] StatusInfo] statusMessage]
                return -code error $statusMessage
            }
            
        }
    }


    if {[catch {::CheckIn::CheckInUniversal $alternateFile $CustomDocMetaData $dDocAccount $dDocAuthor $dDocName $dDocTitle $dDocType $dSecurityGroup $extraProps $primaryFile} results]} {
        return -code error "APSSubmitFileToICMS: $results"
    }

    set statusCode [dict get [dict get [dict get $results CheckInUniversalResult] StatusInfo] statusCode]

    if {$statusCode != 0} {
        set statusMessage [dict get [dict get [dict get $results CheckInUniversalResult] StatusInfo] statusMessage]
        return -code error $statusMessage
    }
    if {$returnURL} {
        set dID [dict get [dict get $results CheckInUniversalResult] dID]
        set dRevClassID [dict get [dict get $results CheckInUniversalResult] dRevClassID]
        set url "https://icmsdocs.aps.anl.gov/docs/idcplg?IdcService=DOC_INFO&dID=${dID}&dDocName=APS_${dRevClassID}"
        return -code ok $url
    }
}

proc APSGetValidICMSSecurityGroupsHelp {} {
    return "Usage: APSGetValidICMSSecurityGroups \n\
-icmsUsername <string>\n\
-icmsPassword <string>\n\
Returns a list of valid security groups."
}

proc APSGetValidICMSSecurityGroups {args} {
    set icmsUsername ""
    set icmsPassword ""
    APSStrictParseArguments {icmsUsername icmsPassword}

    package require WS::Client
    package require base64

    set authentication [list Basic [base64::encode ${icmsUsername}:${icmsPassword}]]
    if {[catch {::WS::Client::GetAndParseWsdl https://icmsdocs.aps.anl.gov/docs/groups/world/documents/data/metadata.wsdl [list Authorization $authentication]} results]} {
        return -code error "APSGetValidICMSSecurityGroups: invalid ICMS username or password"
    }

    ::WS::Client::CreateStubs MetaData

    set output [::MetaData::DocMetaData "" 1]
    return [lindex [dict get [dict get $output DocMetaDataResult] SecurityGroups] 1]
}

proc APSGetValidICMSSecurityAccountsHelp {} {
    return "Usage: APSGetValidICMSSecurityAccounts \n\
-icmsUsername <string>\n\
-icmsPassword <string>\n\
Returns a list of valid security accounts."
}

proc APSGetValidICMSSecurityAccounts {args} {
    set icmsUsername ""
    set icmsPassword ""
    APSStrictParseArguments {icmsUsername icmsPassword}

    package require WS::Client
    package require base64

    set authentication [list Basic [base64::encode ${icmsUsername}:${icmsPassword}]]
    if {[catch {::WS::Client::GetAndParseWsdl https://icmsdocs.aps.anl.gov/docs/groups/world/documents/data/metadata.wsdl [list Authorization $authentication]} results]} {
        return -code error "APSGetValidICMSSecurityAccounts: invalid ICMS username or password"
    }

    ::WS::Client::CreateStubs MetaData

    set output [::MetaData::DocMetaData "" 1]
    return [lindex [dict get [dict get $output DocMetaDataResult] Accounts] 1]
}

proc APSGetValidICMSTechReportCategoriesHelp {} {
    return "Usage: APSGetValidICMSTechReportCategories \n\
Returns a list of valid ICMS categories."
}

proc APSGetValidICMSTechReportCategories {args} {
    set xDivision "ASD"
    set xGroup "AOP"
    APSStrictParseArguments {xDivision xGroup}
    if {[catch {exec /usr/local/oag/apps/bin/linux-x86_64/sddsprocess /home/helios/oagData/ICMS/ICMSCategories.sdds -match=parameter,xDivision=$xDivision -match=parameter,xGroup=$xGroup -pipe=out | /usr/local/oag/apps/bin/linux-x86_64/sdds2stream -pipe=in -par=Category} categories]} {
        return "Undefined"
    }
    return $categories
}

proc APSGetValidICMSTechReportSubCategoriesHelp {} {
    return "Usage: APSGetValidICMSTechReportCategories \n\t-category <string>\n\
Returns a list of valid ICMS sub-categories."
}

proc APSGetValidICMSTechReportSubCategories {args} {
    set xDivision "ASD"
    set xGroup "AOP"
    set category ""
    APSStrictParseArguments {xDivision xGroup category}

    if {[catch {exec /usr/local/oag/apps/bin/linux-x86_64/sddsprocess /home/helios/oagData/ICMS/ICMSCategories.sdds -match=parameter,Category=$category -match=parameter,xDivision=$xDivision -match=parameter,xGroup=$xGroup -pipe=out | /usr/local/oag/apps/bin/linux-x86_64/sdds2stream -pipe=in -col=SubCategory} subcategories]} {
        return "Undefined"
    }
    return $subcategories
}

proc APSPromptSTDINforICMSinfo {args} {
    global env

    #Password
    exec stty -echo echonl <@stdin
    puts -nonewline "\nPassword for $env(USER): "
    flush stdout
    gets stdin password
    exec stty echo -echonl <@stdin

    #Security Group
    if {[catch {APSGetValidICMSSecurityGroups \
                  -icmsUsername $env(USER) \
                  -icmsPassword $password} securityGroups]} {
        puts "Error: $securityGroups"
        exit
    }
    set selection ""
    while {![string is integer $selection] || \
             ([llength [string trim $selection]] != 1) || \
             ($selection < 0) || \
             ($selection >= [llength $securityGroups])} {
        puts "\nAvailable \"Security Groups\":"
        set i 0
        set default 0
        foreach group $securityGroups {
            if {$group == "APS"} {
                set default $i
            }
            puts "($i) $group"
            incr i
        }
        puts "(Default) [lindex $securityGroups $default]"
        puts -nonewline "Select a \"Security Group\": "
        flush stdout
        gets stdin selection
        set selection [string trim $selection]
        if {$selection == ""} {
            set selection $default
        }
    }
    set dSecurityGroup [lindex $securityGroups $selection]

    #Security Account
    if {[catch {APSGetValidICMSSecurityAccounts \
                  -icmsUsername $env(USER) \
                  -icmsPassword $password} securityAccounts]} {
        puts "Error: $securityAccounts"
        exit
    }
    set selection ""
    while {![string is integer $selection] || \
             ([llength [string trim $selection]] != 1) || \
             ($selection < 0) || \
             ($selection >= [llength $securityAccounts])} {
        puts "\nAvailable \"Security Accounts\":"
        set i 0
        set default 0
        foreach account $securityAccounts {
            if {$account == "APSShare/AcceleratorOperationsPhysics"} {
                set default $i
            }
            puts "($i) $account"
            incr i
        }
        puts "(Default) [lindex $securityAccounts $default]"
        puts -nonewline "Select a \"Security Account\": "
        flush stdout
        gets stdin selection
        set selection [string trim $selection]
        if {$selection == ""} {
            set selection $default
        }
    }
    set dDocAccount [lindex $securityAccounts $selection]

    #Division
    puts -nonewline "\nEnter a \"Division\". Default is ASD: "
    flush stdout
    gets stdin xDivision
    set xDivision [string trim $xDivision]
    if {$xDivision == ""} {
        set xDivision ASD
    }

    #Group
    puts -nonewline "\nEnter a \"Group\". Default is AOP: "
    flush stdout
    gets stdin xGroup
    set xGroup [string trim $xGroup]
    if {$xGroup == ""} {
        set xGroup AOP
    }

    #Categories
    set categories [APSGetValidICMSTechReportCategories]
    set selection ""
    while {![string is integer $selection] || \
             ([llength [string trim $selection]] != 1) || \
             ($selection < 0) || \
             ($selection >= [llength $categories])} {
        puts "\nAvailable \"Categories\":"
        set i 0
        foreach category $categories {
            puts "($i) $category"
            incr i
        }
        puts -nonewline "Select a \"Category\": "
        flush stdout
        gets stdin selection
        set selection [string trim $selection]
    }
    set xTopicLevel3 [lindex $categories $selection]

    #Sub-Categories
    set subcategories [APSGetValidICMSTechReportSubCategories -category $xTopicLevel3]
    set selection ""
    while {![string is integer $selection] || \
             ([llength [string trim $selection]] != 1) || \
             ($selection < 0) || \
             ($selection >= [llength $subcategories])} {
        puts "\nAvailable \"Sub-Categories\":"
        set i 0
        foreach subcategory $subcategories {
            puts "($i) $subcategory"
            incr i
        }
        puts -nonewline "Select a \"Sub-Category\": "
        flush stdout
        gets stdin selection
        set selection [string trim $selection]
    }
    set xTopicLevel4 [lindex $subcategories $selection]

    return "-dSecurityGroup \"$dSecurityGroup\" -dDocAccount \"$dDocAccount\" -icmsUsername \"$env(USER)\" -icmsPassword \"$password\" -xDivision \"$xDivision\" -xGroup \"$xGroup\" -xTopicLevel3 \"$xTopicLevel3\" -xTopicLevel4 \"$xTopicLevel4\""
}

proc APSICMSTechReportToSDDSHelp {} {
    return "Usage: APSICMSTechReportToSDDS \n\
-xDivision <division>\n\
-xGroup <group>\n\
-icmsPassword <string>\n\
-icmsUsername <string>\n\
-fileName <output>\n\
"
}

proc APSICMSTechReportToSDDS {args} {
    set xDivision "ASD"
    set xGroup "AOP"
    set icmsPassword ""
    set icmsUsername ""
    set fileName ""
    APSStrictParseArguments {xDivision xGroup icmsUsername icmsPassword fileName}

    if {![llength $fileName]} {
        return -code error "APSICMSTechReportToSDDS: no output filename given"
    }

    package require WS::Client
    package require base64
    
    set authentication [list Basic [base64::encode ${icmsUsername}:${icmsPassword}]]
    
    if {[catch {::WS::Client::GetAndParseWsdl https://icmsdocs.aps.anl.gov/docs/groups/world/documents/data/search.wsdl [list Authorization $authentication]} results]} {
        return -code error "APSICMSTechReportToSDDS: invalid ICMS username or password"
    }
    ::WS::Client::CreateStubs Search

#    set queryText "dDocType <matches> `Report` <AND> `TechReport` <in> xComments <AND> xDivision <matches> `$xDivision` <AND> xGroup <matches> `$xGroup`"
    if {($xDivision == "ASD") && (($xGroup == "AOP") || ($xGroup == "DIA"))} {
        set queryText "xDivision <matches> `$xDivision` <AND> xGroup <matches> `$xGroup` <AND> xTopicLevel1 <substring> `Technical Documentation` <AND> xTopicLevel2 <substring> `Technical Notes` <AND> `TechReport` <in> xComments"
    } else {
        set queryText "xDivision <matches> `$xDivision` <AND> xGroup <matches> `$xGroup` <AND> xTopicLevel1 <substring> `Technical Documentation` <AND> xTopicLevel2 <substring> `Technical Notes`"
    }
    set extraProps ""
    set resultCount 10000
    set sortField "dID"
    set sortOrder "Desc"

    set xDivision ""
    set xGroup ""

    if {[catch {::Search::AdvancedSearch $extraProps $queryText $resultCount $sortField $sortOrder} results]} {
        return -code error "APSICMSTechReportToSDDS: invalid ICMS username or password"
    }
    set statusCode [dict get [dict get [dict get $results AdvancedSearchResult] StatusInfo] statusCode]
    if {$statusCode != 0} {
        set statusMessage [dict get [dict get [dict get $results AdvancedSearchResult] StatusInfo] statusMessage]
        return -code error "APSICMSTechReportToSDDS: $statusMessage"
    }

    set searchresults [dict get [dict get $results AdvancedSearchResult] SearchResults]
    
    set data(ColumnNames) "dID dRevisionID dDocName dDocTitle dDocType dDocAuthor dSecurityGroup dDocAccount dExtension dWebExtension dRevLabel dInDate dOutDate dFormat dOriginalName url dGif webFileSize vaultFileSize alternateFileSize alternateFormat dPublishType dRendition1 dRendition2 "
    set data(ColumnInfo.dID) "type SDDS_LONG"
    set data(ColumnInfo.dRevisionID) "type SDDS_LONG"
    set data(ColumnInfo.dDocName) "type SDDS_STRING"
    set data(ColumnInfo.dDocTitle) "type SDDS_STRING"
    set data(ColumnInfo.dDocType) "type SDDS_STRING"
    set data(ColumnInfo.dDocAuthor) "type SDDS_STRING"
    set data(ColumnInfo.dSecurityGroup) "type SDDS_STRING"
    set data(ColumnInfo.dDocAccount) "type SDDS_STRING"
    set data(ColumnInfo.dExtension) "type SDDS_STRING"
    set data(ColumnInfo.dWebExtension) "type SDDS_STRING"
    set data(ColumnInfo.dRevLabel) "type SDDS_STRING"
    set data(ColumnInfo.dInDate) "type SDDS_STRING"
    set data(ColumnInfo.dOutDate) "type SDDS_STRING"
    set data(ColumnInfo.dFormat) "type SDDS_STRING"
    set data(ColumnInfo.dOriginalName) "type SDDS_STRING"
    set data(ColumnInfo.url) "type SDDS_STRING"
    set data(ColumnInfo.dGif) "type SDDS_STRING"
    set data(ColumnInfo.webFileSize) "type SDDS_LONG"
    set data(ColumnInfo.vaultFileSize) "type SDDS_LONG"
    set data(ColumnInfo.alternateFileSize) "type SDDS_LONG"
    set data(ColumnInfo.alternateFormat) "type SDDS_STRING"
    set data(ColumnInfo.dPublishType) "type SDDS_STRING"
    set data(ColumnInfo.dRendition1) "type SDDS_STRING"
    set data(ColumnInfo.dRendition2) "type SDDS_STRING"

    set first 1

    foreach line $searchresults {
        lappend dID [dict get $line dID]
        lappend dRevisionID [dict get $line dRevisionID]
        lappend dDocName [dict get $line dDocName]
        lappend dDocTitle [dict get $line dDocTitle]
        lappend dDocType [dict get $line dDocType]
        lappend dDocAuthor [dict get $line dDocAuthor]
        lappend dSecurityGroup [dict get $line dSecurityGroup]
        lappend dDocAccount [dict get $line dDocAccount]
        lappend dExtension [dict get $line dExtension]
        lappend dWebExtension [dict get $line dWebExtension]
        lappend dRevLabel [dict get $line dRevLabel]
        lappend dInDate [dict get $line dInDate]
        lappend dOutDate [dict get $line dOutDate]
        lappend dFormat [dict get $line dFormat]
        lappend dOriginalName [dict get $line dOriginalName]
        lappend url [dict get $line url]
        lappend dGif [dict get $line dGif]
        lappend webFileSize [dict get $line webFileSize]
        lappend vaultFileSize [dict get $line vaultFileSize]
        lappend alternateFileSize [dict get $line alternateFileSize]
        lappend alternateFormat [dict get $line alternateFormat]
        lappend dPublishType [dict get $line dPublishType]
        lappend dRendition1 [dict get $line dRendition1]
        lappend dRendition2 [dict get $line dRendition2]
        set CustomDocMetaData [dict get [dict get $line CustomDocMetaData] property]
        if {$first} {
            set first 0
            foreach customline $CustomDocMetaData {
                append customColumns "[lindex $customline 1] "
                set data(ColumnInfo.[lindex $customline 1]) "type SDDS_STRING"
            }
        }
        foreach cc $customColumns customline $CustomDocMetaData {
            lappend $cc [lindex $customline 3]
        }
    }
    append data(ColumnNames) $customColumns
    
    foreach column $data(ColumnNames) {
        set data(Column.$column) [list [set $column]]
    }
    sdds save $fileName data

    return
}

proc APSICMSUpdateDocInfoFromSDDSHelp {} {
    return "Usage: APSICMSUpdateDocInfoFromSDDS \n\
-icmsPassword <string>\n\
-icmsUsername <string>\n\
-fileName <input>\n\
"
}

proc APSICMSUpdateDocInfoFromSDDS {args} {
    set icmsPassword ""
    set icmsUsername ""
    set fileName ""
    set verbose 0
    APSStrictParseArguments {icmsUsername icmsPassword fileName verbose}

    if {![llength $fileName]} {
        return -code error "APSICMSUpdateDocInfoFromSDDS: no input filename given"
    }

    package require WS::Client
    package require base64
    
    set authentication [list Basic [base64::encode ${icmsUsername}:${icmsPassword}]]
    
    if {[catch {::WS::Client::GetAndParseWsdl https://icmsdocs.aps.anl.gov/docs/groups/world/documents/data/search.wsdl [list Authorization $authentication]} results]} {
        return -code error "APSICMSUpdateDocInfoFromSDDS: invalid ICMS username or password"
    }
    ::WS::Client::CreateStubs Search

    if {[catch {::WS::Client::GetAndParseWsdl https://icmsdocs.aps.anl.gov/docs/groups/world/documents/data/checkin.wsdl [list Authorization $authentication]} results]} {
        return -code error "APSICMSUpdateDocInfoFromSDDS: invalid ICMS username or password"
    }
    ::WS::Client::CreateStubs CheckIn
    
    if {[catch {sdds load $fileName data} results]} {
        return -code error "APSICMSUpdateDocInfoFromSDDS: $results"
    }
    
    set standardColumnNames ""
    set customColumnNames ""
    foreach cn $data(ColumnNames) {
        if {[string index $cn 0] == "x"} {
            lappend customColumnNames $cn
        } else {
            lappend standardColumnNames $cn
        }
    }

    set lines [llength [lindex $data(Column.dID) 0]]
    for {set n 0} {$n < $lines} {incr n} {
        foreach cn "dDocAccount dDocAuthor dDocName dDocTitle dDocType dID dRevLabel dSecurityGroup" {
            set $cn [lindex [lindex $data(Column.$cn) 0] $n]
        }

        #Do not allow titles that end in ", Rev. 1"
        set i [string last ", Rev." $dDocTitle]
        if {$i != -1} {
            set dDocTitle [string range $dDocTitle 0 [expr $i - 1]]
        }

        set CustomDocMetaData ""
        set extraProps ""
        foreach cn $customColumnNames {
            lappend CustomDocMetaData "name $cn value \"[lindex [lindex $data(Column.$cn) 0] $n]\""
        }
        set CustomDocMetaData [list property $CustomDocMetaData]
        
        if {$verbose} {
            puts "Updating $dDocTitle"
        }
        if {[catch {::CheckIn::UpdateDocInfo $CustomDocMetaData $dDocAccount $dDocAuthor $dDocName $dDocTitle $dDocType $dID $dRevLabel $dSecurityGroup $extraProps} results]} {
            return -code error "APSICMSUpdateDocInfoFromSDDS: $results"
        }
        
        set statusCode [dict get [dict get [dict get $results UpdateDocInfoResult] StatusInfo] statusCode]
        
        if {$statusCode != 0} {
            set statusMessage [dict get [dict get [dict get $results UpdateDocInfoResult] StatusInfo] statusMessage]
            return -code error $statusMessage
        }
    }
}

proc APSICMSQueryDocNameAndRevisionHelp {} {
    return "Usage: APSICMSQueryDocNameAndRevision \n\
-dDocTitle <title>\n\
-dDocType <type>\n\
-xComments <comments>\n\
-xDivision <division>\n\
-xGroup <group>\n\
-icmsPassword <string>\n\
-icmsUsername <string>\n\
"
}

proc APSICMSQueryDocNameAndRevision {args} {
    set icmsPassword ""
    set icmsUsername ""
    set dDocTitle ""
    set dDocType ""
    set xComments ""
    set xDivision ""
    set xGroup ""
    APSStrictParseArguments {icmsUsername icmsPassword dDocTitle dDocType xComments xDivision xGroup}

    package require WS::Client
    package require base64
    
    set authentication [list Basic [base64::encode ${icmsUsername}:${icmsPassword}]]
    
    if {[catch {::WS::Client::GetAndParseWsdl https://icmsdocs.aps.anl.gov/docs/groups/world/documents/data/search.wsdl [list Authorization $authentication]} results]} {
        return -code error "APSICMSQueryDocNameAndRevision: invalid ICMS username or password"
    }
    ::WS::Client::CreateStubs Search

    set queryText ""
    if {[llength $dDocTitle]} {
        lappend queryText "dDocTitle <matches> `$dDocTitle`"
    }
    if {[llength $dDocType]} {
        lappend queryText "dDocType <matches> `$dDocType`"
    }
    if {[llength $xComments]} {
        lappend queryText "`$xComments` <in> xComments"
    }
    if {[llength $xDivision]} {
        lappend queryText "xDivision <matches> `$xDivision`"
    }
    if {[llength $xGroup]} {
        lappend queryText "xGroup <matches> `$xGroup`"
    }
    lappend queryText "xTopicLevel1 <substring> `Technical Documentation`"
    lappend queryText "xTopicLevel2 <substring> `Technical Notes`"
    set queryText [join $queryText "<AND>"]
    set extraProps ""
    set resultCount 2
    set sortField "dID"
    set sortOrder "Desc"

    if {[catch {::Search::AdvancedSearch $extraProps $queryText $resultCount $sortField $sortOrder} results]} {
        return -code error "APSICMSQueryDocNameAndRevision: invalid ICMS username or password"
    }
    set statusCode [dict get [dict get [dict get $results AdvancedSearchResult] StatusInfo] statusCode]
    if {$statusCode != 0} {
        set statusMessage [dict get [dict get [dict get $results AdvancedSearchResult] StatusInfo] statusMessage]
        return -code error "APSICMSQueryDocNameAndRevision: $statusMessage"
    }

    set searchresults [dict get [dict get $results AdvancedSearchResult] SearchResults]

    if {[llength $searchresults] == 0} {
        return -code error "APSICMSQueryDocNameAndRevision: No unique match found"
    }
    if {[llength $searchresults] > 1} {
        return -code error "APSICMSQueryDocNameAndRevision: No unique match found"
    }
    
    foreach line $searchresults {
        lappend dDocName [dict get $line dDocName]
        lappend dRevLabel [dict get $line dRevLabel]
    }
    return "$dDocName $dRevLabel"
}

proc APSICMSQueryRevisionNumberHelp {} {
    return "Usage: APSICMSQueryRevisionNumber \n\
-dDocName <ICMS number>\n\
-icmsPassword <string>\n\
-icmsUsername <string>\n\
"
}

proc APSICMSQueryRevisionNumber {args} {
    set icmsPassword ""
    set icmsUsername ""
    set dDocName ""
    APSStrictParseArguments {icmsUsername icmsPassword dDocName}

    package require WS::Client
    package require base64
    
    set authentication [list Basic [base64::encode ${icmsUsername}:${icmsPassword}]]
    
    if {[catch {::WS::Client::GetAndParseWsdl  https://icmsdocs.aps.anl.gov/docs/groups/world/documents/data/search.wsdl [list Authorization $authentication]} results]} {
        return -code error "APSICMSQueryRevisionNumber: invalid ICMS username or password"
    }
    ::WS::Client::CreateStubs Search

    set queryText ""
    if {[llength $dDocName]} {
        lappend queryText "dDocName <matches> `$dDocName`"
    }
    set queryText [join $queryText "<AND>"]
    set extraProps ""
    set resultCount 2
    set sortField "dID"
    set sortOrder "Desc"

    if {[catch {::Search::AdvancedSearch $extraProps $queryText $resultCount $sortField $sortOrder} results]} {
        return -code error "APSICMSQueryRevisionNumber: invalid ICMS username or password"
    }
    set statusCode [dict get [dict get [dict get $results AdvancedSearchResult] StatusInfo] statusCode]
    if {$statusCode != 0} {
        set statusMessage [dict get [dict get [dict get $results AdvancedSearchResult] StatusInfo] statusMessage]
        return -code error "APSICMSQueryRevisionNumber: $statusMessage"
    }

    set searchresults [dict get [dict get $results AdvancedSearchResult] SearchResults]

    if {[llength $searchresults] == 0} {
        return -code error "APSICMSQueryRevisionNumber: No unique match found"
    }
    if {[llength $searchresults] > 1} {
        return -code error "APSICMSQueryRevisionNumber: No unique match found"
    }
    
    foreach line $searchresults {
        lappend dDocName [dict get $line dDocName]
        lappend dRevLabel [dict get $line dRevLabel]
    }
    return "$dRevLabel"
}

proc APSICMSQueryVaultFileSizeHelp {} {
    return "Usage: APSICMSQueryVaultFileSize \n\
-dDocName <ICMS ID Number>\n\
-dRevLabel <revision>\n\
-icmsPassword <string>\n\
-icmsUsername <string>\n\
"
}

proc APSICMSQueryVaultFileSize {args} {
    set icmsPassword ""
    set icmsUsername ""
    set dDocName ""
    set dRevLabel ""
    APSStrictParseArguments {icmsUsername icmsPassword dDocName dRevLabel}

    package require WS::Client
    package require base64
    
    set authentication [list Basic [base64::encode ${icmsUsername}:${icmsPassword}]]
    
    if {[catch {::WS::Client::GetAndParseWsdl https://icmsdocs.aps.anl.gov/docs/groups/world/documents/data/search.wsdl [list Authorization $authentication]} results]} {
        return -code error "APSICMSQueryVaultFileSize: invalid ICMS username or password"
    }
    ::WS::Client::CreateStubs Search

    set queryText ""
    if {[llength $dDocName]} {
        lappend queryText "dDocName <matches> `$dDocName`"
    }
    if {[llength $dRevLabel]} {
        lappend queryText "dRevLabel <matches> `$dRevLabel`"
    }
    set queryText [join $queryText "<AND>"]
    set extraProps ""
    set resultCount 2
    set sortField "dID"
    set sortOrder "Desc"

    if {[catch {::Search::AdvancedSearch $extraProps $queryText $resultCount $sortField $sortOrder} results]} {
        return -code error "APSICMSQueryVaultFileSize: invalid ICMS username or password"
    }
    set statusCode [dict get [dict get [dict get $results AdvancedSearchResult] StatusInfo] statusCode]
    if {$statusCode != 0} {
        set statusMessage [dict get [dict get [dict get $results AdvancedSearchResult] StatusInfo] statusMessage]
        return -code error "APSICMSQueryVaultFileSize: $statusMessage"
    }

    set searchresults [dict get [dict get $results AdvancedSearchResult] SearchResults]

    if {[llength $searchresults] == 0} {
        return -code error "APSICMSQueryVaultFileSize: No unique match found"
    }
    if {[llength $searchresults] > 1} {
        return -code error "APSICMSQueryVaultFileSize: No unique match found"
    }
    
    foreach line $searchresults {
        lappend vaultFileSize [dict get $line vaultFileSize]
    }
    return "$vaultFileSize"
}

proc APSICMSQueryTopicLevelsHelp {} {
    return "Usage: APSICMSQueryTopicLevels \n\
-dDocName <ICMS ID Number>\n\
-dRevLabel <revision>\n\
-icmsPassword <string>\n\
-icmsUsername <string>\n\
"
}

proc APSICMSQueryTopicLevels {args} {
    set icmsPassword ""
    set icmsUsername ""
    set dDocName ""
    set dRevLabel ""
    APSStrictParseArguments {icmsUsername icmsPassword dDocName dRevLabel}

    package require WS::Client
    package require base64
    
    set authentication [list Basic [base64::encode ${icmsUsername}:${icmsPassword}]]
    
    if {[catch {::WS::Client::GetAndParseWsdl https://icmsdocs.aps.anl.gov/docs/groups/world/documents/data/search.wsdl [list Authorization $authentication]} results]} {
        return -code error "APSICMSQueryTopicLevels: invalid ICMS username or password"
    }
    ::WS::Client::CreateStubs Search

    set queryText ""
    if {[llength $dDocName]} {
        lappend queryText "dDocName <matches> `$dDocName`"
    }
    if {[llength $dRevLabel]} {
        lappend queryText "dRevLabel <matches> `$dRevLabel`"
    }
    set queryText [join $queryText "<AND>"]
    set extraProps ""
    set resultCount 2
    set sortField "dID"
    set sortOrder "Desc"

    if {[catch {::Search::AdvancedSearch $extraProps $queryText $resultCount $sortField $sortOrder} results]} {
        return -code error "APSICMSQueryTopicLevels: invalid ICMS username or password"
    }
    set statusCode [dict get [dict get [dict get $results AdvancedSearchResult] StatusInfo] statusCode]
    if {$statusCode != 0} {
        set statusMessage [dict get [dict get [dict get $results AdvancedSearchResult] StatusInfo] statusMessage]
        return -code error "APSICMSQueryTopicLevels: $statusMessage"
    }

    set searchresults [dict get [dict get $results AdvancedSearchResult] SearchResults]

    if {[llength $searchresults] == 0} {
        return -code error "APSICMSQueryTopicLevels: No unique match found"
    }
    if {[llength $searchresults] > 1} {
        return -code error "APSICMSQueryTopicLevels: No unique match found"
    }
    
    foreach line $searchresults {
        set CustomDocMetaData [dict get [dict get $line CustomDocMetaData] property]
    }
    foreach customline $CustomDocMetaData {
        set cc [lindex $customline 1]
        if {$cc == "xTopicLevel1"} {
            set xTopicLevel1 [lindex $customline 3]
        } elseif {$cc == "xTopicLevel2"} {
            set xTopicLevel2 [lindex $customline 3]
        } elseif {$cc == "xTopicLevel3"} {
            set xTopicLevel3 [lindex $customline 3]
        } elseif {$cc == "xTopicLevel4"} {
            set xTopicLevel4 [lindex $customline 3]
        }
    }
    return "\"$xTopicLevel1\" \"$xTopicLevel2\" \"$xTopicLevel3\" \"$xTopicLevel4\""
}

proc APSICMSDocInfoToSDDSHelp {} {
    return "Usage: APSICMSDocInfoToSDDS \n\
-dDocName <ICMS ID Number>\n\
-dRevLabel <revision>\n\
-icmsPassword <string>\n\
-icmsUsername <string>\n\
-fileName <output>\n\
"
}

proc APSICMSDocInfoToSDDS {args} {
    set icmsPassword ""
    set icmsUsername ""
    set dDocName ""
    set dRevLabel ""
    set fileName ""
    APSStrictParseArguments {icmsUsername icmsPassword dDocName dRevLabel fileName}

    if {![llength $fileName]} {
        return -code error "APSICMSDocInfoToSDDS: no output filename given"
    }

    package require WS::Client
    package require base64
    
    set authentication [list Basic [base64::encode ${icmsUsername}:${icmsPassword}]]
    
    if {[catch {::WS::Client::GetAndParseWsdl https://icmsdocs.aps.anl.gov/docs/groups/world/documents/data/search.wsdl [list Authorization $authentication]} results]} {
        return -code error "APSICMSDocInfoToSDDS: invalid ICMS username or password"
    }
    ::WS::Client::CreateStubs Search

    set queryText ""
    if {[llength $dDocName]} {
        lappend queryText "dDocName <matches> `$dDocName`"
    }
    if {[llength $dRevLabel]} {
        lappend queryText "dRevLabel <matches> `$dRevLabel`"
    }
    set queryText [join $queryText "<AND>"]
    set extraProps ""
    set resultCount 2
    set sortField "dID"
    set sortOrder "Desc"

    if {[catch {::Search::AdvancedSearch $extraProps $queryText $resultCount $sortField $sortOrder} results]} {
        return -code error "APSICMSDocInfoToSDDS: invalid ICMS username or password"
    }
    set statusCode [dict get [dict get [dict get $results AdvancedSearchResult] StatusInfo] statusCode]
    if {$statusCode != 0} {
        set statusMessage [dict get [dict get [dict get $results AdvancedSearchResult] StatusInfo] statusMessage]
        return -code error "APSICMSDocInfoToSDDS: $statusMessage"
    }

    set searchresults [dict get [dict get $results AdvancedSearchResult] SearchResults]

    if {[llength $searchresults] == 0} {
        return -code error "APSICMSDocInfoToSDDS: No unique match found"
    }
    if {[llength $searchresults] > 1} {
        return -code error "APSICMSDocInfoToSDDS: No unique match found"
    }

    set dDocName ""
    set dRevLabel ""

    set data(ColumnNames) "dID dRevisionID dDocName dDocTitle dDocType dDocAuthor dSecurityGroup dDocAccount dExtension dWebExtension dRevLabel dInDate dOutDate dFormat dOriginalName url dGif webFileSize vaultFileSize alternateFileSize alternateFormat dPublishType dRendition1 dRendition2 "
    set data(ColumnInfo.dID) "type SDDS_LONG"
    set data(ColumnInfo.dRevisionID) "type SDDS_LONG"
    set data(ColumnInfo.dDocName) "type SDDS_STRING"
    set data(ColumnInfo.dDocTitle) "type SDDS_STRING"
    set data(ColumnInfo.dDocType) "type SDDS_STRING"
    set data(ColumnInfo.dDocAuthor) "type SDDS_STRING"
    set data(ColumnInfo.dSecurityGroup) "type SDDS_STRING"
    set data(ColumnInfo.dDocAccount) "type SDDS_STRING"
    set data(ColumnInfo.dExtension) "type SDDS_STRING"
    set data(ColumnInfo.dWebExtension) "type SDDS_STRING"
    set data(ColumnInfo.dRevLabel) "type SDDS_STRING"
    set data(ColumnInfo.dInDate) "type SDDS_STRING"
    set data(ColumnInfo.dOutDate) "type SDDS_STRING"
    set data(ColumnInfo.dFormat) "type SDDS_STRING"
    set data(ColumnInfo.dOriginalName) "type SDDS_STRING"
    set data(ColumnInfo.url) "type SDDS_STRING"
    set data(ColumnInfo.dGif) "type SDDS_STRING"
    set data(ColumnInfo.webFileSize) "type SDDS_LONG"
    set data(ColumnInfo.vaultFileSize) "type SDDS_LONG"
    set data(ColumnInfo.alternateFileSize) "type SDDS_LONG"
    set data(ColumnInfo.alternateFormat) "type SDDS_STRING"
    set data(ColumnInfo.dPublishType) "type SDDS_STRING"
    set data(ColumnInfo.dRendition1) "type SDDS_STRING"
    set data(ColumnInfo.dRendition2) "type SDDS_STRING"

    set first 1
    foreach line $searchresults {
        lappend dID [dict get $line dID]
        lappend dRevisionID [dict get $line dRevisionID]
        lappend dDocName [dict get $line dDocName]
        lappend dDocTitle [dict get $line dDocTitle]
        lappend dDocType [dict get $line dDocType]
        lappend dDocAuthor [dict get $line dDocAuthor]
        lappend dSecurityGroup [dict get $line dSecurityGroup]
        lappend dDocAccount [dict get $line dDocAccount]
        lappend dExtension [dict get $line dExtension]
        lappend dWebExtension [dict get $line dWebExtension]
        lappend dRevLabel [dict get $line dRevLabel]
        lappend dInDate [dict get $line dInDate]
        lappend dOutDate [dict get $line dOutDate]
        lappend dFormat [dict get $line dFormat]
        lappend dOriginalName [dict get $line dOriginalName]
        lappend url [dict get $line url]
        lappend dGif [dict get $line dGif]
        lappend webFileSize [dict get $line webFileSize]
        lappend vaultFileSize [dict get $line vaultFileSize]
        lappend alternateFileSize [dict get $line alternateFileSize]
        lappend alternateFormat [dict get $line alternateFormat]
        lappend dPublishType [dict get $line dPublishType]
        lappend dRendition1 [dict get $line dRendition1]
        lappend dRendition2 [dict get $line dRendition2]
        set CustomDocMetaData [dict get [dict get $line CustomDocMetaData] property]
        if {$first} {
            set first 0
            foreach customline $CustomDocMetaData {
                append customColumns "[lindex $customline 1] "
                set data(ColumnInfo.[lindex $customline 1]) "type SDDS_STRING"
            }
        }
        foreach cc $customColumns customline $CustomDocMetaData {
            lappend $cc [lindex $customline 3]
        }
    }
    append data(ColumnNames) $customColumns
    
    foreach column $data(ColumnNames) {
        set data(Column.$column) [list [set $column]]
    }
    sdds save $fileName data

    return
}
