#!/usr/bin/env tclsh
#
#   Dionysus is a search engine for scientific constants and 
#   engineering parameters.
#
#   Copyright (C) 2009, 2010 Jean Michel Sellier
#   <jeanmichel.sellier@gmail.com>
# 
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 3, or (at your option)
#   any later version.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# created : 08 sep.2009, Jean Michel Sellier, West Lafayette, IN, USA
# last modified : 14 aug.2010, Daniel Kraft, Graz, Austria
#
# how to use this command
# > ./dionysus DB.ddb value_name option
# for more informations type
# > ./dionysus --help
# to list the values in a database
# > ./dionysus DB.ddb --list-values FORMAT
# where FORMAT is HTML or ASCII

# help option
if {[lindex $argv 0]=="--help" || [lindex $argv 0]=="--h"} {
 puts "Usage:"
 puts "> dionysus DB.bb constant_name info"
 puts "to know the info of constant_name in DB.bb database."
 puts ""
 puts "> dionysus DB.bb --list-values FORMAT"
 puts "to see the complete list of constants in the specified FORMAT in DB.bb database."
 puts ""
 puts ">dionysus --version"
 puts "to see the version of this package."
 puts ""
 puts "> dionysus --help"
 puts "to see this help message."
 puts ""
 puts "Example:"
 puts "> dionysus databases/universal.ddb electron_mass value"
 puts ""
 exit 1
}

# version option
if {[lindex $argv 0]=="--version" || [lindex $argv 0]=="--v"} {
 puts "Dionysus version 1.3.0"
 puts ""
 puts "Copyright (C) 2009, 2010 Sellier Jean Michel."
 puts "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A"
 puts "PARTICULAR PURPOSE."
 puts "You may redistribute copies of GNU Dionysus under the terms"
 puts "of the GNU General Public License."
 puts "For more information about these matters, see the file named COPYING."
 puts ""
 exit 1
}

# check the number of specified arguments
set num [llength $argv]
if {$num!=3} {
 puts "the number of arguments is wrong."
 puts "please use --help option for more informations."
 exit 1
}

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# THIS IS WHERE THE --list-values OPTION IS IMPLEMENTED
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
if {[lindex $argv 1]=="--list-values"} {

 # check if the specified format is valid
 # (for now the onlly two valid formats are ASCII and HTML)
 set format [string tolower [lindex $argv 2]]
 if {$format!="ascii" && $format!="html" && $format!="fortran"} {
  puts "this format is not supported."
  puts "the supported formats are:"
  puts "- ASCII"
  puts "- HTML"
  puts "- Fortran"
  exit 1
 }

 # check and open the specified ASCII DB file
 set dbname [lindex $argv 0]
 if { [catch {set fp [open $dbname "r"]}]} {
  puts "the specified DB file does not exist or cannot be open"
  close $fp
  exit 1
 }

 # read the entire file in a string
 set data [read $fp]
 if {$data==""} {
  puts "the specified DB file is empty!"
  close $fp
  exit 1
 }

 # close the file properly
 close $fp

 # split the entire variable "data" into single rows
 set rows [split $data "\n"]
 if {$format=="ascii"} {
  puts "Item(s) founds in the database:"
  puts "-------------------------------"
 }
 if {$format=="html"} {
  puts "<html><h3>Database: $dbname</h3><table border=2>"
  puts "<tr><td>Name(s)</td><td>Value</td><td>Units</td><td>Description</td></tr>"
 }
 if {$format=="fortran"} {
  set modname "dionysus_constants"
  set already_written {}
  puts "! This file is generated by GNU Dionysus from:\n! $dbname"
  puts "! You may want to change the module-name and/or precision used.\n"
  puts "MODULE $modname"
  puts "  IMPLICIT NONE\n"
  puts "  INTEGER, PARAMETER :: prec = KIND(1.0d0)"
  puts "  PRIVATE :: prec\n"
 }

 # set the counter to zero
 set counter 0

 # split every row and check if they start by a "def" tag
 foreach row $rows {
  set constname ""
  set splitted [split $row "="]
  set first [string tolower [lindex $splitted 0]]
  set dummy [split $first " "]
  foreach elem $dummy {
   if {$elem=="name"} {
    incr counter
    set minilist [split [lindex $splitted 1] "\""]
    if {$format=="ascii"} {
     foreach minielem $minilist {
      if {[lsearch $minielem "||"]==-1 && $minielem!=""} {
       puts -nonewline "-- $minielem --  "
      }
     }
     puts ""
    }; # end of ASCII format
    if {$format=="fortran"} {
     set names {}
     foreach minielem $minilist {
      if {[lsearch $minielem "||"]==-1 && $minielem!=""} {
       # some names are not allowed as Fortran identifiers!
       if {[regexp {^[a-zA-Z_][a-zA-Z0-9_]*$} $minielem]} {
        lappend names $minielem
       } else {
        puts stderr "ignoring $minielem, which is invalid in Fortran"
       }
      }
     }
     if {[llength $names]>0} {
      set constname [lindex $names 0]
      exec dionysus $dbname $constname value > dum.out
      set fp [open "dum.out" "r"]
      set dum [read -nonewline $fp]
      close $fp
      if {$dum!="" && [regexp {^[+-]?\d*(\.\d*)?([eE][+-]?\d+)?$} $dum]} {
       foreach n $names {
        if {$n ni $already_written} {
          puts "  REAL(KIND=prec), PARAMETER :: $n = $dum\_prec"
          lappend already_written $n
        } else {
          puts stderr "duplicate variable $n"
        }
       }
      } else {
       puts stderr "invalid constant '$dum'"
      }
     }
    }; # end of Fortran format
    if {$format=="html"} {
     puts "<tr><td>"
     set cc 0
     foreach minielem $minilist {
      if {[lsearch $minielem "||"]==-1 && $minielem!=""} {
       global constname
       global cc
       if {$cc=="0"} {
        set constname $minielem
       }
       incr cc
       puts "$minielem<br>"
      }
     }
     puts "</td>"
     # show the value
     exec dionysus $dbname $constname value > dum.out
     set fp [open "dum.out" "r"]
     set dum [read -nonewline $fp]
     if {$dum==""} {
      global dum
      set dum "not specified"
     }
     close $fp
     puts "<td> $dum </td>"
     # show the units
     exec dionysus $dbname $constname units > dum.out
     set fp [open "dum.out" "r"]
     set dum [read -nonewline $fp]
     if {$dum==""} {
      global dum
      set dum "not specified"
     }
     close $fp
     puts "<td> $dum </td>"
     # show the description
     exec dionysus $dbname $constname description > dum.out
     set fp [open "dum.out" "r"]
     set dum [read -nonewline $fp]
     if {$dum==""} {
      global dum
      set dum "not specified"
     }
     close $fp
     puts "<td> $dum </td>"
     puts "</tr>"
    }; # end of HTML format
   }
  }
 }

 # eventually remove auxiliary files
 exec rm -rf dum.out

 # show the number of found items or created files
 if {$format=="ascii"} {
  puts "the number of found items is: $counter"
 }
 if {$format=="html"} {
  puts "</table>"
  puts "<h3>the number of items in the database is: $counter</h3>"
  puts "</html>"
 }
 if {$format=="fortran"} {
  puts "END MODULE $modname\n"
  puts "! There were $counter items found."
 }

 # if we are here everything went fine
 exit 0
}

# END OF --list-values OPTION

# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# THIS IS WHERE THE QUERY IS PROCESSED
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

# check and open the specified ASCII DB file
if { [catch {set fp [open [lindex $argv 0] "r"]}]} {
 puts "the specified DB file does not exist or cannot be open"
 exit 1
}

# once we are sure the file exists we scan it
# value name and property
set specname [string tolower [lindex $argv 1]]
set property [string tolower [lindex $argv 2]]

# read the entire file in a string
set data [read $fp]
if {$data==""} {
 puts "the specified DB file is empty!"
 exit 1
}

# split the entire variable "data" into single rows
set rows [split $data "\n"]

# scan every single row and look for what is required
set found 0
set namef 0
for {set i 1} {$i<=[llength $rows]} {incr i} {
 global found
 global namef
 set row [lindex $rows [expr $i-1]]
 # search for an eventual definition
 # parse the row only if it's not a comment
 if {[lindex [split $row " "] 0]!="#"} {
  foreach dum [split $row " "] {
   if {[string tolower $dum]=="def"} {
    # if there is a "def" which does not finish by a "end" then error
    if {$found==1} {
     puts "The DB is not defined correctly. Row $i is \"def\" while it should be \"end\"."
     exit 1
    } else {
     # if everything is all right then set the flag to 1
     set found 1
    }
   }
  }

  # the following row is needed by both "property" and "value"
  set commands [split $row "="]

  # if the word is $property
  if {$namef==1} {
   set comand [split [lindex $commands 0] " "]
   if {[string tolower [lindex $comand 2]]==[string tolower $property]} {
    set ret [lindex $commands 1]
    set primo  [expr [string first "\"" $ret]+1]
    set ultimo [expr [string last "\"" $ret]-1]
    puts [string range $ret $primo $ultimo]
    set $namef 0
    exit 0
   }
  }
  # look for the name of the variable
  if {[string first "name" [string tolower [lindex $commands 0]]]!=-1 && $namef==0} {
   set names [lindex [split $row "="] 1]
   foreach name [split $names "||"] {
    set name [string tolower $name]
    # toggles the double quotes in names
    set primo  [expr [string first "\"" $name]+1]
    set ultimo [expr [string last "\"" $name]-1]
    # "nome" is "name" without the initial and final double quotes
    set nome [string range $name $primo $ultimo]
    if {$nome==$specname} {
     set namef 1
    }
   }
  }
  # if the word is "end"
  foreach dum [split $row " "] {
   if {[string tolower $dum]=="end"} {
    set found 0
    set namef 0
   }
  }
 }
}

close $fp
exit 0

# END OF QUERY PROCESSING
