import posixpath

from parallels.core.logging import get_logger
from parallels.core import messages
from parallels.core.utils.common import obj

logger = get_logger(__name__)

PERMISSION_CHANGE_MODE = obj(
    # change permissions on specified file only
    SELF='self', 
    # recursively change permissions on all files inside a directory
    # (but do not touch the directory itself, and do not touch directories)
    SUBFILES_AND_SUBDIRS='sub',
)


class PermissionRule(object):
    """Entity that represents a rule to change file permissions"""
    def __init__(self, mode, path, user=None, group=None, permissions=None):
        """Create object
        Arguments:
        mode - one of PERMISSION_CHANGE_MODE
        path - (string) relative path to file/directory to change permissions
        user - (string) system user name, for chown input
        group - (string) system group name, for chgrp input
        permissions - (string) permissions, for chmod input
        """
        self.mode = mode
        self.path = path
        self.user = user
        self.group = group
        self.permissions = permissions

    def __repr__(self):
        return \
            'PermissionRule(mode=%r, path=%r, user=%r, group=%r, permissions=%r)' % (
                self.mode, self.path, self.user, self.group, self.permissions
            )


def bulk_change_permissions(runner, root_path, permissions_list):
    """Change permissions for files according to permissions list
    
    permissions_list is a list of PermissionRule objects
    root_path - is prepended to path attribute of each permission rule
    
    Function iterates by the list one-by-one and changes permissions,
    so consider to put them in correct order
    
    :type runner: parallels.core.runners.base.BaseRunner
    """
    logger.debug(
        messages.CHANGE_PERMISSIONS_ACCORDING_FOLLOWING_RULES_S,
        permissions_list
    )
        
    for permission in permissions_list:
        full_path = posixpath.join(
            root_path, permission.path
        )

        if not runner.file_exists(full_path):
            continue  # simply ignore if file/dir does not exist

        if permission.mode == PERMISSION_CHANGE_MODE.SELF:
            if permission.user is not None:
                runner.execute_command('chown {user} {path}', dict(
                    user=permission.user, path=full_path
                ))
            if permission.group is not None:
                runner.execute_command('chgrp {group} {path}', dict(
                    group=permission.group, path=full_path
                ))
            if permission.permissions is not None:
                runner.execute_command('chmod {perm} {path}', dict(
                    perm=permission.permissions, path=full_path
                ))
        elif permission.mode == PERMISSION_CHANGE_MODE.SUBFILES_AND_SUBDIRS:
            runner.execute_command(
                'find {path} -mindepth 1 -exec chown {user}:{group} {{}} \\;',
                dict(
                    path=full_path, 
                    user=permission.user,
                    group=permission.group
                )
            )
        else:
            assert False
