text: """natcap.invest.reporting package."""
  
  import os
  import logging
  import codecs
  import re
  from types import StringType
  import copy
  
  from ... import invest
  import natcap.invest.pygeoprocessing_0_3_3.geoprocessing
  import table_generator
  
  LOGGER = logging.getLogger('natcap.invest.reporting')
  REPORTING_DATA = os.path.join(invest.local_dir(__file__), 'reporting_data/')
  JQUERY_URI = os.path.join(REPORTING_DATA, 'jquery-1.10.2.min.js')
  SORTTABLE_URI = os.path.join(REPORTING_DATA, 'sorttable.js')
  TOTALS_URI = os.path.join(REPORTING_DATA, 'total_functions.js')
  
  u = lambda string: unicode(string, 'utf-8')
  
  
  def generate_report(args):
      """Generate an html page from the arguments given in 'reporting_args'
  
          reporting_args[title] - a string for the title of the html page
              (required)
  
          reporting_args[sortable] - a boolean value indicating whether
              the sorttable.js library should be added for table sorting
              functionality (optional)
  
          reporting_args[totals] - a boolean value indicating whether
              the totals_function.js script should be added for table totals
              functionality (optional)
  
          reporting_args[out_uri] - a URI to the output destination for the html
              page (required)
  
          reporting_args[elements] - a list of dictionaries that represent html
              elements to be added to the html page. (required) If no elements
              are provided (list is empty) a blank html page will be generated.
              The 3 main element types are 'table', 'head', and 'text'.
              All elements share the following arguments:
                  'type' - a string that depicts the type of element being add.
                      Currently 'table', 'head', and 'text' are defined
                      (required)
  
                  'section' - a string that depicts whether the element belongs
                      in the body or head of the html page.
                      Values: 'body' | 'head' (required)
  
              Table element dictionary has at least the following additional
              arguments:
                  'attributes' - a dictionary of html table attributes. The
                      attribute name is the key which gets set to the value
                      of the key. (optional)
                      Example: {'class': 'sorttable', 'id': 'parcel_table'}
  
                  'sortable' - a boolean value for whether the tables columns
                      should be sortable (required)
  
                  'checkbox' - a boolean value for whether there should be a
                      checkbox column. If True a 'selected total' row will be
                      added to the bottom of the table that will show the
                      total of the columns selected (optional)
  
                  'checkbox_pos' - an integer value for in which column
                      position the the checkbox column should appear
                      (optional)
  
                  'data_type' - one of the following string values:
                      'shapefile'|'hg csv'|'dictionary'. Depicts the type of data
                      structure to build the table from (required)
  
                  'data' - either a list of dictionaries if 'data_type' is
                      'dictionary' or a URI to a CSV table or shapefile if
                      'data_type' is 'shapefile' or 'csv' (required). If a
                      list of dictionaries, each dictionary should have
                      keys that represent the columns, where each dictionary
                      is a row (list could be empty)
                      How the rows are ordered are defined by their
                      index in the list. Formatted example:
                      [{col_name_1: value, col_name_2: value, ...},
                       {col_name_1: value, col_name_2: value, ...},
                       ...]
  
                  'key' - a string that defines which column or field should be
                      used as the keys for extracting data from a shapefile or
                      csv table 'key_field'.
                      (required for 'data_type' = 'shapefile' | 'csv')
  
                  'columns'- a list of dictionaries that defines the column
                      structure for the table (required). The order of the
                      columns from left to right is depicted by the index
                      of the column dictionary in the list. Each dictionary
                      in the list has the following keys and values:
                          'name' - a string for the column name (required)
                          'total' - a boolean for whether the column should be
                              totaled (required)
                          'attr' - a dictionary that has key value pairs for
                              optional tag attributes (optional). Ex:
                              'attr': {'class': 'offsets'}
                          'td_class' - a String to assign as a class name to
                              the table data tags under the column. Each
                              table data tag under the column will have a class
                              attribute assigned to 'td_class' value (optional)
  
                  'total'- a boolean value for whether there should be a constant
                      total row at the bottom of the table that sums the column
                      values (optional)
  
              Head element dictionary has at least the following additional
              arguments:
                  'format' - a string representing the type of head element being
                      added. Currently 'script' (javascript) and 'style' (css
                      style) accepted (required)
  
                  'data_src'- a URI to the location of the external file for
                      either the 'script' or the 'style' OR a String representing
                      the html script or style (DO NOT include the tags)
                      (required)
  
                  'input_type' -  a String, 'File' or 'Text' that refers to how
                      'data_src' is being passed in (URI vs String) (required).
  
                  'attributes' - a dictionary that has key value pairs for
                      optional tag attributes (optional). Ex:
                      'attributes': {'id': 'muni_data'}
  
              Text element dictionary has at least the following additional
              arguments:
                  'text'- a string to add as a paragraph element in the html page
                      (required)
  
          returns - nothing"""
      LOGGER.info('Creating HTML Report')
      # Since the dictionary being is mutated, make a copy to mutate on
      # while keeping the integrity of the original
      reporting_args = copy.deepcopy(args)
      # Get the title for the html page and place it in a string with html
      # title tags
      html_title = '<title>%s</title>' % reporting_args['title']
  
      # Initiate the html dictionary which will store all the head and body
      # elements. The 'head' and 'body' keys points to a tuple of two lists. The
      # first list holds the string representations of the html elements and the
      # second list is the corresponding 'position' of those elements. This allows
      # for proper ordering later in 'write_html'.
      # Initialize head's first element to be the title where the -1 position
      # ensures it will be the first element
      html_obj = {'head':[html_title], 'body':[]}
  
      # A dictionary of 'types' that point to corresponding functions. When an
      # 'element' is passed in the 'type' will be one of the defined types below
      # and will execute a function that properly handles that element
      report = {
              'table': build_table,
              'text' : add_text_element,
              'head': add_head_element
              }
  
      LOGGER.debug('Adding default JavaScript libs')
      # Add Jquery file to the elements list any time a html page is generated
      jquery_dict = {
              'type': 'head', 'section': 'head', 'format': 'script',
              'data_src': JQUERY_URI, 'input_type':'File'}
      reporting_args['elements'].insert(0, jquery_dict)
  
      # A list of tuples of possible default js libraries / scripts to add
      jsc_lib_list = [('totals', TOTALS_URI), ('sortable', SORTTABLE_URI)]
      # Used to have control of how the js libraries / scripts get added
      index = 1
      for lib_tup in jsc_lib_list:
          if (lib_tup[0] in reporting_args) and reporting_args[lib_tup[0]]:
              # Build up the dictionary for the script head element
              lib_dict = {
                  'type': 'head', 'section': 'head', 'format': 'script',
                  'data_src': lib_tup[1], 'input_type':'File'}
              # Add dictionary to elements list
              reporting_args['elements'].insert(index, lib_dict)
              index = index + 1
  
      # Iterate over the elements to be added to the html page
      for element in reporting_args['elements']:
          # There are 2 general purpose arguments that each element will have,
          # 'type' and 'section'. Get and remove these from the
          # elements dictionary (they should not be added weight passed to the
          # individual element functions)
          fun_type = element.pop('type')
          section = element.pop('section')
  
          # Process the element by calling it's specific function handler which
          # will return a string. Append this to html dictionary to be written
          # in write_html
          html_obj[section].append(report[fun_type](element))
  
      # Write the html page to 'out_uri'
      write_html(html_obj, reporting_args['out_uri'])
  
  
  def write_html(html_obj, out_uri):
      """Write an html file to 'out_uri' from html element represented as strings
          in 'html_obj'
  
          html_obj - a dictionary with two keys, 'head' and 'body', that point to
              lists. The list for each key is a list of the htmls elements as
              strings (required)
              example: {'head':['elem_1', 'elem_2',...],
                        'body':['elem_1', 'elem_2',...]}
  
          out_uri - a URI for the output html file
  
          returns - nothing"""
  
      LOGGER.debug('Writing HTML page')
  
      # Start the string that will be written as the html file
      html_str = u('<html>')
  
      for section in ['head', 'body']:
          # Ensure the browser interprets the html file as utf-8
          if section == 'head':
              html_str += '<meta charset="UTF-8">'
  
          # Write the tag for the section
          html_str += '<%s>' % u(section)
          # Get the list of html string elements for this section
          sect_elements = html_obj[section]
  
          for element in sect_elements:
              # Add each element to the html string
              if type(element) is StringType:
                  element = u(element)
              html_str += element
  
          # Add the closing tag for the section
          html_str += '</%s>' % section
  
      # Finish the html tag
      html_str += '</html>'
  
      #LOGGER.debug('HTML Complete String : %s', html_str)
  
      # If the URI for the html output file exists remove it
      if os.path.isfile(out_uri):
          os.remove(out_uri)
  
      # Open the file, write the string and close the file
      html_file = codecs.open(out_uri, 'wb', 'utf-8')
      html_file.write(html_str)
      html_file.close()
  
  
  def build_table(param_args):
      """Generates a string representing a table in html format.
  
          param_args - a dictionary that has the parameters for building up the
              html table. The dictionary includes the following:
  
              'attributes' - a dictionary of html table attributes. The attribute
                      name is the key which gets set to the value of the key.
                      (optional)
                      Example: {'class': 'sorttable', 'id': 'parcel_table'}
  
              param_args['sortable'] - a boolean value that determines whether the
                  table should be sortable (required)
  
              param_args['data_type'] - a string depicting the type of input to
                  build the table from. Either 'shapefile', 'csv', or 'dictionary'
                  (required)
  
              param_args['data'] - a URI to a csv or shapefile OR a list of
                  dictionaries. If a list of dictionaries the data should be
                  represented in the following format: (required)
                      [{col_name_1: value, col_name_2: value, ...},
                       {col_name_1: value, col_name_2: value, ...},
                       ...]
  
              param_args['key'] - a string that depicts which column (csv) or
                  field (shapefile) will be the unique key to use in extracting
                  the data into a dictionary. (required for 'data_type'
                  'shapefile' and 'csv')
  
              param_args['columns'] - a list of dictionaries that defines the
                      column structure for the table (required). The order of
                      the columns from left to right is depicted by the index
                      of the column dictionary in the list. Each dictionary
                      in the list has the following keys and values:
                          'name' - a string for the column name (required)
                          'total' - a boolean for whether the column should be
                              totaled (required)
                          'attr' - a dictionary that has key value pairs for
                              optional tag attributes (optional). Ex:
                              'attr': {'class': 'offsets'}
                          'td_class' - a String to assign as a class name to
                              the table data tags under the column. Each
                              table data tag under the column will have a class
                              attribute assigned to 'td_class' value (optional)
  
              param_args['total'] - a boolean value where if True a constant
                  total row will be placed at the bottom of the table that sums
                  the columns (required)
  
          returns - a string that represents an html table
      """
      LOGGER.debug('Building Table Structure')
      # Initialize an intermediate dictionary which will hold the physical data
      # elements of the table
      data_dict = {}
  
      # Initialize the final dictionary which will have the data of the table as
      # well as parameters needed to build up the html table
      table_dict = {}
  
      # Get the data type of the input being passed in so that it can properly be
      # pre-processed
      data_type = param_args['data_type']
  
      # Get a handle on the input data being passed in, whether it a URI to a
      # shapefile / csv file or a list of dictionaries
      input_data = param_args['data']
  
      # Depending on the type of input being passed in, pre-process it
      # accordingly
      if data_type == 'shapefile':
          key = param_args['key']
          data_dict = natcap.invest.pygeoprocessing_0_3_3.geoprocessing.extract_datasource_table_by_key(
              input_data, key)
          # Convert the data_dict to a list of dictionaries where each dictionary
          # in the list represents a row of the table
          data_list = data_dict_to_list(data_dict)
      elif data_type == 'csv':
          key = param_args['key']
          data_dict = natcap.invest.pygeoprocessing_0_3_3.geoprocessing.get_lookup_from_csv(input_data, key)
          # Convert the data_dict to a list of dictionaries where each dictionary
          # in the list represents a row of the table
          data_list = data_dict_to_list(data_dict)
      else:
          data_list = input_data
  
      #LOGGER.debug('Data Collected from Input Source: %s', data_list)
      LOGGER.debug('Data Collected from Input Source')
  
      # Add the columns data to the final dictionary that is to be passed
      # off to the table generator
      table_dict['cols'] = param_args['columns']
  
      # Add the properly formatted row data to the final dictionary that is
      # to be passed to the table generator
      table_dict['rows'] = data_list
  
      # If a totals row is present, add it to the final dictionary
      if 'total' in param_args:
          table_dict['total'] = param_args['total']
  
      # If table attributes were passed in check to see if the 'sortable' class
      # needs to be added to that list
      if 'attributes' in param_args:
          table_dict['attributes'] = param_args['attributes']
          if param_args['sortable']:
              try:
                  class_list = table_dict['attributes']['class'] + ' sortable'
                  table_dict['attributes']['class'] = class_list
              except KeyError:
                  table_dict['attributes']['class'] = 'sortable'
      else:
          # Attributes were not passed in, however if sortable is True
          # create attributes key and dictionary to pass in to table
          # handler
          if param_args['sortable']:
              table_dict['attributes'] = {'class': 'sortable'}
  
      # If a checkbox column is wanted pass in the table dictionary
      if 'checkbox' in param_args and param_args['checkbox']:
          table_dict['checkbox'] = True
          if 'checkbox_pos' in param_args:
              table_dict['checkbox_pos'] = param_args['checkbox_pos']
  
      LOGGER.debug('Calling table_generator')
      # Call generate table passing in the final dictionary and attribute
      # dictionary. Return the generate string
      return table_generator.generate_table(table_dict)
  
  
  def data_dict_to_list(data_dict):
      """Abstract out inner dictionaries from data_dict into a list, where
          the inner dictionaries are added to the list in the order of
          their sorted keys
  
          data_dict - a dictionary with unique keys pointing to dictionaries.
              Could be empty (required)
  
          returns - a list of dictionaries, or empty list if data_dict is empty"""
  
      data_list = []
      data_keys = data_dict.keys()
      data_keys.sort()
      for key in data_keys:
          data = data_dict[key]
          data_list.append(data)
  
      return data_list
  
  
  def add_text_element(param_args):
      """Generates a string that represents a html text block. The input string
          should be wrapped in proper html tags
  
          param_args - a dictionary with the following arguments:
  
              param_args['text'] - a string
  
          returns - a string
      """
  
      return param_args['text']
  
  
  def add_head_element(param_args):
      """Generates a string that represents a valid element in the head section
          of an html file. Currently handles 'style' and 'script' elements,
          where both the script and style are locally embedded
  
          param_args - a dictionary that holds the following arguments:
  
              param_args['format'] - a string representing the type of element to
                  be added. Currently : 'script', 'style' (required)
  
              param_args['data_src'] - a string URI path for the external source
                  of the element OR a String representing the html
                  (DO NOT include html tags, tags are automatically generated).
                  If a URI the file is read in as a String. (required)
  
              param_args['input_type'] - 'Text' or 'File'. Determines how the
                  input from 'data_src' is handled (required)
  
              'attributes' - a dictionary that has key value pairs for
                  optional tag attributes (optional). Ex:
                  'attributes': {'class': 'offsets'}
  
          returns - a string representation of the html head element"""
  
      LOGGER.info('Preparing to generate head element as String')
  
      # Get the type of element to add
      form = param_args['format']
      # Get a handle on the data whether it be a String or URI
      src = param_args['data_src']
      # Get the input type of the data, 'File' or 'Text'
      input_type = param_args['input_type']
      if input_type == 'File':
          # Read in file and save as string. Using latin1 to decode, seems to
          # work on the current javascript / css files
          head_file = codecs.open(src, 'rb', 'latin1')
          file_str = head_file.read()
      else:
          file_str = src
  
      attr = ''
      if 'attributes' in param_args:
          for key, val in param_args['attributes'].iteritems():
              attr += '%s="%s" ' % (key, val)
  
      # List of regular expression strings to search against
      reg_list = [r'<script', r'/script>', r'<style', r'/style>']
  
      # Iterate over the String object to make sure there are no conflicting html
      # tags
      for exp in reg_list:
          if re.search(exp, file_str) != None:
              raise Exception('The following html tag was found in header'
                      ' string : %s. Please do not place any html tags in'
                      ' the header elements' % exp)
  
      if form == 'style':
          html_str = '''<style type=text/css %s> %s </style>''' % (attr, file_str)
      elif form == 'script':
          html_str = '''<script type=text/javascript %s> %s </script>''' % (attr, file_str)
      elif form == 'json':
          html_str = '''<script type=application/json %s> %s </script>''' % (attr, file_str)
      else:
          raise Exception('Currently this type of head element is not supported'
                  ' : %s' % form)
  
      return html_str
  