def __init__(self, show_error_dialog = False):
     self.show_error_dialog = show_error_dialog
     self.data_manager = IndicatorDataManager()
 def __init__(self, show_error_dialog=False):
     self.show_error_dialog = show_error_dialog
     self.data_manager = IndicatorDataManager()
class IndicatorResults(object):
    """  Takes the descriptions and locations of precomputed indicators 
         and generates an html file to browse them.
    
         The purpose of IndicatorResults is to take in a description 
         of the indicators that were requested through the GUI and output 
         an html file that can be used to browse the indicator results. 
         There is a single entry point and all the other functions are private.
    """ 
    
    def __init__(self, show_error_dialog = False):
        self.show_error_dialog = show_error_dialog
        self.data_manager = IndicatorDataManager()
        
    def create_page(self, 
                    source_data, 
                    indicators, 
                    output_directory = None,
                    page_name = 'indicator_results.html'):
        
        """  Generates the html page based on information about precomputed indicators.
        
             The file path to the generated html page is returned.
             
             Parameters:
                 source_data -- information about where the indicators were computed from
                 page_name -- the filename of the outputted html file
                 indicators -- a list of the generated indicators
        """
        
        #stores the html that is built up over the course of execution
        html = []
        
        self.indicator_documentation_mapping = {}
        
        html.append( self._output_header() )
        html.append( self._start_body() )

        #generate html for configuration info
        html.append( self._output_configuration_info(source_data) )
        html.append( self._start_table() )
        
        #load previously computed indicators
        indicator_dirs = []
        for i in indicators:
            if i.write_to_file:
                dir = i.get_storage_location()
                if not dir in indicator_dirs:
                    indicator_dirs.append(dir)
            
        indicators = []
        for dir in indicator_dirs: 
            try:
                indicators += self.data_manager.import_indicators(
                                 indicator_directory = dir)
            except: 
                logger.log_warning('Could not load indicators from directory %s'%dir)
        
        rows = []
        self._output_body(indicators, rows)
        
        unique_rows = dict([(' '.join(x), x) for x in rows])
        #rows_by_date_dict = dict([(x[4],x) for x in unique_rows.itervalues()])
        
        sorted_rows = unique_rows.items()
        sorted_rows.sort(reverse = True)
        
        sorted_rows = [row[1] for row in sorted_rows]

        for row in sorted_rows:
            html.append(self._output_row(row))
            
        html.append( self._end_table() )
        html.append( self._end_page() )

        if output_directory is None:
            output_directory = indicator_dirs[0]
            
        file = open(os.path.join(
                         output_directory, 
                         page_name),
                         'w')   
        file.write(''.join(html))
        file.close()
        
        return file.name

    def _output_body(self, indicators, rows, test = False):
        """ Generates the html for the indicators. 
        
            Finds the indicator file for every year each of the indicators 
            were run and formats this into a table.
            
            test is only used for unit testing
        """    
        for indicator in indicators:
            years = indicator.years
            
            if years == []: continue
            
            if indicator.is_single_year_indicator_image_type():
                links = []
                for year in years:
                    path = indicator.get_file_path(year)
                    if os.path.exists(path) or test:
                        link = self._get_link(indicator.get_file_name(year),str(year)) 
                        links.append(link)
                image_paths = ','.join(links)
            else:
                #aggregate multiyear run data so it is outputted nicely...
                path = indicator.get_file_path()
                if os.path.exists(path) or test:
                    year_aggregation = self._get_year_aggregation(years)
                    image_paths = self._get_link(indicator.get_file_name(),year_aggregation)
                
            doc_link = self._get_doc_link(indicator)
            
            row = [  
               doc_link,
               indicator.dataset_name,
               indicator.get_visualization_shorthand(), 
               image_paths
            ]
            rows.append(row)
    
    def _get_year_aggregation(self, years):
        """Given a sequence of years, outputs a string that represents 
           the years with dashes between consecutive years 
           (e.g. "1983,1985-1987,1999") 
        """
        years = list(years) #traits funniness
        years.sort()
        if years == []: return ''
        year_aggregation = []
        (first, last) = (years[0], years[0])
        for i in range(1,len(years)): 
            if years[i] == last + 1: last = years[i]
            else:
                if first == last: year_aggregation.append('%i' % first)
                else: year_aggregation.append('%i-%i' % (first, last))
                (first, last) = (years[i], years[i])
                
        if first == last: year_aggregation.append('%i' % first)
        else: year_aggregation.append('%i-%i' % (first, last))            
   
        return ','.join(year_aggregation)
        
    #private HTML output functions. None of the above functions directly outputs any HTML.
    def _output_configuration_info(self, source_data):
        html = []
        config_fields = { 
           'Cache directory: ' : source_data.cache_directory,
           }
        
        for title,value in config_fields.iteritems():
            html.append('<b>%s</b>%s<br><br>\n'%(title,value))
        
        return ''.join(html)
        
    def _get_doc_link(self, indicator):
        urls = []
        for attribute in indicator.attributes:
            try:
                attribute_alias = indicator.get_attribute_alias(attribute)
                url = self._get_documentation_url(attribute_alias)
            except: 
                url = None
                
            if url is None: 
                url = indicator.get_file_name(suppress_extension_addition=True)
            else:
                url = self._get_link(url,
                                     indicator.get_file_name(suppress_extension_addition=True))
            urls.append(url)
            
        return '<br>'.join(urls)
    
    def _get_link(self,url,name):
        url = url.replace('\\\\','/////').replace('\\','/')
        return '<A HREF="%s">%s</A>' % (url, name)
    
    def _get_documentation_url(self, attribute):
        """ A mapping between attribute name and documentation"""
        if self.indicator_documentation_mapping == {}:
            indicator_info = IndicatorMetaData.get_indicator_info()
            self.indicator_documentation_mapping = {}
            for (name, path, variable, documentation) in indicator_info:
                self.indicator_documentation_mapping[variable] = documentation
        
        try:
            doc_file = self.indicator_documentation_mapping[attribute] 
            prefix = IndicatorMetaData.get_indicator_documentation_URL() 
        except: return None
        return os.path.join(prefix,doc_file)
    
    #HTML outputting methods
    def _output_header(self):
        return '<head><title>Indicator Results</title></head>\n'
        
    def _output_section(self, title):
        return '<h2>%s</h2>\n' % title
        
    def _start_body(self):
        return '<body>\n' + '<h2>Indicator Results</h2>\n'
        
    def _start_table(self):
        return (
           '<table border=1 cellspacing="0" cellpadding="5" style="border-style: solid; border-color: black">\n'
           '\t<tr>\n'
           '\t\t<td><b>Indicator name</b></td>\n'
           '\t\t<td><b>Dataset</b></td>\n'
           '\t\t<td><b>Type</b></td>\n'
           '\t\t<td><b>Years</b></td>\n'
           '\t</tr>\n')
    
    def _end_table(self):
        return '</table>\n'
    
    def _output_row(self, row):
        html = ['\t<tr>\n']
        for col in row:
            html.append( '\t\t<td>%s</td>\n' % col )
        html.append( '\t</tr>\n' )
        return ''.join(html)
    
    def _end_page(self):
        return '</body>'
class IndicatorResults(object):
    """  Takes the descriptions and locations of precomputed indicators 
         and generates an html file to browse them.
    
         The purpose of IndicatorResults is to take in a description 
         of the indicators that were requested through the GUI and output 
         an html file that can be used to browse the indicator results. 
         There is a single entry point and all the other functions are private.
    """
    def __init__(self, show_error_dialog=False):
        self.show_error_dialog = show_error_dialog
        self.data_manager = IndicatorDataManager()

    def create_page(self,
                    source_data,
                    indicators,
                    output_directory=None,
                    page_name='indicator_results.html'):
        """  Generates the html page based on information about precomputed indicators.
        
             The file path to the generated html page is returned.
             
             Parameters:
                 source_data -- information about where the indicators were computed from
                 page_name -- the filename of the outputted html file
                 indicators -- a list of the generated indicators
        """

        #stores the html that is built up over the course of execution
        html = []

        self.indicator_documentation_mapping = {}

        html.append(self._output_header())
        html.append(self._start_body())

        #generate html for configuration info
        html.append(self._output_configuration_info(source_data))
        html.append(self._start_table())

        #load previously computed indicators
        indicator_dirs = []
        for i in indicators:
            if i.write_to_file:
                dir = i.get_storage_location()
                if not dir in indicator_dirs:
                    indicator_dirs.append(dir)

        indicators = []
        for dir in indicator_dirs:
            try:
                indicators += self.data_manager.import_indicators(
                    indicator_directory=dir)
            except:
                logger.log_warning(
                    'Could not load indicators from directory %s' % dir)

        rows = []
        self._output_body(indicators, rows)

        unique_rows = dict([(' '.join(x), x) for x in rows])
        #rows_by_date_dict = dict([(x[4],x) for x in unique_rows.itervalues()])

        sorted_rows = unique_rows.items()
        sorted_rows.sort(reverse=True)

        sorted_rows = [row[1] for row in sorted_rows]

        for row in sorted_rows:
            html.append(self._output_row(row))

        html.append(self._end_table())
        html.append(self._end_page())

        if output_directory is None:
            output_directory = indicator_dirs[0]

        file = open(os.path.join(output_directory, page_name), 'w')
        file.write(''.join(html))
        file.close()

        return file.name

    def _output_body(self, indicators, rows, test=False):
        """ Generates the html for the indicators. 
        
            Finds the indicator file for every year each of the indicators 
            were run and formats this into a table.
            
            test is only used for unit testing
        """
        for indicator in indicators:
            years = indicator.years

            if years == []: continue

            if indicator.is_single_year_indicator_image_type():
                links = []
                for year in years:
                    path = indicator.get_file_path(year)
                    if os.path.exists(path) or test:
                        link = self._get_link(indicator.get_file_name(year),
                                              str(year))
                        links.append(link)
                image_paths = ','.join(links)
            else:
                #aggregate multiyear run data so it is outputted nicely...
                path = indicator.get_file_path()
                if os.path.exists(path) or test:
                    year_aggregation = self._get_year_aggregation(years)
                    image_paths = self._get_link(indicator.get_file_name(),
                                                 year_aggregation)

            doc_link = self._get_doc_link(indicator)

            row = [
                doc_link, indicator.dataset_name,
                indicator.get_visualization_shorthand(), image_paths
            ]
            rows.append(row)

    def _get_year_aggregation(self, years):
        """Given a sequence of years, outputs a string that represents 
           the years with dashes between consecutive years 
           (e.g. "1983,1985-1987,1999") 
        """
        years = list(years)  #traits funniness
        years.sort()
        if years == []: return ''
        year_aggregation = []
        (first, last) = (years[0], years[0])
        for i in range(1, len(years)):
            if years[i] == last + 1: last = years[i]
            else:
                if first == last: year_aggregation.append('%i' % first)
                else: year_aggregation.append('%i-%i' % (first, last))
                (first, last) = (years[i], years[i])

        if first == last: year_aggregation.append('%i' % first)
        else: year_aggregation.append('%i-%i' % (first, last))

        return ','.join(year_aggregation)

    #private HTML output functions. None of the above functions directly outputs any HTML.
    def _output_configuration_info(self, source_data):
        html = []
        config_fields = {
            'Cache directory: ': source_data.cache_directory,
        }

        for title, value in config_fields.iteritems():
            html.append('<b>%s</b>%s<br><br>\n' % (title, value))

        return ''.join(html)

    def _get_doc_link(self, indicator):
        urls = []
        for attribute in indicator.attributes:
            try:
                attribute_alias = indicator.get_attribute_alias(attribute)
                url = self._get_documentation_url(attribute_alias)
            except:
                url = None

            if url is None:
                url = indicator.get_file_name(suppress_extension_addition=True)
            else:
                url = self._get_link(
                    url,
                    indicator.get_file_name(suppress_extension_addition=True))
            urls.append(url)

        return '<br>'.join(urls)

    def _get_link(self, url, name):
        url = url.replace('\\\\', '/////').replace('\\', '/')
        return '<A HREF="%s">%s</A>' % (url, name)

    def _get_documentation_url(self, attribute):
        """ A mapping between attribute name and documentation"""
        if self.indicator_documentation_mapping == {}:
            indicator_info = IndicatorMetaData.get_indicator_info()
            self.indicator_documentation_mapping = {}
            for (name, path, variable, documentation) in indicator_info:
                self.indicator_documentation_mapping[variable] = documentation

        try:
            doc_file = self.indicator_documentation_mapping[attribute]
            prefix = IndicatorMetaData.get_indicator_documentation_URL()
        except:
            return None
        return os.path.join(prefix, doc_file)

    #HTML outputting methods
    def _output_header(self):
        return '<head><title>Indicator Results</title></head>\n'

    def _output_section(self, title):
        return '<h2>%s</h2>\n' % title

    def _start_body(self):
        return '<body>\n' + '<h2>Indicator Results</h2>\n'

    def _start_table(self):
        return (
            '<table border=1 cellspacing="0" cellpadding="5" style="border-style: solid; border-color: black">\n'
            '\t<tr>\n'
            '\t\t<td><b>Indicator name</b></td>\n'
            '\t\t<td><b>Dataset</b></td>\n'
            '\t\t<td><b>Type</b></td>\n'
            '\t\t<td><b>Years</b></td>\n'
            '\t</tr>\n')

    def _end_table(self):
        return '</table>\n'

    def _output_row(self, row):
        html = ['\t<tr>\n']
        for col in row:
            html.append('\t\t<td>%s</td>\n' % col)
        html.append('\t</tr>\n')
        return ''.join(html)

    def _end_page(self):
        return '</body>'