#!%PERL%
# Copyright (c) vhffs project and its contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without 
# modification, are permitted provided that the following conditions 
# are met:
#
# 1. Redistributions of source code must retain the above copyright 
#   notice, this list of conditions and the following disclaimer.
#2. Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in 
#   the documentation and/or other materials provided with the 
#   distribution.
#3. Neither the name of vhffs nor the names of its contributors 
#   may be used to endorse or promote products derived from this 
#   software without specific prior written permission.
#
#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
#FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
#COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
#INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
#BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
# POSSIBILITY OF SUCH DAMAGE.

use strict;
use utf8;

package Vhffs::Panel::Group;

use DBI;
use POSIX qw(locale_h);
use HTML::Template;
use locale;
use Locale::gettext;
use CGI;
use CGI::Session;
use Vhffs::User;
use Vhffs::Main;
use Vhffs::Panel::Main;

=head1 NAME

Vhffs::Panel::Group - Handle group information in the panel.

=head1 METHODS

=head2 getall_users

    $users = Vhffs::Panel::Group::getall_users( $vhffs, $gid );

Returns an array of hashes {uid, username, state} containing all users of
the given group (C<state> is a descriptive string).

=cut

sub getall_users
{
    my ($main, $gid) = @_;
    my $sql = 'SELECT u.uid, u.username, u.firstname, u.lastname, u.mail, ug.state FROM vhffs_users u INNER JOIN vhffs_user_group ug ON ug.uid = u.uid WHERE ug.gid = ?';
    my $dbh = $main->get_db_object;
    my $sth = $dbh->prepare($sql) or return -1;
    $sth->execute($gid) or return -2;
    my $users = [];
    while(my $u = $sth->fetchrow_hashref) {
        $u->{active} = ($u->{state} == Vhffs::Constants::ACTIVATED);
        $u->{state} = Vhffs::Functions::status_string_from_status_id($u->{state});
        push @$users, $u;
    }
    return $users;
}

sub get_last_groups {
    my $main = shift;
    my @groups;

    my $sql = 'SELECT g.gid, g.groupname, g.realname, o.description, owner.username AS owner_name FROM vhffs_groups g LEFT OUTER JOIN vhffs_users u ON u.username=g.groupname INNER JOIN vhffs_object o ON o.object_id=g.object_id INNER JOIN vhffs_users owner ON owner.uid = o.owner_uid WHERE o.state=? AND u.username IS NULL ORDER BY o.date_creation DESC LIMIT 10';

    return fetch_groups_and_users($main, $sql, Vhffs::Constants::ACTIVATED);
}

sub search
{
    my ($main, $name) = @_;
    my $sql;
    my @params;
    my $groups = [];

	if( defined $name ) {
		$sql =  'SELECT g.groupname, o.state, u.username FROM vhffs_groups g INNER JOIN vhffs_object o ON g.object_id = o.object_id INNER JOIN vhffs_users u ON u.uid = o.owner_uid WHERE g.groupname LIKE ?';
        push(@params, '%'.lc($name).'%');
	} else {
		$sql =  'SELECT g.groupname, o.state, u.username FROM vhffs_groups g INNER JOIN vhffs_object o ON g.object_id = o.object_id INNER JOIN vhffs_users u ON u.uid = o.owner_uid WHERE g.groupname NOT IN ( SELECT username FROM vhffs_users )';
	}
    my $dbh = $main->get_db_object();
    my $sth = $dbh->prepare( $sql ) or return undef;

    return undef unless ( $sth->execute(@params) );

    while(my $g = $sth->fetchrow_hashref('NAME_lc')) {
        $g->{state} = Vhffs::Functions::status_string_from_status_id($g->{state});
        push(@$groups, $g);
    }

    return $groups;
}


sub public_search {
    my ($main, $groupname, $description, $included_tags, $excluded_tags, $start) = @_;

    my $sql =
' FROM vhffs_groups g 
	LEFT OUTER JOIN vhffs_users u ON u.username=g.groupname
	INNER JOIN vhffs_object o ON o.object_id=g.object_id
	INNER JOIN vhffs_users owner ON owner.uid = o.owner_uid
	WHERE o.state=? AND u.username IS NULL';

	my @params;
    push @params, Vhffs::Constants::ACTIVATED;
    
	if($groupname =~ /\S/) {
		$sql .= ' AND g.groupname ILIKE ?';
		push @params, '%'.$groupname.'%';
	}
	
	if($description =~ /\S/) {
		$sql .= ' AND o.description ILIKE ? ';
		push @params, '%'.$description.'%';
	}
	
	if(scalar(@$included_tags)) {
		$sql .= ' AND o.object_id IN (SELECT ot.object_id from vhffs_object_tag ot WHERE ot.tag_id IN(?';
		$sql .= ', ?' x (scalar(@$included_tags) - 1);
		$sql .= '))';
		push @params, @$included_tags;
	}
	
	if(scalar(@$excluded_tags)) {
		$sql .= ' AND o.object_id NOT IN (SELECT ot.object_id from vhffs_object_tag ot WHERE ot.tag_id IN(?';
		$sql .= ', ?' x (scalar(@$excluded_tags) - 1);
		$sql .= '))';
		push @params, @$excluded_tags;
	}
	
	my $limit = ' LIMIT 10';
	$limit .= ' OFFSET '.($start * 10) if(defined $start);
	
	my $select = 'SELECT g.gid, g.groupname, g.realname, o.description, owner.username AS owner_name'.$sql.' ORDER BY groupname '.$limit;
    	my $groups = fetch_groups_and_users($main, $select, @params);

	my $dbh = $main->get_db_object();
	
	my $sth = $dbh->prepare('SELECT COUNT(*)'.$sql);
	return undef unless ( $sth->execute(@params) );
	
	my ($count) = $sth->fetchrow_array();
	
	return ($groups, $count);
}

sub getall_groups_per_user
{
	my ( $user , $main ) = @_;

	return undef if ( ! defined $user );

	my $query = "SELECT g.groupname , g.object_id, o.state  FROM vhffs_groups g, vhffs_user_group ug , vhffs_object o WHERE o.object_id=g.object_id AND ug.gid=g.gid AND ug.uid='".$user->{'uid'}."'";

	my $request = $main->{'db'}->prepare( $query ) or return -1;
	my @retour;

	return undef if ( $request->execute() <= 0);
	return ( $request->fetchall_hashref( 'groupname' ) );
}

=head2 create_group($groupname, $user, $main)

Create a new group with specified name and the
specified user as owner. Owner if affected to
the group and an ACL is created in order to
allow him to delete group.

All arguments are mandatory

=over

=item $groupname: Name of the group

=item $user: Vhffs::User owner of the group (must be registered
in DB).

=item $main: Vhffs::Main instance

=cut

sub create_group
{
	my( $groupname , $realname, $user , $main, $description ) = @_;

	my $group = Vhffs::Group::create($main, $groupname, $realname, $user->get_uid, undef, $description);

    return undef unless( defined $group );

	return undef if ($group->add_user( $user->get_uid ) < 0 );

    return undef if ( Vhffs::Acl::add_acl( $user , $group , Vhffs::Constants::ACL_DELETE , $main ) < 0 ); 
    return undef if ( Vhffs::Acl::add_acl( $group , $group , Vhffs::Constants::ACL_VIEW , $main ) < 0 );

	return $group;
}

sub get_groups_starting_with {
    my ($main, $letter, $starting, $count) = @_;
    my @params;

    my $select_clause = 'SELECT g.gid, g.groupname, g.realname, o.description, owner.username as owner_name';
    my $sql = ' FROM vhffs_groups g '.
    	'LEFT OUTER JOIN vhffs_users u ON u.username=g.groupname '.
    	'INNER JOIN vhffs_object o ON o.object_id=g.object_id '.
    	'INNER JOIN vhffs_users owner ON owner.uid = o.owner_uid '.
    	'WHERE o.state=? AND u.username IS NULL';
    push @params, Vhffs::Constants::ACTIVATED;
    if(defined $letter) {
        $sql .=  ' AND SUBSTR(g.groupname, 1, 1) = ?';
        push @params, $letter;
    }
    
    my $order_clause = ' ORDER BY g.groupname LIMIT '.$count.' OFFSET '.$starting;
    return Vhffs::Panel::Commons::fetch_slice_and_count($main, $select_clause, $sql, ' ORDER BY groupname', $starting, $count, \@params, \&Vhffs::Panel::Group::fetch_groups_and_users);
}

sub fetch_groups_and_users {
    my ($main, $sql, @params) = @_;
    my @groups;


    my $dbh = $main->get_db_object;
    my $sth = $dbh->prepare($sql);
    $sql = 'SELECT u.username FROM vhffs_users u INNER JOIN vhffs_user_group ug ON ug.uid = u.uid WHERE ug.gid = ?';
    my $usth = $dbh->prepare($sql);
    # FIXME fetch object_id along with gid in every caller and suppress vhffs_groups from the query
    $sql = 'SELECT c.tag_category_id as category_id, c.label as category_label, t.tag_id, t.label as tag_label '.
            'FROM vhffs_tag t INNER JOIN vhffs_tag_category c ON c.tag_category_id = t.category_id '.
            'INNER JOIN vhffs_object_tag ot ON ot.tag_id = t.tag_id '.
            'INNER JOIN vhffs_groups g ON g.object_id = ot.object_id '.
            'WHERE g.gid = ? AND c.visibility = ?';
    my $tsth = $dbh->prepare($sql);
    $sth->execute(@params);
    while(my $row = $sth->fetchrow_hashref) {
        $usth->execute($row->{gid});
        $row->{users} = $usth->fetchall_arrayref({});
        $tsth->execute($row->{gid}, Vhffs::Constants::TAG_VISIBILITY_PUBLIC);
        $row->{tags} = $tsth->fetchall_arrayref({});
        push @groups, $row;
    }

    return \@groups;
}

sub get_used_letters {
    my $main = shift;
    my $dbh = $main->get_db_object;
    my $sql = 'SELECT substr(g.groupname, 1, 1) AS letter, COUNT(*) AS count FROM vhffs_groups g LEFT OUTER JOIN vhffs_users u ON u.username = g.groupname INNER JOIN vhffs_object o ON o.object_id = g.object_id WHERE u.username IS NULL AND o.state = ? GROUP BY substr(g.groupname, 1, 1) ORDER BY substr(g.groupname, 1, 1)';
    return $dbh->selectall_arrayref($sql, { Slice => {} }, Vhffs::Constants::ACTIVATED);
}

1;
