# -*- coding: utf-8 -*-
#
# Copyright (C) 2007, 2008 by Jan Dittberner.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
#
# Version: $Id$

"""Tools for handling user and group information."""

import pwd
import grp


class PasswdUser(object):
    """This class represents users in the user database."""

    def __init__(self, username, passw, uid, gid, gecos, home, shell):
        """Create a new PasswdUser."""
        self.username = username
        self.uid = int(uid)
        self.gid = int(gid)
        self.gecos = gecos
        self.home = home
        self.shell = shell

    def __repr__(self):
        """Returns a user string representation."""
        return "%s(%s:%d:%d:%s:%s:%s)" % (self.__class__.__name__,
                                          self.username,
                                          self.uid,
                                          self.gid,
                                          self.gecos,
                                          self.home,
                                          self.shell)


class PasswdGroup(object):
    """This class represents lines in the groups database."""

    def __init__(self, groupname, passwd, gid, members):
        """Create a new PasswdGroup."""
        self.groupname = groupname
        self.gid = int(gid)
        self.members = members

    def __repr__(self):
        """Returns a group string representation."""
        return "%s(%s:%d:%s)" % (self.__class__.__name__,
                                 self.groupname,
                                 self.gid,
                                 ",".join(self.members))


def parse_groups():
    """Parses all available groups to PasswdGroup instances."""
    return [PasswdGroup(*arr) for arr in grp.getgrall()]


def parse_users():
    """Parses all available users to PasswdUser instances."""
    return [PasswdUser(*arr) for arr in pwd.getpwall()]


def find_user_by_prefix(prefix):
    """Finds all user entries with the given prefix."""
    return [user for user in parse_users() if user.username.startswith(prefix)]


def get_user_by_id(uid):
    """Gets the user with the given user id."""
    users = [user for user in parse_users() if user.uid == uid]
    if users:
        return users[0]
    return None


def get_group_by_id(gid):
    """Gets the group with the given group id."""
    groups = [group for group in parse_groups() if group.gid == gid]
    if groups:
        return groups[0]
    return None


def get_next_uid(lowerboundary = 10000, upperboundary = 65536):
    """Gets the first available user id in the given range.

    The returned uid is a value between lowerboundary and upper
    boundary. An exception is raised if no uid can be found.

    Keyword arguments:
    lowerboundary -- lower boundary for uid range
    upperboundary -- upper boundary for uid range

    """
    for uid in range(lowerboundary, upperboundary):
        try:
            pwd.getpwuid(uid)
        except KeyError:
            return uid
    raise Exception("no free uid found in range %d to %d",
                    lowerboundary, upperboundary)


def get_max_uid(boundary = 65536):
    """Gets the highest uid value."""
    return max([user.uid for user in parse_users() if user.uid <= boundary])


def get_max_gid(boundary = 65536):
    """Gets the highest gid value."""
    return max([group.gid for group in parse_groups() \
                if group.gid <= boundary])

if __name__ == "__main__":
    print "Max UID is %d" % (get_max_uid(40000))
    print "Max GID is %d" % (get_max_gid(40000))
    print "User with max UID is %s" % (get_user_by_id(get_max_uid(40000)))
    print "Group with max GID is %s" % (get_group_by_id(get_max_gid(40000)))
    print "First free UID is %s" % (get_next_uid(10000, 40000))