# Kanbanara Reports Component
# Written by Rebecca Shalfield between 2013 and 2017
# Copyright (c) Rebecca Shalfield 2013-2017
# Released under the GNU AGPL v3

'''Kanbanara's Reports Component'''

import ast
import datetime
import logging
import os
import re
import urllib.parse

import cherrypy
from kanbanara import Kanbanara
from pymongo import MongoClient


class Reports(Kanbanara):
    '''Kanbanara's Reports Component'''

    @cherrypy.expose
    def delete_report(self, reportname):
        """Allows a saved user-defined report to be deleted"""
        if reportname:
            session_id = Kanbanara.cookie_handling(self)
            session_document = self.sessions_collection.find_one({"session_id": session_id})
            member_document = Kanbanara.get_member_document(self, session_document)
            reports = member_document.get('reports', [])
            if reports:
                remaining_reports = [report for report in reports if reportname != report['reportname']]
                if remaining_reports != reports:
                    member_document['reports'] = remaining_reports
                    self.members_collection.save(member_document)
                    self.save_member_as_json(member_document)

        raise cherrypy.HTTPRedirect("/reports/report_manager", 302)

    def __init__(self):
        """Initialisation"""
        self.component = 'reports'

        Kanbanara.__init__(self)

        self.current_dir = os.path.dirname(os.path.abspath(__file__))

        logging.basicConfig(level=logging.DEBUG,
                            format='%(asctime)s - %(levelname)s - %(message)s',
                            filename=os.path.join(self.current_dir, '..', 'logs', 'kanbanara.log'),
                            filemode='w'
                           )

        # Initialisation Settings
        self.mongodb_host, self.mongodb_port, self.mongodb_username, self.mongodb_password, self.mongodb_bindir = Kanbanara.read_mongodb_ini_file(self)

        # Connect to MongoDB on given host and port
        if self.mongodb_username and self.mongodb_password:
            modified_username = urllib.parse.quote_plus(self.mongodb_username)
            modified_password = urllib.parse.quote_plus(self.mongodb_password)
            connection = MongoClient('mongodb://' + modified_username + ':' + modified_password + '@' +
                                     self.mongodb_host + ':' + str(self.mongodb_port))
        else:
            connection = MongoClient(self.mongodb_host, self.mongodb_port)

        # Connect to 'kanbanara' database, creating if not already exists
        db = connection['kanbanara']

        # Connect to 'projects' collection
        self.projects_collection = db['projects']
        for attribute in ['project']:
            self.projects_collection.create_index(attribute, unique=True, background=True)

        # Connect to 'sessions' collection
        self.sessions_collection = db['sessions']
        for attribute in ['session_id']:
            self.sessions_collection.create_index(attribute, unique=True, background=True)

        for attribute in ['lastaccess']:
            self.sessions_collection.create_index(attribute, unique=False, background=True)

        # Connect to 'members' collection
        self.members_collection = db['members']
        for attribute in ['username']:
            # TODO - username attribute should be unique but get error when unique=true set
            self.members_collection.create_index(attribute, unique=False, background=True)

        # Connect to 'cards' collection
        self.cards_collection = db['cards']

    @cherrypy.expose
    def backlog_trend(self):
        """comment"""
        username = Kanbanara.check_authentication(f'/{self.component}/backlog_trend')
        session_id = Kanbanara.cookie_handling(self)
        session_document = self.sessions_collection.find_one({"session_id": session_id})
        member_document = Kanbanara.get_member_document(self, session_document)
        content = []
        content.append(Kanbanara.header(self, 'backlog_trend', "Backlog Trend"))
        content.append(Kanbanara.filter_bar(self, 'backlog_trend'))
        content.append(Kanbanara.menubar(self))
        content.append('<div align="center">')
        content.append(self.insert_page_title_and_online_help(session_document, 'backlog_trend', 'Backlog Trend'))
        content.append('</div>')
        content.append(Kanbanara.footer(self))
        return "".join(content)

    @cherrypy.expose
    def rootcauseanalysis_report(self):
        """comment"""
        username = Kanbanara.check_authentication(f'/{self.component}/rootcauseanalysis_report')
        session_id = Kanbanara.cookie_handling(self)
        session_document = self.sessions_collection.find_one({"session_id": session_id})
        member_document = Kanbanara.get_member_document(self, session_document)
        content = []
        epoch = datetime.datetime.utcnow()
        content.append(Kanbanara.header(self, 'rootcauseanalysis_report', "Root-Cause Analysis Report"))
        content.append(Kanbanara.filter_bar(self, 'rootcauseanalysis_report'))
        content.append(Kanbanara.menubar(self))
        content.append('<div align="center">')
        content.append(self.insert_page_title_and_online_help(session_document, 'rootcauseanalysis_report',
                                                              'Root-Cause Analysis Report'))
        required_columns, required_states = self.get_displayable_columns()
        _, _, owner_reviewer_search_criteria = self.get_filtered_search_criteria(session_document, required_states)
        owner_reviewer_search_criteria['rootcauseanalysis'] = {'$nin': ['', [], None]}
        content.append('<table class="admin"><tr><td></td><th>External Reference</th><th>Priority</th><th>Customer</th><th>ID</th><th>Escalation</th><th>Title</th><th>Owner</th><th>Co-Owner</th><th>State</th><th>Fix Version</th><th>Status</th><th>Root-Cause Analysis</th></tr>')
        for card_document in self.cards_collection.find(owner_reviewer_search_criteria):
            nextaction = card_document.get('nextaction', '')
            state = card_document.get('state', '')
            status = card_document.get('status', '')
            content.append('<tr><td valign="top">')
            buttons = self.ascertain_card_menu_items(card_document, member_document)
            content.append(self.assemble_card_menu(member_document, card_document, buttons, 'index'))
            content.append('</td>')
            for attribute in ['externalreference', 'priority', 'customer', 'id', 'escalation',
                              'title', 'owner', 'coowner', 'state', 'fixversion', 'status',
                              'rootcauseanalysis']:
                if attribute in card_document and card_document[attribute]:
                    if attribute == 'status':
                        modified_status = Kanbanara.format_multiline(status)
                        content.append('<td valign="top">'+modified_status+'</td>')
                    elif attribute == 'nextaction':
                        if state not in ['closed']:
                            date_format = self.convert_time_to_display_format(nextaction)
                            if nextaction and nextaction < epoch:
                                content.append('<td valign="top" class="warning">'+date_format+'</td>')
                            else:
                                content.append('<td valign="top">'+date_format+'</td>')

                        else:
                            content.append('<td></td>')

                    else:
                        content.append('<td valign="top">'+card_document[attribute]+'</td>')

                else:
                    content.append('<td></td>')

            content.append('</tr>')

        content.append('</table></div>')
        content.append(Kanbanara.footer(self))
        return "".join(content)

    @cherrypy.expose
    def escalation_report(self):
        """comment"""
        username = Kanbanara.check_authentication(f'/{self.component}/escalation_report')
        session_id = Kanbanara.cookie_handling(self)
        session_document = self.sessions_collection.find_one({"session_id": session_id})
        member_document = Kanbanara.get_member_document(self, session_document)
        project, _, _ = self.get_member_project_release_iteration(member_document)
        project_document = self.projects_collection.find_one({'project': project})
        workflow_index = project_document.get('workflow_index', {})
        condensed_column_states = workflow_index.get('condensed_column_states', [])
        content = []
        epoch = datetime.datetime.utcnow()
        content.append(Kanbanara.header(self, 'escalation_report', "Escalation Report"))
        content.append(Kanbanara.filter_bar(self, 'escalation_report'))
        content.append(Kanbanara.menubar(self))
        content.append('<div align="center">')
        content.append(self.insert_page_title_and_online_help(session_document, 'escalation_report', 'Escalation Report'))
        required_columns, required_states = self.get_displayable_columns()
        _, _, owner_reviewer_search_criteria = self.get_filtered_search_criteria(session_document, required_states)
        backlog_states = self.get_custom_states_mapped_onto_metastates(['backlog'])
        owner_reviewer_search_criteria['escalation'] = {'$nin': ['', [], None]}
        content.append('<table class="admin"><tr><td></td><td></td><th>External Reference</th><th>Priority</th><th>Customer</th><th>ID</th><th>Escalation</th><th>Title</th><th>Owner</th><th>Co-Owner</th><th>State</th><th>Fix Version</th><th>Status</th><th>Next Action</th></tr>')
        for card_document in self.cards_collection.find(owner_reviewer_search_criteria):
            nextaction = card_document.get('nextaction', '')
            project = card_document.get('project', '')
            state = card_document.get('state', '')
            statehistory = card_document.get('statehistory', [])
            status = card_document.get('status', '')
            content.append('<tr><td valign="top">')
            buttons = self.ascertain_card_menu_items(card_document, member_document)
            content.append(self.assemble_card_menu(member_document, card_document,
                                                   buttons, 'index'))
            content.append('</td><td valign="top">')
            state_metrics = self.get_state_metrics(condensed_column_states, statehistory)
            for backlog_state in backlog_states:
                backlog = state_metrics.get(backlog_state, 0)
                if backlog:
                    break

            if backlog and backlog > epoch-self.timedelta_day:
                content.append('<sup class="new">New!</sup>')

            content.append('</td>')
            for attribute in ['externalreference', 'priority', 'customer', 'id', 'escalation',
                              'title', 'owner', 'coowner', 'state', 'fixversion', 'status',
                              'nextaction']:
                if attribute in card_document and card_document[attribute]:
                    if attribute == 'status':
                        modified_status = Kanbanara.format_multiline(status)
                        content.append('<td valign="top">'+modified_status+'</td>')
                    elif attribute == 'nextaction':
                        if state not in ['closed']:
                            date_format = self.convert_time_to_display_format(nextaction)
                            if nextaction and nextaction < epoch:
                                content.append('<td valign="top" class="warning">'+date_format+'</td>')
                            else:
                                content.append('<td valign="top">'+date_format+'</td>')

                        else:
                            content.append('<td></td>')

                    else:
                        content.append('<td valign="top">'+card_document[attribute]+'</td>')

                else:
                    content.append('<td></td>')

            content.append('</tr>')

        content.append('</table></div>')
        content.append(Kanbanara.footer(self))
        return "".join(content)

    @cherrypy.expose
    def index(self):
        """Redirects you to the kanban board"""
        raise cherrypy.HTTPRedirect("/kanban", 302)

    @cherrypy.expose
    def costs_report(self):
        """comment"""
        username = Kanbanara.check_authentication(f'/{self.component}')

        session_id = Kanbanara.cookie_handling(self)
        content = []
        estimated_costs_total = 0
        actual_costs_total = 0
        content.append(Kanbanara.header(self, 'costs_report', "Costs Report"))
        content.append(Kanbanara.filter_bar(self, 'costs_report'))
        content.append(Kanbanara.menubar(self))
        content.append('<div align="center">')
        session_document = self.sessions_collection.find_one({"session_id": session_id})
        content.append(self.insert_page_title_and_online_help(session_document, 'costs_report', 'Costs Report'))
        required_columns, required_states = self.get_displayable_columns()
        owner_search_criteria, reviewer_search_criteria, owner_reviewer_search_criteria = self.get_filtered_search_criteria(session_document, required_states)
        owner_reviewer_search_criteria["estimatedcost"] = {"$exists": True,"$ne":""}
        documents = self.cards_collection.find(owner_reviewer_search_criteria).sort("estimatedcost")

        content.append('<table class="unsortable"><thead><tr><th>ID</th><th>Title</th><th>State</th><th>Estimated Cost</th><th>Actual Cost</th></tr></thead><tbody>')
        for document in documents:
            content.append(f'<tr class="{document["type"]}">')
            content.append(f'<td>{document["id"]}</td>')
            content.append('<td>'+document.get('title', '')+'</td>')
            content.append(f'<td>{document["state"]}</td>')
            content.append(f'<td>{document["estimatedcost"]}</td>')
            estimated_costs_total += float(document['estimatedcost'])
            content.append(f'<td>{document["actualcost"]}</td>')
            actual_costs_total += float(document['actualcost'])
            content.append('</tr>')

        content.append(f'<tr><th colspan="3">Total:</th><td>{estimated_costs_total}</td><td>{actual_costs_total}</td></tr>')
        content.append('</tbody></table>')
        content.append('</div>')
        content.append(Kanbanara.footer(self))
        return "".join(content)

    @cherrypy.expose
    def report_generator(self, reportcriteria="", reportname="", compile="", save=""):
        """comment"""
        username = Kanbanara.check_authentication(f'/{self.component}/report_generator')
        session_id = Kanbanara.cookie_handling(self)
        session_document = self.sessions_collection.find_one({"session_id": session_id})
        member_document = Kanbanara.get_member_document(self, session_document)
        content = []
        content.append(Kanbanara.header(self, 'report_generator', "Report Generator"))
        content.append(Kanbanara.filter_bar(self, 'report_generator'))
        content.append(Kanbanara.menubar(self))
        content.append('<div align="center">')
        content.append(self.insert_page_title_and_online_help(session_document, 'report_generator', 'Report Generator'))
        content.append('<form action="/reports/report_generator" method="post">')
        content.append('<table class="unsortable"><tr><th>Report Search Criteria</th><td><input type="text" name="reportcriteria" size="80" value="'+reportcriteria+'" placeholder="search ... show ..."></td></tr><tr><th>Report Name</th><td><input type="text" name="reportname" value="'+reportname+'"></td></tr><tr><td colspan="2" align="center"><input class="button" name="compile" type="submit" value="Compile"><input class="button" name="save" type="submit" value="Save"></td></tr></table></form>')
        if save and reportcriteria and reportname:
            reports = member_document.get('reports', [])
            modified_reports = []
            overwritten = False
            for report_document in reports:
                if report_document['reportname'] == reportname:
                    modified_reports.append({'reportname': reportname, 'reportcriteria': reportcriteria})
                    overwritten = True
                else:
                    modified_reports.append(report_document)

            if not overwritten:
                modified_reports.append({'reportname': reportname, 'reportcriteria': reportcriteria})

            member_document['reports'] = modified_reports
            self.members_collection.save(member_document)
            raise cherrypy.HTTPRedirect("/reports/index", 302)
        elif compile and reportcriteria:
            attrs_ops_vals, show_attrs = self.parse_report_criteria(reportcriteria)
            search_criteria = {'project': member_document['project']}
            for (attr, op, val) in attrs_ops_vals:
                if op == "=":
                    search_criteria[attr] = val
                elif op == "!=":
                    search_criteria[attr] = {'$ne': val}
                elif op == "<":
                    search_criteria[attr] = {'$lt': val}
                elif op == ">":
                    search_criteria[attr] = {'$gt': val}
                elif op == "in":
                    search_criteria[attr] = {'$in': val}
                elif op == "nin":
                    search_criteria[attr] = {'$nin': val}

            content.append('<table class="sortable"><thead><tr>')
            for attr in show_attrs:
                content.append('<th><span>'+attr+'</span></th>')

            content.append('</tr></thead><tbody>')

            for card_document in self.cards_collection.find(search_criteria):
                content.append('<tr>')
                for attr in show_attrs:
                    if attr in card_document:
                        content.append(f'<td>{card_document[attr]}</td>')
                    else:
                        content.append('<td><p class="warning">NON-EXISTENT!</p></td>')

                content.append('</tr>')

            content.append('</tbody></table>')

        content.append('</div>')
        content.append('<script type="text/javascript" src="/scripts/listview.js"></script>')
        content.append(Kanbanara.footer(self))
        return "".join(content)

    def parse_report_criteria(self, reportcriteria):
        attrs_ops_vals_raw = ''
        show_attrs_raw = ''
        attrs_ops_vals = []
        show_attrs = []
        if ' show ' in reportcriteria:
            (attrs_ops_vals_raw, show_attrs_raw) = reportcriteria.split(' show ')

        attrs_ops_vals = ""
        while '  ' in attrs_ops_vals_raw:
            attrs_ops_vals_raw = attrs_ops_vals_raw.replace('  ', ' ')

        inside_list          = False
        inside_single_quotes = False
        inside_double_quotes = False
        # TODO - Do we want to support """...""" and '''...''' quoted strings?
        for char in attrs_ops_vals_raw:
            if char == "'":
                attrs_ops_vals += char
                if not inside_list:
                    if not inside_single_quotes:
                        if not inside_double_quotes:
                            inside_single_quotes = True

                    else:
                        inside_single_quotes = False

                else:
                    inside_single_quotes = False

            elif char == '[':
                attrs_ops_vals += char
                if not inside_single_quotes:
                    if not inside_double_quotes:
                        inside_list = True

            elif char == ']':
                attrs_ops_vals += char
                if inside_list:
                    inside_list = False

            elif char == '"':
                attrs_ops_vals += char
                if not inside_list:
                    if not inside_double_quotes:
                        if not inside_single_quotes:
                            inside_double_quotes = True

                    else:
                        inside_double_quotes = False

                else:
                    inside_double_quotes = False

            elif char == ' ':
                if inside_list or inside_double_quotes or inside_single_quotes:
                    attrs_ops_vals += char
                else:
                    attrs_ops_vals += '--===--'

            else:
                attrs_ops_vals += char

        components = attrs_ops_vals.split('--===--')

        attrs_ops_vals = []
        if not len(components) % 4:
            for component_no in range(0, len(components), 4):
                attribute = components[component_no+1]
                operand   = components[component_no+2]
                value     = components[component_no+3]
                if value.startswith("'''") and value.endswith("'''"):
                    value = ast.literal_eval(value)
                elif value.startswith('"""') and value.endswith('"""'):
                    value = ast.literal_eval(value)
                elif value.startswith("'") and value.endswith("'"):
                    value = ast.literal_eval(value)
                    value = value.replace("\\'", "'")
                elif value.startswith('"') and value.endswith('"'):
                    value = ast.literal_eval(value)
                    value = value.replace('\\"', '"')
                elif value.isdigit():
                    value = int(value)
                elif self.isfloat(value):
                    value = float(value)
                elif value.startswith("[") and value.endswith("]"):
                    value = ast.literal_eval(value)
                elif value.lower() in ['true', 'false', 'enabled', 'disabled']:
                    if value in ['true', 'enabled']:
                        value = True
                    else:
                        value = False

                attrs_ops_vals.append((attribute, operand, value))

        show_attrs_raw = show_attrs_raw.replace(' ,', ',')
        show_attrs_raw = show_attrs_raw.replace(', ', ',')
        show_attrs = show_attrs_raw.split(',')
        return attrs_ops_vals, show_attrs

    @cherrypy.expose
    def report(self, reportname):
        """comment"""
        username = Kanbanara.check_authentication(f'/{self.component}')
        session_id = Kanbanara.cookie_handling(self)
        session_document = self.sessions_collection.find_one({"session_id": session_id})
        content = []
        content.append(Kanbanara.header(self, 'report', "Report"))
        content.append(Kanbanara.filter_bar(self, 'report'))
        content.append(Kanbanara.menubar(self))
        content.append('<div align="center">')
        content.append(self.insert_page_title_and_online_help(session_document, 'report', reportname+' Report'))
        member_document = Kanbanara.get_member_document(self, session_document)
        reports = member_document.get('reports', [])
        for report_document in reports:
            if report_document['reportname'] == reportname:
                report_criteria = report_document['reportcriteria']

        if report_criteria:
            attrs_ops_vals, show_attrs = self.parse_report_criteria(report_criteria)
            search_criteria = {'project': member_document['project']}
            for (attr, op, val) in attrs_ops_vals:
                if op == "=":
                    search_criteria[attr] = val
                elif op == "!=":
                    search_criteria[attr] = {'$ne': val}
                elif op == "<":
                    search_criteria[attr] = {'$lt': val}
                elif op == ">":
                    search_criteria[attr] = {'$gt': val}
                elif op == "in":
                    search_criteria[attr] = {'$in': val}
                elif op == "nin":
                    search_criteria[attr] = {'$nin': val}

            content.append('<table class="sortable"><thead><tr>')
            for attr in show_attrs:
                content.append('<th><span>'+attr+'</span></th>')

            content.append('</tr></thead><tbody>')

            for card_document in self.cards_collection.find(search_criteria):
                content.append('<tr>')
                for attr in show_attrs:
                    if attr in card_document:
                        content.append(f'<td>{card_document[attr]}</td>')
                    else:
                        content.append('<td>-</td>')

                content.append('</tr>')

            content.append('</tbody></table>')

        content.append('<hr><p>'+report_criteria+' <form action="/reports/report_generator" method="post"><input type="hidden" name="reportname" value="'+reportname+'"><input type="hidden" name="reportcriteria" value="'+report_criteria+'"><input type="submit" value="Edit"></form></p>')
        content.append('</div>')
        content.append('<script type="text/javascript" src="/scripts/listview.js"></script>')

        content.append('</div>')
        content.append(Kanbanara.footer(self))
        return "".join(content)

    @cherrypy.expose
    def report_manager(self):
        """comment"""
        username = Kanbanara.check_authentication(f'/{self.component}/report_manager')
        session_id = Kanbanara.cookie_handling(self)
        session_document = self.sessions_collection.find_one({"session_id": session_id})
        member_document = Kanbanara.get_member_document(self, session_document)
        content = []
        content.append(Kanbanara.header(self, 'report_manager', "Report Manager"))
        content.append(Kanbanara.filter_bar(self, 'report_manager'))
        content.append(Kanbanara.menubar(self))
        content.append('<div align="center">')
        content.append(self.insert_page_title_and_online_help(session_document, 'report_manager', 'Report Manager'))
        reports = member_document.get('reports', [])
        if reports:
            content.append('<table><tr><th>Report Name</th><th>Report Criteria</th><td></td></tr>')
            for report_document in reports:
                content.append('<tr><td><a href="/reports/report?reportname='+report_document['reportname']+'">'+report_document['reportname']+'</a></td><td>'+report_document['reportcriteria']+'</td><td><form action="/reports/delete_report" method="post"><input type="hidden" name="reportname" value="'+report_document['reportname']+'"><input type="submit" value="Delete"></form></td></tr>')

            content.append('</table>')
        else:
            content.append('<p>There are no custom reports</p>')

        content.append('</div>')
        content.append(Kanbanara.footer(self))
        return "".join(content)

    @cherrypy.expose
    def times_report(self):
        """comment"""
        username = Kanbanara.check_authentication(f'/{self.component}')
        session_id = Kanbanara.cookie_handling(self)
        session_document = self.sessions_collection.find_one({"session_id": session_id})
        content = []
        estimated_times_total = 0
        actual_times_total = 0
        content.append(Kanbanara.header(self, 'times_report', "Times Report"))
        content.append(Kanbanara.filter_bar(self, 'times_report'))
        content.append(Kanbanara.menubar(self))
        content.append('<div align="center">')
        content.append(self.insert_page_title_and_online_help(session_document, 'times_report', 'Times Report'))
        required_columns, required_states = self.get_displayable_columns()
        _, _, owner_reviewer_search_criteria = self.get_filtered_search_criteria(session_document, required_states)
        owner_reviewer_search_criteria["estimatedtime"] = {"$exists": True,"$ne":""}
        documents = self.cards_collection.find(owner_reviewer_search_criteria).sort("estimatedtime")

        content.append('<table class="unsortable"><thead><tr><th>ID</th><th>Title</th><th>State</th><th>Estimated Time</th><th>Actual Time</th></tr></thead><tbody>')
        for document in documents:
            content.append('<tr class="'+document['type']+'">')
            content.append(f'<td>{document["id"]}</td>')
            if 'title' in document and document['title']:
                content.append('<td>'+document['title']+'</td>')
            else:
                content.append('<td></td>')

            content.append('<td>'+document['state']+'</td>')
            content.append(f'<td>{document["estimatedtime"]}</td>')
            estimated_times_total += float(document['estimatedtime'])
            content.append(f'<td>{document["actualtime"]}</td>')
            actual_times_total += float(document['actualtime'])
            content.append('</tr>')

        content.append(f'<tr><th colspan="3">Total:</th><td>{estimated_times_total}</td><td>{actual_times_total}</td></tr>')
        content.append('</tbody></table>')
        content.append('</div>')
        content.append(Kanbanara.footer(self))
        return "".join(content)

    @cherrypy.expose
    def statusreport(self):
        """comment"""
        username = Kanbanara.check_authentication(f'/{self.component}')
        session_id = Kanbanara.cookie_handling(self)
        content = []
        content.append(Kanbanara.header(self, "statusreport", "Status Report"))
        content.append(Kanbanara.filter_bar(self, 'statusreport'))
        content.append(Kanbanara.menubar(self))
        session_document = self.sessions_collection.find_one({"session_id": session_id})
        member_document = Kanbanara.get_member_document(self, session_document)
        search_criteria = {}
        if 'type' in session_document and session_document['type']:
            search_criteria['type'] = session_document['type']

        required_columns, allowable_states = self.get_displayable_columns()
        if allowable_states:
            search_criteria['state'] = {"$in":allowable_states}

        if "teammember" in member_document and member_document['teammember']:
            if member_document['teammember'] == 'Unassigned':
                content.append('<h2 align="center">Unassigned Status Report</h2>')
            else:
                content.append('<h2 align="center">'+member_document['teammember']+"'s Status Report</h2>")

            search_criteria['owner'] = member_document['teammember']
        else:
            content.append('<h2 align="center">Status Report</h2>')

        if "project" in session_document and session_document['project']:
            search_criteria['project'] = session_document['project']
        else:
            allowable_projects = self.get_member_projects(member_document)
            if allowable_projects:
                search_criteria['project'] = {"$in":allowable_projects}

        projects = sorted(self.cards_collection.find(search_criteria).distinct('project'))

        selected_release = ""
        if 'release' in session_document and session_document['release']:
            selected_release = session_document['release']

        selected_iteration = ""
        if 'iteration' in session_document and session_document['iteration']:
            selected_iteration = session_document['iteration']

        # TODO - THIS SHOULD ONLY BE FOR THE CURRENT PROJECT!
        for project in projects:
            search_criteria['project'] = project
            content.append('<h3>&nbsp;&nbsp;'+project+'</h3>')
            if selected_release:
                search_criteria['release'] = selected_release

            releases = sorted(self.cards_collection.find(search_criteria).distinct('release'))
            if releases:
                for release in releases:
                    if selected_iteration:
                        search_criteria['iteration'] = selected_iteration

                    iterations = sorted(self.cards_collection.find(search_criteria).distinct('iteration'))
                    if iterations:
                        for iteration in iterations:
                            if release != iteration:
                                content.append('<h4>&nbsp;&nbsp;&nbsp;&nbsp;'+release+' &rArr; '+iteration+'</h4>')
                            else:
                                content.append('<h4>&nbsp;&nbsp;&nbsp;&nbsp;'+iteration+'</h4>')

                            # OPERATION DYNAMIC WORKFLOW
                            for (title, states) in [('Closed', ['closed']), ('Accepted', ['accepted']),
                                                    ('Testing', ['developed', 'testing']),
                                                    ('Development', ['analysed', 'development']),
                                                    ('Analysis', ['defined', 'analysis']),
                                                    ('Backlog', ['backlog'])]:
                                revised_states = [state for state in states if state in allowable_states]
                                search_criteria['state'] = {"$in":revised_states}
                                if self.cards_collection.find(search_criteria).count():
                                    content.append('<h5>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'+title+'</h5>')
                                    for document in self.cards_collection.find(search_criteria):
                                        content.append('<h6>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8226; ')
                                        if 'externalreference' in document and document['externalreference']:
                                            content.append(document['externalreference']+' - ')

                                        if 'title' in document:
                                            content.append(document['title'])
                                        elif 'description' in document:
                                            content.append(document['description'])

                                        content.append('</h6>')
                                        if 'status' in document:
                                            status = document['status']
                                            status = status.replace('\r\n', '<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;')
                                            status = status.replace('\r', '<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;')
                                            status = status.replace('\n', '<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;')
                                            content.append('<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'+status+'</p>')

                    else:
                        # OPERATION DYNAMIC WORKFLOW
                        for (title, states) in [('Closed', ['closed']), ('Accepted', ['accepted']),
                                                ('Testing', ['developed', 'testing']),
                                                ('Development', ['analysed', 'development']),
                                                ('Analysis', ['defined', 'analysis']), ('Backlog', ['backlog'])]:
                            revised_states = [state for state in states if state in allowable_states]
                            search_criteria['state'] = {"$in":revised_states}
                            if self.cards_collection.find(search_criteria).count():
                                content.append('<h5 class="statusreport">'+title+'</h5>')
                                for document in self.cards_collection.find(search_criteria):
                                    content.append('<h6 class="statusreport">')
                                    if 'externalreference' in document and document['externalreference']:
                                        content.append(document['externalreference']+' - ')

                                    if 'title' in document:
                                        content.append(document['title'])
                                    elif 'description' in document:
                                        content.append(document['description'])

                                    content.append('</h6>')
                                    if 'status' in document:
                                        status = Kanbanara.format_multiline(document['status'])
                                        content.append('<p class="statusreport">'+status+'</p>')

            else:
                # OPERATION DYNAMIC WORKFLOW
                for (title, states) in [('Closed', ['closed']), ('Accepted', ['accepted']),
                                        ('Testing', ['developed', 'testing']),
                                        ('Development', ['analysed', 'development']),
                                        ('Analysis', ['defined', 'analysis']), ('Backlog', ['backlog'])]:
                    revised_states = [state for state in states if state in allowable_states]
                    search_criteria['state'] = {"$in":revised_states}
                    if self.cards_collection.find(search_criteria).count():
                        content.append('<h5 class="statusreport">'+title+'</h5>')
                        for document in self.cards_collection.find(search_criteria):
                            content.append('<h6 class="statusreport">')
                            if 'externalreference' in document and document['externalreference']:
                                content.append(document['externalreference']+' - ')

                            if 'title' in document:
                                content.append(document['title'])
                            elif 'description' in document:
                                content.append(document['description'])

                            content.append('</h6>')
                            if 'status' in document:
                                status = Kanbanara.format_multiline(document['status'])
                                content.append('<p class="statusreport">'+status+'</p>')

        content.append(self.footer("Status Report"))
        return "".join(content)

currentDir = os.path.dirname(os.path.abspath(__file__))
conf = {'/': {'tools.staticdir.root':   currentDir,
              'tools.sessions.on':      True,
              'tools.sessions.locking': 'explicit'
              }}
for directory in ['css', 'images']:
    if os.path.exists(currentDir+os.sep+directory):
        conf['/'+directory] = {'tools.staticdir.on':  True,
                               'tools.staticdir.dir': directory}

cherrypy.tree.mount(Reports(), '/reports', config=conf)
