#!/usr/bin/env python
#
# Copyright (C) 2003 Stefan Seefeld
# All rights reserved.
# Licensed to the public under the terms of the GNU LGPL (>= 2),
# see the file COPYING for details.
#

from Synopsis import config
from Synopsis.getoptions import get_options
from Synopsis import AST
from Synopsis.Processor import Processor, Composite, Error

import sys, os, os.path, string, getopt

def error(msg):
   """Write an error message and exit."""
   sys.stderr.write(msg)
   sys.stderr.write('\n')
   sys.exit(-1)

def __import__(name, verbose):
   """Import a named processor. Instead of returning the module, this
   reimplementation returns the processor itself. Exits on error."""

   from Synopsis.import_processor import import_processor
   try:
      return import_processor(name)

   except ImportError, msg:
      if verbose:
         print 'Unable to import %s'%name
         print 'Reason :', msg
      else:
         print 'Error : no processor \'%s\''%'.'.join(name.split('.')[-2:])
      sys.exit(-1)

def usage():
   """Print a little usage text"""

   print 'Usage : %s [options] <input files>'%sys.argv[0]
   print """
List of options:

  -h, --help             help
  -V, --version          print version info and exit
  -v  --verbose          operate verbosely
  -d  --debug            operate in debug mode
  -o, --output           output file / directory
  -p, --parser           select a parser
  -Wp,<arg>[,<arg>...]   send args to the parser
  -l, --linker           link
  -Wl,<arg>[,<arg>...]   send args to the linker
  -f, --formatter        select a formatter
  -Wf,<arg>[,<arg>...]   send args to the formatter
  -I <path>              specify include path
  -D <macro>             specify macro for the parser

  -j  --javadoc          process javadoc tags in comments
"""
   
def get_opt(argv):
   """Parse command line options and translate them to
   processor commands and arguments."""

   parser = None
   parser_opts = {}
   linker = None
   linker_opts = {}
   formatter = None
   formatter_opts = {}
   options = {}
   help = False

   javadoc = False

   opts, args = getopt.getopt(argv,
                              'o:p:l:f:I:D:W:jvhVd',
                              ['output=',
                               'parser=', 'linker=', 'formatter=',
                               'version', 'help', 'verbose', 'debug',
                               'javadoc'])

   for o, a in opts:
      if o == '-V' or o == '--version':
         print 'synopsis version %s'%config.version
         sys.exit(0)
         
      if o == '-v' or o == '--verbose':
         options['verbose'] = True

      if o == '-d' or o == '--debug':
         options['debug'] = True

      elif o == '-o' or o == '--output':
         options['output'] = a

      elif o == '-p' or o == '--parser':
         parser = __import__('Synopsis.Parsers.%s.Parser'%a,
                             'verbose' in options)

      elif o == '-l' or o == '--linker':
         linker = __import__('Synopsis.Processors.Linker',
                             'verbose' in options)
         linker_opts['processors'] = map(lambda x: __import__('Synopsis.Processors.%s'%x,
                                                              'verbose' in options)(),
                                         string.split(a, ','))

      elif o == '-f' or o == '--formatter':
         formatter = __import__('Synopsis.Formatters.%s.Formatter'%a,
                                'verbose' in options)

      elif o == '-I':
         if not parser_opts.get('cppflags'): parser_opts['cppflags'] = []
         parser_opts['cppflags'].append('-I%s'%a)

      elif o == '-D':
         if not parser_opts.get('cppflags'): parser_opts['cppflags'] = []
         parser_opts['cppflags'].append('-D%s'%a)

      elif o == '-W':
         if a[0] == "p":
            for o,a in get_options(a[2:].split(',')):
               parser_opts[o] = a
         elif a[0] == "l":
            for o,a in get_options(a[2:].split(',')):
               linker_opts[o] = a
         elif a[0] == "f":
            for o,a in get_options(a[2:].split(',')):
               formatter_opts[o] = a

      elif o == '-h' or o == '--help':
         help = True

      elif o == '-j' or o == '--javadoc':
         javadoc = True

   if help:
      for p in parser, linker, formatter:
         if not p: continue
         processor = p()
         print "Parameters for processor '%s':"%p.__module__
         parameters = processor.get_parameters()
         tab = max(map(lambda x:len(x), parameters.keys()))
         for p in parameters:
            print "   %-*s     %s"%(tab, p, parameters[p].doc)
      if not (parser or linker or formatter):
         usage()
      sys.exit(0)

   # quick hack: if the parser is Cpp, rename the 'cppflags'
   # options to just 'flags'
   if parser and parser.__module__ == 'Synopsis.Parsers.Cpp.Parser':
      if parser_opts.has_key('cppflags'):
         parser_opts['flags'] = parser_opts['cppflags']
         del parser_opts['cppflags']

   options['input'] = args

   #now instantiate the processor
   processors = []
   if parser:
      processors.append(parser(**parser_opts))
   if linker:
      processors.append(linker(**linker_opts))
   if formatter:

      if string.split(formatter.__module__, '.')[-2] == 'HTML':
         #treat frequent flags at this level for convenience
         if javadoc:
            from Synopsis.Formatters.HTML import Comments
            # add javadoc to the default list of comment formatters
            formatter_opts['comment_formatters'] = [Comments.QuoteHTML(),
                                                    Comments.Section(),
                                                    Comments.Javadoc()]
      processors.append(formatter(**formatter_opts))

   processor = Composite(*processors, **options)

   return processor

def main():
   processor = get_opt(sys.argv[1:])
   processor.process(AST.AST())

if __name__ == '__main__':

   try:
      main()
   except KeyError, e:
      error('missing argument "%s"'%e)
   except Error, e:
      error(str(e))
   except KeyboardInterrupt, e:
      print 'KeyboardInterrupt'
