'Extract the Data'

def _extract(self, r, **attr):

    db = current.db
    s3db = current.s3db
    NONE = current.messages['NONE']
    project_id = r.id
    goals = {}
    table = s3db.project_goal
    query = ((table.project_id == project_id) & (table.deleted == False))
    rows = db(query).select(table.id, table.code, table.name, table.overall_status_by_indicators)
    for row in rows:
        goals[row.id] = dict(code=row.code, name=row.name, outcomes={}, status=row.overall_status_by_indicators)
    table = s3db.project_outcome
    query = ((table.project_id == project_id) & (table.deleted == False))
    rows = db(query).select(table.id, table.goal_id, table.code, table.name, table.overall_status_by_indicators)
    for row in rows:
        goals[row.goal_id]['outcomes'][row.id] = dict(code=row.code, name=row.name, outputs={}, status=row.overall_status_by_indicators)
    table = s3db.project_output
    query = ((table.project_id == project_id) & (table.deleted == False))
    rows = db(query).select(table.id, table.goal_id, table.outcome_id, table.code, table.name, table.overall_status_by_indicators)
    for row in rows:
        goals[row.goal_id]['outcomes'][row.outcome_id]['outputs'][row.id] = dict(code=row.code, name=row.name, indicators={}, status=row.overall_status_by_indicators)
    indicators = {}
    table = s3db.project_indicator
    query = ((table.project_id == project_id) & (table.deleted == False))
    rows = db(query).select(table.id, table.goal_id, table.outcome_id, table.output_id, table.code, table.name, table.overall_status_by_indicators)
    for row in rows:
        indicator_id = row.id
        goal_id = row.goal_id
        outcome_id = row.outcome_id
        output_id = row.output_id
        indicators[indicator_id] = dict(goal=goal_id, outcome=outcome_id, output=output_id)
        goals[goal_id]['outcomes'][outcome_id]['outputs'][output_id]['indicators'][indicator_id] = dict(code=row.code, name=row.name, dates={}, years={}, status=row.overall_status_by_indicators, target=0, actual=0)
    table = s3db.project_indicator_data
    query = (((table.project_id == project_id) & (table.end_date <= current.request.utcnow)) & (table.deleted == False))
    rows = db(query).select(table.indicator_id, table.end_date, table.target_value, table.value, orderby=table.end_date)
    dates = []
    dappend = dates.append
    years = []
    yappend = years.append
    for row in rows:
        date = row.end_date
        dappend(date)
        year = date.year
        yappend(year)
        indicator_id = row.indicator_id
        target = row.target_value
        actual = row.value
        i = indicators[indicator_id]
        indicator = goals[i['goal']]['outcomes'][i['outcome']]['outputs'][i['output']]['indicators'][indicator_id]
        if target:
            indicator['target'] += target
        if actual:
            indicator['actual'] += actual
        elif (actual is None):
            actual = NONE
        indicator['dates'][date] = dict(target=target, actual=actual)
        iyears = indicator['years']
        if (year in iyears):
            if target:
                iyears[year]['target'] += target
            if (actual != NONE):
                iyears[year]['actual'] += actual
        else:
            iyears[year] = dict(target=target, actual=actual)
    dates = set(dates)
    years = set(years)
    dates = [d for d in dates]
    dates.sort()
    years = [y for y in years]
    years.sort()
    goals = OrderedDict(sorted(goals.items(), key=(lambda x: x[1]['code'])))
    for goal in goals:
        outcomes = OrderedDict(sorted(goals[goal]['outcomes'].items(), key=(lambda x: x[1]['code'])))
        for outcome in outcomes:
            outputs = OrderedDict(sorted(outcomes[outcome]['outputs'].items(), key=(lambda x: x[1]['code'])))
            for output in outputs:
                indicators = OrderedDict(sorted(outputs[output]['indicators'].items(), key=(lambda x: x[1]['code'])))
                outputs[output]['indicators'] = indicators
            outcomes[outcome]['outputs'] = outputs
        goals[goal]['outcomes'] = outcomes
    return (dates, years, goals)
