#!/usr/bin/perl -wT
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# Contributor(s): Christian Reis <kiko@async.com.br>
#                 Shane H. W. Travis <travis@sedsystems.ca>
#
use strict;

use lib qw(.);

use Bugzilla::Bug;       # EmitDependList
use Bugzilla::Util;      # trim
use Bugzilla::Constants; # LOGIN_*
use Bugzilla::User;      # UserInGroup
use Bugzilla;
use Bugzilla::Error;
use Bugzilla::Product;
use Bugzilla::Milestone;


sub get_bugs_by_milestones {
    my $sth = query_bugs_by_milestones(@_);
    my %res;
    while (my $row = $sth->fetch) {
            my $milestone_value = $row->[0];
            push @{$res{$milestone_value}}, { bug_id => $row->[1],
                                         short_desc => $row->[2],
                                         component => $row->[3],
                                         bug_severity => $row->[4],
                                         bug_status => $row->[5],
                                         resolution => $row->[6] };
        }
    return \%res;
}

sub get_info_by_milestones {
    my $sth = query_info_by_milestones(@_);
    my %res;
    while (my $row = $sth->fetch) {
            my $milestone_value = $row->[0];
            push @{$res{$milestone_value}}, { deadline => $row->[1],
                                         open => $row->[2],
                                         closed => $row->[3],
					 total => $row->[4], 
					 perc_open => ($row->[2]*100/$row->[4]),
					 perc_closed => ($row->[3]*100/$row->[4]) };
        }
    return \%res;
}

sub get_desc_by_bugs {
    my $sth = query_desc_by_bugs(@_);
    my %res;
    my $bug_id = 0;
    while (my $row = $sth->fetch) {
            if ($bug_id != $row->[0]) {
		push @{$res{$row->[0]}}, { thetext => $row->[1]};
		$bug_id = $row->[0];
	    }
        }
    return \%res;
}

sub query_bugs_by_milestones {
    my ($bugids) = @_;
    my $dbh = Bugzilla->dbh;

    # $bugids is guaranteed to be non-empty because at least one bug is
    # always provided to this page.
    my $buglist = join ", ", @{$bugids};

    # Returns the total time worked on each bug *per developer*, with
    # bug descriptions and developer address
    my $q = qq{SELECT
			bugs.target_milestone,bugs.bug_id,bugs.short_desc,
			components.name,bugs.bug_severity,bugs.bug_status,
			bugs.resolution
		FROM
			bugs,
			milestones,
			components
		WHERE 
			bugs.bug_id in ($buglist)
			AND bugs.component_id = components.id	
			AND bugs.product_id = milestones.product_id and bugs.target_milestone = milestones.value
		ORDER BY milestones.sortkey desc,bugs.delta_ts desc};	
    my $sth = $dbh->prepare($q);
    $sth->execute();
    return $sth;
}

sub query_info_by_milestones {
    my ($bugids) = @_;
    my $dbh = Bugzilla->dbh;

    # $bugids is guaranteed to be non-empty because at least one bug is
    # always provided to this page.
    my $buglist = join ", ", @{$bugids};

    # Returns the total time worked on each bug *per developer*, with
    # bug descriptions and developer address
    my $q = qq{SELECT
			bugs.target_milestone,
			max(bugs.deadline),
			sum(CASE bug_status WHEN 'RESOLVED' THEN 0 WHEN 'CLOSED' THEN 0 WHEN 'VERIFIED' THEN 0 ELSE 1 END),
			sum(CASE bug_status WHEN 'RESOLVED' THEN 1 WHEN 'CLOSED' THEN 1 WHEN 'VERIFIED' THEN 1 ELSE 0 END),
			sum(1)
		FROM
			bugs
		WHERE 
			bugs.bug_id in ($buglist)
		GROUP BY
			bugs.target_milestone
		};	
    my $sth = $dbh->prepare($q);
    $sth->execute();
    return $sth;
}

sub query_desc_by_bugs {
    my ($bugids) = @_;
    my $dbh = Bugzilla->dbh;

    # $bugids is guaranteed to be non-empty because at least one bug is
    # always provided to this page.
    my $buglist = join ", ", @{$bugids};

    # Returns the total time worked on each bug *per developer*, with
    # bug descriptions and developer address
    my $q = qq{SELECT
			bugs.bug_id,
			longdescs.thetext
		FROM
			bugs,
			longdescs
		WHERE 
			bugs.bug_id in ($buglist)
			AND bugs.bug_id = longdescs.bug_id
			AND (longdescs.thetext like 'Description:%' or bugs.creation_ts = longdescs.bug_when)
		ORDER by bugs.bug_id,longdescs.bug_when desc};	
    my $sth = $dbh->prepare($q);
    $sth->execute();
    return $sth;
}


# If we're using bug groups for products, we should apply those restrictions
# to viewing reports, as well.  Time to check the login in that case.


Bugzilla->login(LOGIN_REQUIRED);
my $cgi = Bugzilla->cgi;

Bugzilla->switch_to_shadow_db();

my $user = Bugzilla->login();
my $template = Bugzilla->template;
my $vars = {};
my $dbh = Bugzilla->dbh;
	

# Display the menu
$vars->{'classifications'} = $user->get_selectable_classifications;
my $product = $cgi->param('product');
my $limitsql = '';

if (!$cgi->param('viewall') && !$cgi->param('milestone')) {
	$vars->{'viewlimited'} = 'yes';
	$limitsql = 'LIMIT 10';
}

if ($product) { 

	# We only want those products that the user has permissions for.
	my @myproducts;
	push( @myproducts, map { $_->name } @{$user->get_selectable_products} );

	# For security and correctness, validate the value of the "product" form variable.
	# Valid values are those products for which the user has permissions which appear
	# in the "product" drop-down menu on the report generation form.
	grep($_ eq $product, @myproducts) || ($product eq "0")
	|| ThrowUserError("invalid_product_name", {product => $product});

	# We've checked that the product exists, and that the user can see it
	# This means that is OK to detaint

	my $product_obj = new Bugzilla::Product({ name => $product });
	my $product_id = $product_obj->id;
	trick_taint($product_id);

	my $milestone = $cgi->param('milestone');
	if (defined $cgi->param('milestone')) {
		my $valid_milestones = new Bugzilla::Milestone({ product => $product_obj, name => $milestone }) || ThrowUserError("invalid_product_name", {product => $product});
		trick_taint($milestone);
	}

	# Select all the milesones for the product selected

	my @milestones;
	if ($milestone) {
		push @milestones,$milestone;
	} else { 
		my $q2 = qq{SELECT distinct target_milestone from bugs,milestones 
				where milestones.product_id = $product_id
				and bugs.product_id = $product_id
				and bugs.target_milestone = milestones.value
				order by sortkey desc 
				$limitsql};
		my $sth = $dbh->prepare($q2);
		$sth->execute();
		while (my $row2 = $sth->fetch) {
			push @milestones,$row2->[0];
		}
	}

	my $milestonelist = join "','", @milestones;
	$milestonelist="'".$milestonelist."'";
	
	# Select all the bugs that are in the product (/milestone) selected 

	my @ids;
	my $q = qq{SELECT bug_id from bugs where product_id = $product_id
			AND bugs.target_milestone in ($milestonelist)
			AND ((bugs.target_milestone <> "---") or (bugs.bug_status <> \"CLOSED\" 
			OR bugs.delta_ts > now() - INTERVAL 1 MONTH))};
	my $sth2 = $dbh->prepare($q);
	$sth2->execute();
	while (my $row = $sth2->fetch) {
		push @ids,$row->[0];
	}	
	@ids = grep { Bugzilla->user->can_see_bug($_) } @ids;
	
	
	$vars->{'product'} = $product;
	$vars->{'milestones'} = \@milestones;
	$vars->{'bugs'} = get_bugs_by_milestones(\@ids);
	$vars->{'milestonesinfo'} = get_info_by_milestones(\@ids);

	if ($milestone) {
		$vars->{'bugs_desc'} = get_desc_by_bugs(\@ids);
	}
}

my $ctype = scalar($cgi->param("ctype"));
my $format = $template->get_format("reports/releases", undef, $ctype);

# Get the proper content-type
print $cgi->header(-type=> $format->{'ctype'});

$template->process("$format->{'template'}", $vars)
  || ThrowTemplateError($template->error());

  


