diff --git a/bootstrap.php b/bootstrap.php
index bb9eede3555e3ab0778c2c9dea054cf884ce0041..424f3637c1bc5cc9ecde66edd30fd07555490562 100644
--- a/bootstrap.php
+++ b/bootstrap.php
@@ -80,7 +80,7 @@ class Bootstrap {
         define('TEAM_TABLE',$prefix.'team');
         define('TEAM_MEMBER_TABLE',$prefix.'team_member');
         define('DEPT_TABLE',$prefix.'department');
-        define('GROUP_TABLE',$prefix.'groups');
+        define('GROUP_TABLE', $prefix.'group');
         define('GROUP_DEPT_TABLE', $prefix.'group_dept_access');
         define('ROLE_TABLE', $prefix.'role');
 
diff --git a/include/class.config.php b/include/class.config.php
index 164171a920a964493fbd24ebe969f814709c65ee..6fd4208b64e2f1e9a0f8fbc3aa5d44a8fb161704 100644
--- a/include/class.config.php
+++ b/include/class.config.php
@@ -39,6 +39,10 @@ class Config {
         if (!isset($_SESSION['cfg:'.$this->section]))
             $_SESSION['cfg:'.$this->section] = array();
         $this->session = &$_SESSION['cfg:'.$this->section];
+        $this->load();
+    }
+
+    function load() {
 
         $sql='SELECT id, `key`, value, `updated` FROM '.$this->table
             .' WHERE `'.$this->section_column.'` = '.db_input($this->section);
diff --git a/include/class.dept.php b/include/class.dept.php
index d80ceb28aa44c2aa3db88a423dc6fecbec858d13..a3129c909dfe991fe80b3588a5d098fa1d35a997 100644
--- a/include/class.dept.php
+++ b/include/class.dept.php
@@ -45,7 +45,7 @@ class Dept extends VerySimpleModel {
         ),
     );
 
-    var $members;
+    var $_members;
     var $_groupids;
     var $config;
 
@@ -97,11 +97,10 @@ class Dept extends VerySimpleModel {
     function getEmail() {
         global $cfg;
 
-        if(!$this->email)
-            if(!($this->email = Email::lookup($this->getEmailId())) && $cfg)
-                $this->email = $cfg->getDefaultEmail();
+        if ($this->email)
+            return $this->email;
 
-        return $this->email;
+        return $cfg? $cfg->getDefaultEmail() : null;
     }
 
     function getNumMembers() {
@@ -109,7 +108,7 @@ class Dept extends VerySimpleModel {
     }
 
     function getMembers($criteria=null) {
-        if (!$this->members || $criteria) {
+        if (!$this->_members || $criteria) {
             $members = Staff::objects()
                 ->filter(Q::any(array(
                     'dept_id' => $this->getId(),
@@ -132,9 +131,9 @@ class Dept extends VerySimpleModel {
             if ($criteria)
                 return $members->all();
 
-            $this->members = $members->all();
+            $this->_members = $members->all();
         }
-        return $this->members;
+        return $this->_members;
     }
 
     function getAvailableMembers() {
@@ -268,21 +267,30 @@ class Dept extends VerySimpleModel {
         return $this->_groupids;
     }
 
-    function updateGroups($groups_ids) {
+    function updateGroups($groups_ids, $vars) {
 
-        // Groups allowes to access department
+        // Groups allowed to access department
         if (is_array($groups_ids)) {
-            $groups = GroupDept::objects()
+            $groups = GroupDeptAccess::objects()
                 ->filter(array('dept_id' => $this->getId()));
             foreach ($groups as $group) {
-                if ($idx = array_search($group->group_id, $groups_ids))
+                if ($idx = array_search($group->group_id, $groups_ids)) {
                     unset($groups_ids[$idx]);
-                else
+                    $roleId = $vars['group'.$group->group_id.'_role_id'];
+                    if ($roleId != $group->role_id) {
+                        $group->set('role_id', $roleId ?: 0);
+                        $group->save();
+                    }
+                } else {
                     $group->delete();
+                }
             }
             foreach ($groups_ids as $id) {
-                GroupDept::create(array(
-                    'dept_id'=>$this->getId(), 'group_id'=>$id
+                $roleId = $vars['group'.$id.'_role_id'];
+                GroupDeptAccess::create(array(
+                    'dept_id' => $this->getId(),
+                    'group_id' => $id,
+                    'role_id' => $roleId ?: 0,
                 ))->save();
             }
         }
@@ -290,7 +298,7 @@ class Dept extends VerySimpleModel {
     }
 
     function updateSettings($vars) {
-        $this->updateGroups($vars['groups'] ?: array());
+        $this->updateGroups($vars['groups'] ?: array(), $vars);
         $this->getConfig()->set('assign_members_only', $vars['assign_members_only']);
         return true;
     }
@@ -302,9 +310,7 @@ class Dept extends VerySimpleModel {
             // Default department cannot be deleted
             || $this->getId()==$cfg->getDefaultDeptId()
             // Department  with users cannot be deleted
-            || Staff::objects()
-                ->filter(array('dept_id'=>$this->getId()))
-                ->count()
+            || $this->members->count()
         ) {
             return 0;
         }
@@ -482,7 +488,10 @@ class GroupDeptAccess extends VerySimpleModel {
                 'constraint' => array('dept_id' => 'Dept.id'),
             ),
             'group' => array(
-                'constraint' => array('group_id' => 'Group.group_id'),
+                'constraint' => array('group_id' => 'Group.id'),
+            ),
+            'role' => array(
+                'constraint' => array('role_id' => 'Role.id'),
             ),
         ),
     );
diff --git a/include/class.group.php b/include/class.group.php
index 48fe6dba40031feb556783b88f72a42d7080041c..3bbf296f5ecbfaf2173311ac1f23a4124b31746b 100644
--- a/include/class.group.php
+++ b/include/class.group.php
@@ -18,37 +18,79 @@ class Group extends VerySimpleModel {
 
     static $meta = array(
         'table' => GROUP_TABLE,
-        'pk' => array('group_id'),
+        'pk' => array('id'),
+        'joins' => array(
+            'members' => array(
+                'null' => true,
+                'list' => true,
+                'reverse' => 'Staff.group',
+            ),
+            'depts' => array(
+                'null' => true,
+                'list' => true,
+                'reverse' => 'GroupDeptAccess.group',
+            ),
+            'role' => array(
+                'constraint' => array('role_id' => 'Role.id')
+            ),
+        ),
     );
 
-    var $members;
+    const FLAG_ENABLED = 0X0001;
+
     var $departments;
 
     function getHashtable() {
         $base = $this->ht;
-        $base['name'] = $base['group_name'];
-        $base['isactive'] = $base['group_enabled'];
+        $base['name'] = $base['name'];
+        $base['isactive'] = $base['flags'];
         return $base;
     }
 
-    function getInfo(){
+    function getInfo() {
         return $this->getHashtable();
     }
 
-    function getId(){
-        return $this->group_id;
+    function getId() {
+        return $this->id;
+    }
+
+    function getRoleId() {
+        return $this->role_id;
     }
 
-    function getName(){
-        return $this->group_name;
+    function getRole($deptId=0) {
+
+        if ($deptId // Department specific role.
+                && ($roles=$this->getDepartmentsAccess())
+                && isset($roles[$deptId])
+                && $roles[$deptId]
+                && ($role=Role::lookup($roles[$deptId]))
+                && $role->isEnabled())
+            return $role;
+
+        // Default role for this group.
+        return $this->role;
     }
 
-    function getNumUsers(){
-        return Staff::objects()->filter(array('group_id'=>$this->getId()))->count();
+    function getName() {
+        return $this->name;
     }
 
-    function isEnabled(){
-        return $this->group_enabled;
+    function getCreateDate() {
+        return $this->created;
+    }
+
+    function getUpdateDate() {
+        return $this->updated;
+    }
+
+    function getNumMembers() {
+        return $this->members ? $this->members->count() : 0;
+     }
+
+    function isEnabled() {
+        $this->get('flags') & self::FLAG_ENABLED !== 0;
     }
 
     function isActive(){
@@ -81,34 +123,47 @@ class Group extends VerySimpleModel {
         return $this->members;
     }
 
-    //Get departments the group is allowed to access.
+    //Get departments & roles the group is allowed to access.
     function getDepartments() {
+        return array_keys($this->getDepartmentsAccess());
+    }
+
+    function getDepartmentsAccess() {
         if (!isset($this->departments)) {
             $this->departments = array();
             foreach (GroupDeptAccess::objects()
                 ->filter(array('group_id'=>$this->getId()))
-                ->values_flat('dept_id') as $gda
+                ->values_flat('dept_id', 'role_id') as $gda
             ) {
-                $this->departments[] = $gda[0];
+                $this->departments[$gda[0]] = $gda[1];
             }
         }
+
         return $this->departments;
     }
 
-
-    function updateDeptAccess($dept_ids) {
+    function updateDeptAccess($dept_ids, $vars=array()) {
         if (is_array($dept_ids)) {
             $groups = GroupDeptAccess::objects()
                 ->filter(array('group_id' => $this->getId()));
             foreach ($groups as $group) {
-                if ($idx = array_search($group->dept_id, $dept_ids))
+                if ($idx = array_search($group->dept_id, $dept_ids)) {
                     unset($dept_ids[$idx]);
-                else
+                    $roleId = $vars['dept'.$group->dept_id.'_role_id'];
+                    if ($roleId != $group->role_id) {
+                        $group->set('role_id', $roleId ?: 0);
+                        $group->save();
+                    }
+                } else {
                     $group->delete();
+                }
             }
             foreach ($dept_ids as $id) {
+                $roleId = $vars['dept'.$id.'_role_id'];
                 GroupDeptAccess::create(array(
-                    'group_id'=>$this->getId(), 'dept_id'=>$id
+                    'group_id' => $this->getId(),
+                    'dept_id' => $id,
+                    'role_id' => $roleId ?: 0
                 ))->save();
             }
         }
@@ -118,7 +173,7 @@ class Group extends VerySimpleModel {
     function delete() {
 
         // Can't delete with members
-        if ($this->getNumUsers())
+        if ($this->getNumMembers())
             return false;
 
         if (!parent::delete())
@@ -132,45 +187,8 @@ class Group extends VerySimpleModel {
         return true;
     }
 
-    /*** Static functions ***/
-    static function getIdByName($name){
-        $id = static::objects()->filter(array('group_name'=>trim($name)))
-            ->values_flat('group_id')->first();
-
-        return $id ? $id[0] : 0;
-    }
-
-    static function getGroupNames($localize=true) {
-        static $groups=array();
-
-        if (!$groups) {
-            $query = static::objects()
-                ->values_flat('group_id', 'group_name', 'group_enabled')
-                ->order_by('group_name');
-            foreach ($query as $row) {
-                list($id, $name, $enabled) = $row;
-                $groups[$id] = sprintf('%s%s',
-                    self::getLocalById($id, 'name', $name),
-                    $enabled ? '' : ' ' . __('(disabled)'));
-            }
-        }
-        // TODO: Sort groups if $localize
-        return $groups;
-    }
-
-    static function create($vars=false) {
-        $group = parent::create($vars);
-        $group->created = SqlFunction::NOW();
-        return $group;
-    }
-
-    static function __create($vars, &$errors) {
-        $g = self::create($vars);
-        $g->save();
-        if ($vars['depts'])
-            $g->updateDeptAccess($vars['depts']);
-
-        return $g;
+    function __toString() {
+        return $this->getName();
     }
 
     function save($refetch=false) {
@@ -181,40 +199,37 @@ class Group extends VerySimpleModel {
     }
 
     function update($vars,&$errors) {
-        if (isset($this->group_id) && $this->getId() != $vars['id'])
-            $errors['err']=__('Missing or invalid group ID');
+        if (isset($this->id) && $this->getId() != $vars['id'])
+            $errors['err'] = __('Missing or invalid group ID');
 
         if (!$vars['name']) {
-            $errors['name']=__('Group name required');
+            $errors['name'] = __('Group name required');
         } elseif(strlen($vars['name'])<3) {
-            $errors['name']=__('Group name must be at least 3 chars.');
+            $errors['name'] = __('Group name must be at least 3 chars.');
         } elseif (($gid=static::getIdByName($vars['name']))
-                && (!isset($this->group_id) || $gid!=$this->getId())) {
-            $errors['name']=__('Group name already exists');
+                && (!isset($this->id) || $gid!=$this->getId())) {
+            $errors['name'] = __('Group name already exists');
         }
 
+        if (!$vars['role_id'])
+            $errors['role_id'] = __('Role selection required');
+
         if ($errors)
             return false;
 
-        $this->group_name=Format::striptags($vars['name']);
-        $this->group_enabled=$vars['isactive'];
-        $this->can_create_tickets=$vars['can_create_tickets'];
-        $this->can_delete_tickets=$vars['can_delete_tickets'];
-        $this->can_edit_tickets=$vars['can_edit_tickets'];
-        $this->can_assign_tickets=$vars['can_assign_tickets'];
-        $this->can_transfer_tickets=$vars['can_transfer_tickets'];
-        $this->can_close_tickets=$vars['can_close_tickets'];
-        $this->can_ban_emails=$vars['can_ban_emails'];
-        $this->can_manage_premade=$vars['can_manage_premade'];
-        $this->can_manage_faq=$vars['can_manage_faq'];
-        $this->can_post_ticket_reply=$vars['can_post_ticket_reply'];
-        $this->can_view_staff_stats=$vars['can_view_staff_stats'];
-        $this->notes=Format::sanitize($vars['notes']);
+        $this->name = Format::striptags($vars['name']);
+        $this->role_id = $vars['role_id'];
+        $this->notes = Format::sanitize($vars['notes']);
+
+        if ($vars['isactive'])
+            $this->flags = ($this->flags | self::FLAG_ENABLED);
+        else
+            $this->flags =  ($this->flags & ~self::FLAG_ENABLED);
 
         if ($this->save())
-            return $this->updateDeptAccess($vars['depts'] ?: array());
+            return $this->updateDeptAccess($vars['depts'] ?: array(), $vars);
 
-        if (isset($this->group_id)) {
+        if (isset($this->id)) {
             $errors['err']=sprintf(__('Unable to update %s.'), __('this group'))
                .' '.__('Internal error occurred');
         }
@@ -224,5 +239,72 @@ class Group extends VerySimpleModel {
         }
         return false;
     }
+
+    /*** Static functions ***/
+    static function getIdByName($name){
+        $id = static::objects()->filter(array('name'=>trim($name)))
+            ->values_flat('id')->first();
+
+        return $id ? $id[0] : 0;
+    }
+
+    static function create($vars=false) {
+        $group = parent::create($vars);
+        $group->created = SqlFunction::NOW();
+        return $group;
+    }
+
+    static function __create($vars, &$errors) {
+        $g = self::create($vars);
+        $g->save();
+        if ($vars['depts'])
+            $g->updateDeptAccess($vars['depts'], $vars);
+
+        return $g;
+    }
+
+    static function getGroups($criteria=array()) {
+        static $groups = null;
+        if (!isset($groups) || $criteria) {
+            $groups = array();
+            $query = static::objects()
+                ->values_flat('id', 'name', 'flags')
+                ->order_by('name');
+
+            $filters = array();
+            if (isset($criteria['active']))
+                $filters += array(
+                        'isactive' => $criteria['active'] ? 1 : 0);
+
+            if ($filters)
+                $query->filter($filters);
+
+            $names = array();
+            foreach ($query as $row) {
+                list($id, $name, $flags) = $row;
+                $names[$id] = sprintf('%s%s',
+                    self::getLocalById($id, 'name', $name),
+                    $flags ? '' : ' ' . __('(disabled)'));
+            }
+
+            //TODO: sort if $criteria['localize'];
+            if ($criteria)
+                return $names;
+
+            $groups = $names;
+        }
+
+        return $groups;
+    }
+
+    static function getActiveGroups() {
+        static $groups = null;
+
+        if (!isset($groups))
+            $groups = self::getGroups(array('active'=>true));
+
+        return $groups;
+    }
+
 }
 ?>
diff --git a/include/class.staff.php b/include/class.staff.php
index 473dc42d23e82616e15890cfe68dfaea58508a79..ebdce1aaa0aa7da41cd0316fe33b897f903b2831 100644
--- a/include/class.staff.php
+++ b/include/class.staff.php
@@ -17,6 +17,7 @@ include_once(INCLUDE_DIR.'class.ticket.php');
 include_once(INCLUDE_DIR.'class.dept.php');
 include_once(INCLUDE_DIR.'class.error.php');
 include_once(INCLUDE_DIR.'class.team.php');
+include_once(INCLUDE_DIR.'class.role.php');
 include_once(INCLUDE_DIR.'class.group.php');
 include_once(INCLUDE_DIR.'class.passwd.php');
 include_once(INCLUDE_DIR.'class.user.php');
@@ -34,7 +35,7 @@ implements AuthenticatedUser {
                 'constraint' => array('dept_id' => 'Dept.id'),
             ),
             'group' => array(
-                'constraint' => array('group_id' => 'Group.group_id'),
+                'constraint' => array('group_id' => 'Group.id'),
             ),
             'teams' => array(
                 'null' => true,
@@ -276,7 +277,7 @@ implements AuthenticatedUser {
     }
 
     function isGroupActive() {
-        return $this->group->group_enabled;
+        return $this->group->isEnabled();
     }
 
     function isactive() {
@@ -602,7 +603,7 @@ implements AuthenticatedUser {
 
         if ($availableonly) {
             $members = $members->filter(array(
-                'group__group_enabled' => 1,
+                'group__flags__hasbit' => Group::FLAG_ENABLED,
                 'onvacation' => 0,
                 'isactive' => 1,
             ));
@@ -610,7 +611,7 @@ implements AuthenticatedUser {
 
         $users=array();
         foreach ($members as $M) {
-            $users[$M->id] = $M->getName();
+            $users[$M->getId()] = $M->getName();
         }
 
         return $users;
diff --git a/include/i18n/en_US/group.yaml b/include/i18n/en_US/group.yaml
index 66acefa239cab0722ed74bc0eb1dcc567926bc03..9354e343edc2add4fd535115349faef1e2911558 100644
--- a/include/i18n/en_US/group.yaml
+++ b/include/i18n/en_US/group.yaml
@@ -2,29 +2,11 @@
 # Default groups defined for the system
 #
 # Fields:
-# isactive - (bool:0|1) true or false if the group should be initially
-#       usable
+# id - Primary id for the group
+# role_id - (int)  default role for the group
+# flags - (bit mask) group flags
 # name - (string) descriptive name for the group
 # notes - (string) administrative notes (viewable internally only)
-# can_create_tickets - (bool:0|1) true or false if users of the group can
-#       create new tickets
-# can_edit_tickets - (bool:0|1) true or false if users of the group can
-#       modify and update existing tickets
-# can_delete_tickets - (bool:0|1) true or false if members of the group can
-#       delete tickets (permanently)
-# can_close_tickets - (bool:0|1) true or false if members of the group can
-#       close active tickets
-# can_assign_ticets - (bool:0|1) true or false if members of the group can
-#       assign tickets to staff
-# can_transfer_tickets - (bool:0|1) true or false if members of the group
-#       can change the department tickets are assigne dto
-# can_ban_emails - (bool:0|1) true or false if members of the group can add
-#       emails to the system ban list
-# can_manage_premade - (bool:0|1) true or false if members of the group can
-#       create, modify, and delete canned responses
-# can_manage_faq - (bool:0|1) true or false if members of the group can
-#       manage the customer-facing and internal knowledgebase
-#
 # depts: (list<Department<id>>) id's of the departments to which the group
 #       should initially have access
 #
@@ -32,54 +14,30 @@
 # The very first group listed in this document will be the primary group of
 # the initial staff member -- the administrator.
 ---
-- group_enabled: 1
-  group_name: Lion Tamers
+- id: 1
+  role_id: 1
+  flags: 1
+  name: Lion Tamers
   notes: |
     System overlords. These folks (initially) have full control to all the
     departments they have access to.
-  can_create_tickets: 1
-  can_edit_tickets: 1
-  can_delete_tickets: 1
-  can_close_tickets: 1
-  can_assign_tickets: 1
-  can_transfer_tickets: 1
-  can_ban_emails: 1
-  can_manage_premade: 1
-  can_manage_faq: 1
-  can_post_ticket_reply: 1
 
   depts: [1, 2, 3]
 
-- group_enabled: 1
-  group_name: Elephant Walkers
+- id: 2
+  role_id: 2
+  flags: 1
+  name: Elephant Walkers
   notes: |
     Inhabitants of the ivory tower
-  can_create_tickets: 1
-  can_edit_tickets: 1
-  can_delete_tickets: 1
-  can_close_tickets: 1
-  can_assign_tickets: 1
-  can_transfer_tickets: 1
-  can_ban_emails: 1
-  can_manage_premade: 1
-  can_manage_faq: 1
-  can_post_ticket_reply: 1
 
   depts: [1, 2, 3]
 
-- group_enabled: 1
-  group_name: Flea Trainers
+- id: 3
+  role_id: 3
+  flags: 1
+  name: Flea Trainers
   notes: |
     Lowly staff members
-  can_create_tickets: 1
-  can_edit_tickets: 1
-  can_delete_tickets: 0
-  can_close_tickets: 1
-  can_assign_tickets: 1
-  can_transfer_tickets: 1
-  can_ban_emails: 0
-  can_manage_premade: 0
-  can_manage_faq: 0
-  can_post_ticket_reply: 1
 
   depts: [1, 2, 3]
diff --git a/include/staff/department.inc.php b/include/staff/department.inc.php
index 7681645200ae9f88d6e3171cf987bc91342ba8f5..6828b06925d9bdee216ed73825707b5e8eafeae7 100644
--- a/include/staff/department.inc.php
+++ b/include/staff/department.inc.php
@@ -7,10 +7,9 @@ if($dept && $_REQUEST['a']!='add') {
     $title=__('Update Department');
     $action='update';
     $submit_text=__('Save Changes');
-    $info=$dept->getInfo();
-    $info['id']=$dept->getId();
+    $info = $dept->getInfo();
+    $info['id'] = $dept->getId();
     $info['groups'] = $dept->getAllowedGroups();
-
     $qstr.='&id='.$dept->getId();
 } else {
     $title=__('Add New Department');
@@ -23,8 +22,10 @@ if($dept && $_REQUEST['a']!='add') {
         $info['group_membership'] = 1;
 
     $qstr.='&a='.$_REQUEST['a'];
+
 }
-$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
+
+$info = Format::htmlchars(($errors && $_POST) ? $_POST : $info);
 ?>
 <form action="departments.php?<?php echo $qstr; ?>" method="post" id="save">
  <?php csrf_token(); ?>
@@ -32,6 +33,14 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
  <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
  <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
  <h2><?php echo __('Department');?></h2>
+<br>
+<ul class="tabs">
+    <li class="active"><a href="#settings">
+        <i class="icon-file"></i> <?php echo __('Settings'); ?></a></li>
+    <li><a href="#access">
+        <i class="icon-lock"></i> <?php echo __('Access'); ?></a></li>
+</ul>
+<div id="settings" class="tab_content">
  <table class="form_table" width="940" border="0" cellspacing="0" cellpadding="2">
     <thead>
         <tr>
@@ -47,7 +56,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 <?php echo __('Name');?>:
             </td>
             <td>
-                <input data-translate-tag="<?php echo $dept ? $dept->getTranslationTag() : '';
+                <input data-translate-tag="<?php echo $dept ? $dept->getTranslateTag() : '';
                 ?>" type="text" size="30" name="name" value="<?php echo $info['name']; ?>">
                 &nbsp;<span class="error">*&nbsp;<?php echo $errors['name']; ?></span>
             </td>
@@ -250,30 +259,6 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 </span>
             </td>
         </tr>
-        <tr>
-            <th colspan="2">
-                <em><strong><?php echo __('Group Access'); ?></strong>:
-                <?php echo __('Check all groups allowed to access this department.'); ?>
-                <i class="help-tip icon-question-sign" href="#department_access"></i></em>
-            </th>
-        </tr>
-        <?php
-         $sql='SELECT group_id, group_name, count(staff.staff_id) as members '
-             .' FROM '.GROUP_TABLE.' grp '
-             .' LEFT JOIN '.STAFF_TABLE. ' staff USING(group_id) '
-             .' GROUP by grp.group_id '
-             .' ORDER BY group_name';
-         if(($res=db_query($sql)) && db_num_rows($res)){
-            while(list($id, $name, $members) = db_fetch_row($res)) {
-                if($members>0)
-                    $members=sprintf('<a href="staff.php?a=filter&gid=%d">%d</a>', $id, $members);
-
-                $ck=($info['groups'] && in_array($id,$info['groups']))?'checked="checked"':'';
-                echo sprintf('<tr><td colspan=2>&nbsp;&nbsp;<label><input type="checkbox" name="groups[]" value="%d" %s>&nbsp;%s</label> (%s)</td></tr>',
-                        $id, $ck, $name, $members);
-            }
-         }
-        ?>
         <tr>
             <th colspan="2">
                 <em><strong><?php echo __('Department Signature'); ?></strong>:
@@ -289,9 +274,92 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
         </tr>
     </tbody>
 </table>
+</div>
+<div id="access" class="tab_content" style="display:none">
+   <table class="form_table" width="940" border="0" cellspacing="0" cellpadding="2">
+    <thead>
+        <tr>
+            <th colspan=2>
+                <em><?php echo __('Primary department members have access to this department by default'); ?></em>
+            </th>
+        </tr>
+        <tr>
+            <th width="40%"><?php echo __('Group'); ?></th>
+            <th><?php echo __('Role'); ?></th>
+        </tr>
+    </thead>
+    <tbody>
+        <?php
+        $deptId = $dept ? $dept->getId() : 0;
+        $roles = Role::getRoles();
+        $groups = Group::objects()
+            ->annotate(array(
+                'isenabled'=>new SqlExpr(array(
+                        'flags__hasbit' => Group::FLAG_ENABLED))
+                ))
+            ->order_by('name');
+        foreach ($groups as $group) {
+            $DeptAccess = $group->getDepartmentsAccess();
+            ?>
+         <tr>
+            <td>
+             &nbsp;
+             <label>
+              <?php
+              $ck = ($info['groups'] && in_array($group->getId(), $info['groups'])) ? 'checked="checked"' : '';
+              echo sprintf('%s&nbsp;&nbsp;%s',
+                        sprintf('<input type="checkbox" class="grp-ckb"
+                            name="groups[]" value="%s" %s />',
+                            $group->getId(), $ck),
+                        Format::htmlchars($group->getName()));
+              ?>
+             </label>
+            </td>
+            <td>
+                <?php
+                $_name = 'group'.$group->getId().'_role_id';
+                ?>
+                <select name="<?php echo $_name; ?>">
+                    <option value="0">&mdash; <?php
+                        echo sprintf('%s (%s)',
+                                __('Group Default'),
+                                $group->getRole());
+                        ?>
+                        &mdash;</option>
+                    <?php
+                    foreach ($roles as $rid => $role) {
+                        $sel = '';
+                        if (isset($info[$_name]))
+                            $sel = ($info[$_name] == $rid) ? 'selected="selected"' : '';
+                        elseif ($deptId && isset($DeptAccess[$deptId]))
+                            $sel = ($DeptAccess[$deptId] == $rid) ?  'selected="selected"' : '';
+
+                        echo sprintf('<option value="%d" %s>%s</option>',
+                                $rid, $sel, $role);
+                    } ?>
+                </select>
+                <i class="help-tip icon-question-sign" href="#dept-role"></i>
+            </td>
+         </tr>
+         <?php
+        } ?>
+    </tbody>
+    <tfoot>
+     <tr>
+        <td colspan="2">
+            <?php echo __('Select');?>:&nbsp;
+            <a id="selectAll" href="#grp-ckb"><?php echo __('All');?></a>&nbsp;&nbsp;
+            <a id="selectNone" href="#grp-ckb"><?php echo __('None');?></a>&nbsp;&nbsp;
+            <a id="selectToggle" href="#grp-ckb"><?php echo __('Toggle');?></a>&nbsp;&nbsp;
+        </td>
+     </tr>
+    </tfoot>
+   </table>
+</div>
 <p style="text-align:center">
     <input type="submit" name="submit" value="<?php echo $submit_text; ?>">
     <input type="reset"  name="reset"  value="<?php echo __('Reset');?>">
-    <input type="button" name="cancel" value="<?php echo __('Cancel');?>" onclick='window.location.href="departments.php"'>
+    <input type="button" name="cancel" value="<?php echo __('Cancel');?>"
+        onclick='window.location.href="?"'>
 </p>
 </form>
diff --git a/include/staff/group.inc.php b/include/staff/group.inc.php
index 74cc64cb479f4e450df44b8c60ebf8e3645419ab..d471b791d8da636d5897153fd8e886bcf6332af4 100644
--- a/include/staff/group.inc.php
+++ b/include/staff/group.inc.php
@@ -1,50 +1,58 @@
 <?php
-if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
+
 $info=array();
-$qstr='';
-if($group && $_REQUEST['a']!='add'){
-    $title=__('Update Group');
-    $action='update';
-    $submit_text=__('Save Changes');
-    $info=$group->getInfo();
-    $info['id']=$group->getId();
-    $info['depts']=$group->getDepartments();
+if ($group) {
+    $title = __('Update Group');
+    $action = 'update';
+    $submit_text = __('Save Changes');
+    $info = $group->getInfo();
+    $info['id'] = $group->getId();
+    $info['depts'] = $group->getDepartments();
     $trans['name'] = $group->getTranslateTag('name');
-    $qstr.='&id='.$group->getId();
-}else {
-    $title=__('Add New Group');
-    $action='create';
-    $submit_text=__('Create Group');
-    $info['isactive']=isset($info['isactive'])?$info['isactive']:1;
-    $info['can_create_tickets']=isset($info['can_create_tickets'])?$info['can_create_tickets']:1;
-    $qstr.='&a='.$_REQUEST['a'];
+} else {
+    $title = __('Add New Group');
+    $action = 'add';
+    $submit_text = __('Create Group');
+    $info['isactive'] = isset($info['isactive']) ? $info['isactive'] : 1;
 }
-$info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
+
+$info = Format::htmlchars(($errors && $_POST) ? array_merge($info, $_POST) : $info);
+$roles = Role::getActiveRoles();
+
 ?>
-<form action="groups.php?<?php echo $qstr; ?>" method="post" id="save" name="group">
- <?php csrf_token(); ?>
- <input type="hidden" name="do" value="<?php echo $action; ?>">
- <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
- <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
- <h2><?php echo __('Group Access and Permissions');?></h2>
- <table class="form_table" width="940" border="0" cellspacing="0" cellpadding="2">
+<form action="" method="post" id="save">
+    <?php csrf_token(); ?>
+    <input type="hidden" name="do" value="<?php echo $action; ?>">
+    <input type="hidden" name="a" value="<?php echo Format::htmlchars($_REQUEST['a']); ?>">
+    <input type="hidden" name="id" value="<?php echo $info['id']; ?>">
+<h2> <?php echo $group ?: __('New Group'); ?></h2>
+<br>
+<ul class="tabs">
+    <li class="active"><a href="#group">
+        <i class="icon-file"></i> <?php echo __('Group'); ?></a></li>
+    <li><a href="#departments">
+        <i class="icon-lock"></i> <?php echo __('Departments Access'); ?></a></li>
+</ul>
+<div id="group" class="tab_content">
+    <table class="form_table" width="940" border="0" cellspacing="0" cellpadding="2">
     <thead>
         <tr>
             <th colspan="2">
                 <h4><?php echo $title; ?></h4>
-                <em><strong><?php echo __('Group Information');?></strong>: <?php echo __("Disabled group will limit agents' access. Admins are exempted.");?></em>
+                <em><?php echo __(
+                'Roles are used to define agents\' permissions'
+                ); ?>&nbsp;<i class="help-tip icon-question-sign"
+                href="#roles"></i></em>
             </th>
         </tr>
     </thead>
     <tbody>
         <tr>
-            <td width="180" class="required">
-                <?php echo __('Name');?>:
-            </td>
+            <td width="180" class="required"><?php echo __('Name'); ?>:</td>
             <td>
-                <input type="text" size="30" name="name" value="<?php echo $info['name']; ?>"
+                <input size="50" type="text" name="name" value="<?php echo $info['name']; ?>"
                 data-translate-tag="<?php echo $trans['name']; ?>"/>
-                &nbsp;<span class="error">*&nbsp;<?php echo $errors['name']; ?></span>
+                <span class="error">*&nbsp;<?php echo $errors['name']; ?></span>
             </td>
         </tr>
         <tr>
@@ -52,137 +60,121 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 <?php echo __('Status');?>:
             </td>
             <td>
-                <input type="radio" name="isactive" value="1" <?php echo $info['isactive']?'checked="checked"':''; ?>><strong><?php echo __('Active');?></strong>
+                <input type="radio" name="isactive" value="1" <?php
+                    echo $info['isactive'] ? 'checked="checked"' : ''; ?>><strong><?php echo __('Active');?></strong>
                 &nbsp;
-                <input type="radio" name="isactive" value="0" <?php echo !$info['isactive']?'checked="checked"':''; ?>><strong><?php echo __('Disabled');?></strong>
+                <input type="radio" name="isactive" value="0" <?php
+                    echo !$info['isactive'] ? 'checked="checked"' : ''; ?>><strong><?php echo __('Disabled');?></strong>
                 &nbsp;<span class="error">*&nbsp;<?php echo $errors['status']; ?></span>
                 <i class="help-tip icon-question-sign" href="#status"></i>
             </td>
         </tr>
         <tr>
-            <th colspan="2">
-                <em><strong><?php echo __('Group Permissions');?></strong>: <?php echo __('Applies to all group members');?>&nbsp;</em>
-            </th>
-        </tr>
-        <tr><td><?php echo __('Can <b>Create</b> Tickets');?></td>
-            <td>
-                <input type="radio" name="can_create_tickets"  value="1"   <?php echo $info['can_create_tickets']?'checked="checked"':''; ?> /><?php echo __('Yes');?>
-                &nbsp;&nbsp;
-                <input type="radio" name="can_create_tickets"  value="0"   <?php echo !$info['can_create_tickets']?'checked="checked"':''; ?> /><?php echo __('No');?>
-                &nbsp;&nbsp;<i><?php echo __('Ability to open tickets on behalf of users.');?></i>
-            </td>
-        </tr>
-        <tr><td><?php echo __('Can <b>Edit</b> Tickets</td>');?>
-            <td>
-                <input type="radio" name="can_edit_tickets"  value="1"   <?php echo $info['can_edit_tickets']?'checked="checked"':''; ?> /><?php echo __('Yes');?>
-                &nbsp;&nbsp;
-                <input type="radio" name="can_edit_tickets"  value="0"   <?php echo !$info['can_edit_tickets']?'checked="checked"':''; ?> /><?php echo __('No');?>
-                &nbsp;&nbsp;<i><?php echo __('Ability to edit tickets.');?></i>
-            </td>
-        </tr>
-        <tr><td><?php echo __('Can <b>Post Reply</b>');?></td>
-            <td>
-                <input type="radio" name="can_post_ticket_reply"  value="1"   <?php echo $info['can_post_ticket_reply']?'checked="checked"':''; ?> /><?php echo __('Yes');?>
-                &nbsp;&nbsp;
-                <input type="radio" name="can_post_ticket_reply"  value="0"   <?php echo !$info['can_post_ticket_reply']?'checked="checked"':''; ?> /><?php echo __('No');?>
-                &nbsp;&nbsp;<i><?php echo __('Ability to post a ticket reply.');?></i>
-            </td>
-        </tr>
-        <tr><td><?php echo __('Can <b>Close</b> Tickets');?></td>
-            <td>
-                <input type="radio" name="can_close_tickets"  value="1" <?php echo $info['can_close_tickets']?'checked="checked"':''; ?> /><?php echo __('Yes');?>
-                &nbsp;&nbsp;
-                <input type="radio" name="can_close_tickets"  value="0" <?php echo !$info['can_close_tickets']?'checked="checked"':''; ?> /><?php echo __('No');?>
-                &nbsp;&nbsp;<i><?php echo __('Ability to close tickets.  Agents can still post a response.');?></i>
-            </td>
-        </tr>
-        <tr><td><?php echo __('Can <b>Assign</b> Tickets');?></td>
-            <td>
-                <input type="radio" name="can_assign_tickets"  value="1" <?php echo $info['can_assign_tickets']?'checked="checked"':''; ?> /><?php echo __('Yes');?>
-                &nbsp;&nbsp;
-                <input type="radio" name="can_assign_tickets"  value="0" <?php echo !$info['can_assign_tickets']?'checked="checked"':''; ?> /><?php echo __('No');?>
-                &nbsp;&nbsp;<i><?php echo __('Ability to assign tickets to agents.');?></i>
-            </td>
-        </tr>
-        <tr><td><?php echo __('Can <b>Transfer</b> Tickets');?></td>
-            <td>
-                <input type="radio" name="can_transfer_tickets"  value="1" <?php echo $info['can_transfer_tickets']?'checked="checked"':''; ?> /><?php echo __('Yes');?>
-                &nbsp;&nbsp;
-                <input type="radio" name="can_transfer_tickets"  value="0" <?php echo !$info['can_transfer_tickets']?'checked="checked"':''; ?> /><?php echo __('No');?>
-                &nbsp;&nbsp;<i><?php echo __('Ability to transfer tickets between departments.');?></i>
-            </td>
-        </tr>
-        <tr><td><?php echo __('Can <b>Delete</b> Tickets');?></td>
-            <td>
-                <input type="radio" name="can_delete_tickets"  value="1"   <?php echo $info['can_delete_tickets']?'checked="checked"':''; ?> /><?php echo __('Yes');?>
-                &nbsp;&nbsp;
-                <input type="radio" name="can_delete_tickets"  value="0"   <?php echo !$info['can_delete_tickets']?'checked="checked"':''; ?> /><?php echo __('No');?>
-                &nbsp;&nbsp;<i><?php echo __("Ability to delete tickets (Deleted tickets can't be recovered!)");?></i>
-            </td>
-        </tr>
-        <tr><td><?php echo __('Can Ban Emails');?></td>
-            <td>
-                <input type="radio" name="can_ban_emails"  value="1" <?php echo $info['can_ban_emails']?'checked="checked"':''; ?> /><?php echo __('Yes');?>
-                &nbsp;&nbsp;
-                <input type="radio" name="can_ban_emails"  value="0" <?php echo !$info['can_ban_emails']?'checked="checked"':''; ?> /><?php echo __('No');?>
-                &nbsp;&nbsp;<i><?php echo __('Ability to add/remove emails from banlist via ticket interface.');?></i>
+            <td width="180" class="required">
+                <?php echo __('Default Role');?>:
             </td>
-        </tr>
-        <tr><td><?php echo __('Can Manage Premade');?></td>
             <td>
-                <input type="radio" name="can_manage_premade"  value="1" <?php echo $info['can_manage_premade']?'checked="checked"':''; ?> /><?php echo __('Yes');?>
-                &nbsp;&nbsp;
-                <input type="radio" name="can_manage_premade"  value="0" <?php echo !$info['can_manage_premade']?'checked="checked"':''; ?> /><?php echo __('No');?>
-                &nbsp;&nbsp;<i><?php echo __('Ability to add/update/disable/delete canned responses and attachments.');?></i>
+                <select name="role_id">
+                    <option value="0">Select One</option>
+                    <?php
+                    foreach ($roles as $id => $role) {
+                        $sel = ($info['role_id'] == $id) ? 'selected="selected"' : '';
+                        echo sprintf('<option value="%d" %s>%s</option>',
+                                $id, $sel, $role);
+                    } ?>
+                </select>
+                &nbsp;<span class="error">*&nbsp;<?php echo $errors['role_id']; ?></span>
+                <i class="help-tip icon-question-sign" href="#role"></i>
             </td>
         </tr>
-        <tr><td><?php echo __('Can Manage FAQ');?></td>
-            <td>
-                <input type="radio" name="can_manage_faq"  value="1" <?php echo $info['can_manage_faq']?'checked="checked"':''; ?> /><?php echo __('Yes');?>
-                &nbsp;&nbsp;
-                <input type="radio" name="can_manage_faq"  value="0" <?php echo !$info['can_manage_faq']?'checked="checked"':''; ?> /><?php echo __('No');?>
-                &nbsp;&nbsp;<i><?php echo __('Ability to add/update/disable/delete knowledgebase categories and FAQs.');?></i>
-            </td>
+    </tbody>
+    <tbody>
+        <tr>
+            <th colspan="7">
+                <em><strong><?php echo __('Internal Notes'); ?></strong> </em>
+            </th>
         </tr>
-        <tr><td><?php echo __('Can View Agent Stats');?></td>
-            <td>
-                <input type="radio" name="can_view_staff_stats"  value="1" <?php echo $info['can_view_staff_stats']?'checked="checked"':''; ?> /><?php echo __('Yes');?>
-                &nbsp;&nbsp;
-                <input type="radio" name="can_view_staff_stats"  value="0" <?php echo !$info['can_view_staff_stats']?'checked="checked"':''; ?> /><?php echo __('No');?>
-                &nbsp;&nbsp;<i><?php echo __('Ability to view stats of other agents in allowed departments.');?></i>
+        <tr>
+            <td colspan="7"><textarea name="notes" class="richtext no-bar"
+                rows="6" cols="80"><?php
+                echo $info['notes']; ?></textarea>
             </td>
         </tr>
+    </tbody>
+    </table>
+</div>
+<div id="departments" class="tab_content" style="display:none">
+   <table class="form_table" width="940" border="0" cellspacing="0" cellpadding="2">
+    <thead>
         <tr>
-            <th colspan="2">
-                <em><strong><?php echo __('Department Access');?></strong>:
-                <i class="help-tip icon-question-sign" href="#department_access"></i>
-                &nbsp;<a id="selectAll" href="#deptckb"><?php echo __('Select All');?></a>
-                &nbsp;&nbsp;
-                <a id="selectNone" href="#deptckb"><?php echo __('Select None');?></a></em>
+            <th colspan=2>
+                <em><?php echo __('Check departments the group is allowed to access and optionally select an effective role.') ?></em>
             </th>
         </tr>
-        <?php
-        foreach (Dept::getDepartments() as $id=>$name) {
-            $ck=($info['depts'] && in_array($id,$info['depts']))?'checked="checked"':'';
-            echo sprintf('<tr><td colspan=2>&nbsp;&nbsp;<input type="checkbox" class="deptckb" name="depts[]" value="%d" %s> %s</td></tr>',$id,$ck,$name);
-        }
-        ?>
         <tr>
-            <th colspan="2">
-                <em><strong><?php echo __('Admin Notes');?></strong>: <?php echo __('Internal notes viewable by all admins.');?>&nbsp;</em>
-            </th>
+            <th width="40%"><?php echo __('Department'); ?></th>
+            <th><?php echo __('Group Role'); ?></th>
         </tr>
-        <tr>
-            <td colspan=2>
-                <textarea class="richtext no-bar" name="notes" cols="21"
-                    rows="8" style="width: 80%;"><?php echo $info['notes']; ?></textarea>
+    </thead>
+    <tbody>
+        <?php
+        foreach (Dept::getDepartments() as $deptId => $name) { ?>
+         <tr>
+            <td>
+             &nbsp;
+             <label>
+              <?php
+              $ck = ($info['depts'] && in_array($deptId, $info['depts'])) ? 'checked="checked"' : '';
+              echo sprintf('%s&nbsp;&nbsp;%s',
+                        sprintf('<input type="checkbox" class="dept-ckb"
+                            name="depts[]" value="%s" %s />',
+                            $deptId, $ck),
+                        Format::htmlchars($name));
+              ?>
+             </label>
             </td>
-        </tr>
+            <td>
+                <?php
+                $DeptAccess = $group ? $group->getDepartmentsAccess() : array();
+                $_name = 'dept'.$deptId.'_role_id';
+                ?>
+                <select name="<?php echo $_name; ?>">
+                    <option value="0">&mdash; <?php
+                        echo __('Group Default'); ?> &mdash;</option>
+                    <?php
+                    foreach ($roles as $rid => $role) {
+                        $sel = '';
+                        if (isset($info[$_name]))
+                            $sel = ($info[$_name] == $rid) ? 'selected="selected"' : '';
+                        elseif ($DeptAccess && isset($DeptAccess[$deptId]))
+                            $sel = ($DeptAccess[$deptId] == $rid) ?  'selected="selected"' : '';
+
+                        echo sprintf('<option value="%d" %s>%s</option>',
+                                $rid, $sel, $role);
+                    } ?>
+                </select>
+                <i class="help-tip icon-question-sign" href="#dept-role"></i>
+            </td>
+         </tr>
+         <?php
+        } ?>
     </tbody>
-</table>
-<p style="text-align:center">
+    <tfoot>
+     <tr>
+        <td colspan="2">
+            <?php echo __('Select');?>:&nbsp;
+            <a id="selectAll" href="#dept-ckb"><?php echo __('All');?></a>&nbsp;&nbsp;
+            <a id="selectNone" href="#dept-ckb"><?php echo __('None');?></a>&nbsp;&nbsp;
+            <a id="selectToggle" href="#dept-ckb"><?php echo __('Toggle');?></a>&nbsp;&nbsp;
+        </td>
+     </tr>
+    </tfoot>
+   </table>
+</div>
+<p class="centered">
     <input type="submit" name="submit" value="<?php echo $submit_text; ?>">
-    <input type="reset"  name="reset"  value="<?php echo __('Reset');?>">
-    <input type="button" name="cancel" value="<?php echo __('Cancel');?>" onclick='window.location.href="groups.php"'>
+    <input type="reset"  name="reset"  value="<?php echo __('Reset'); ?>">
+    <input type="button" name="cancel" value="<?php echo __('Cancel'); ?>"
+        onclick='window.location.href="?"'>
 </p>
 </form>
diff --git a/include/staff/groups.inc.php b/include/staff/groups.inc.php
index 326400daa0ba12932943c96934a7783ffb13af92..ac3f438956466eaa2ba695303e8ddae8152ac076 100644
--- a/include/staff/groups.inc.php
+++ b/include/staff/groups.inc.php
@@ -1,43 +1,44 @@
 <?php
-if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied');
+if (!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin())
+    die('Access Denied');
 
-$qstr='';
+$qstr = '';
+$sortOptions = array(
+        'name'   => 'name',
+        'users'  => 'members_count',
+        'depts'  => 'depts_count',
+        'status' => 'isenabled',
+        'created'=> 'created',
+        'updated'=> 'updated');
+
+$orderWays = array('DESC'=>'DESC', 'ASC'=>'ASC');
+$sort = ($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])]) ? strtolower($_REQUEST['sort']) : 'name';
 
-$sql='SELECT grp.*,count(DISTINCT staff.staff_id) as users, count(DISTINCT dept.dept_id) as depts '
-     .' FROM '.GROUP_TABLE.' grp '
-     .' LEFT JOIN '.STAFF_TABLE.' staff ON(staff.group_id=grp.group_id) '
-     .' LEFT JOIN '.GROUP_DEPT_TABLE.' dept ON(dept.group_id=grp.group_id) '
-     .' WHERE 1';
-$sortOptions=array('name'=>'grp.group_name','status'=>'grp.group_enabled',
-                   'users'=>'users', 'depts'=>'depts', 'created'=>'grp.created','updated'=>'grp.updated');
-$orderWays=array('DESC'=>'DESC','ASC'=>'ASC');
-$sort=($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])])?strtolower($_REQUEST['sort']):'name';
 //Sorting options...
-if($sort && $sortOptions[$sort]) {
-    $order_column =$sortOptions[$sort];
+if ($sort && $sortOptions[$sort]) {
+    $order_column = $sortOptions[$sort];
 }
-$order_column=$order_column?$order_column:'grp.group_name';
 
-if($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])]) {
-    $order=$orderWays[strtoupper($_REQUEST['order'])];
+$order_column = $order_column ? $order_column : 'name';
+
+if ($_REQUEST['order'] && isset($orderWays[strtoupper($_REQUEST['order'])])) {
+    $order = $orderWays[strtoupper($_REQUEST['order'])];
+} else {
+    $order = 'ASC';
 }
-$order=$order?$order:'ASC';
 
-if($order_column && strpos($order_column,',')){
+if ($order_column && strpos($order_column,',')) {
     $order_column=str_replace(','," $order,",$order_column);
 }
 $x=$sort.'_sort';
 $$x=' class="'.strtolower($order).'" ';
-$order_by="$order_column $order ";
-
+$page = ($_GET['p'] && is_numeric($_GET['p'])) ? $_GET['p'] : 1;
+$count = Group::objects()->count();
+$pageNav = new Pagenate($count, $page, PAGE_LIMIT);
+$_qstr = $qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order']);
+$pageNav->setURL('groups.php', $_qstr);
+$showing = $pageNav->showing().' '._N('group', 'groups', $count);
 $qstr.='&order='.($order=='DESC'?'ASC':'DESC');
-$query="$sql GROUP BY grp.group_id ORDER BY $order_by";
-$res=db_query($query);
-if($res && ($num=db_num_rows($res)))
-    $showing=sprintf(__('Showing 1-%1$d of %2$d groups'), $num, $num);
-else
-    $showing=__('No groups found!');
-
 ?>
 <div class="pull-left" style="width:700px;padding-top:5px;">
  <h2><?php echo __('Agent Groups');?>
@@ -67,31 +68,47 @@ else
     <tbody>
     <?php
         $total=0;
-        $ids=($errors && is_array($_POST['ids']))?$_POST['ids']:null;
-        if($res && db_num_rows($res)) {
-            while ($row = db_fetch_array($res)) {
+        $ids = ($errors && is_array($_POST['ids'])) ? $_POST['ids'] : null;
+        if ($count) {
+            $groups= Group::objects()
+                ->annotate(array(
+                        'members_count'=>SqlAggregate::COUNT('members', true),
+                        'depts_count'=>SqlAggregate::COUNT('depts', true),
+                        'isenabled'=>new SqlExpr(array(
+                                'flags__hasbit' => Group::FLAG_ENABLED))
+                ))
+                ->order_by(sprintf('%s%s',
+                            strcasecmp($order, 'DESC') ? '' : '-',
+                            $order_column))
+                ->limit($pageNav->getLimit())
+                ->offset($pageNav->getStart());
+
+            foreach ($groups as $group) {
                 $sel=false;
-                if($ids && in_array($row['group_id'],$ids))
+                $id = $group->getId();
+                if($ids && in_array($id, $ids))
                     $sel=true;
                 ?>
-            <tr id="<?php echo $row['group_id']; ?>">
+            <tr id="<?php echo $id; ?>">
                 <td width=7px>
-                  <input type="checkbox" class="ckb" name="ids[]" value="<?php echo $row['group_id']; ?>"
-                            <?php echo $sel?'checked="checked"':''; ?>> </td>
-                <td><a href="groups.php?id=<?php echo $row['group_id']; ?>"><?php echo $row['group_name']; ?></a> &nbsp;</td>
-                <td>&nbsp;<?php echo $row['group_enabled']?__('Active'):'<b>'.__('Disabled').'</b>'; ?></td>
+                  <input type="checkbox" class="ckb" name="ids[]"
+                    value="<?php echo $id; ?>"
+                    <?php echo $sel?'checked="checked"':''; ?>> </td>
+                <td><a href="groups.php?id=<?php echo $id; ?>"><?php echo
+                $group->getName(); ?></a> &nbsp;</td>
+                <td>&nbsp;<?php echo $group->isenabled ? __('Active') : '<b>'.__('Disabled').'</b>'; ?></td>
                 <td style="text-align:right;padding-right:30px">&nbsp;&nbsp;
-                    <?php if($row['users']>0) { ?>
-                        <a href="staff.php?gid=<?php echo $row['group_id']; ?>"><?php echo $row['users']; ?></a>
-                    <?php }else{ ?> 0
+                    <?php if ($num=$group->members_count) { ?>
+                        <a href="staff.php?gid=<?php echo $id; ?>"><?php echo $num; ?></a>
+                    <?php } else { ?> 0
                     <?php } ?>
                     &nbsp;
                 </td>
                 <td style="text-align:right;padding-right:30px">&nbsp;&nbsp;
-                    <?php echo $row['depts']; ?>
+                    <?php echo $group->depts_count; ?>
                 </td>
-                <td><?php echo Format::date($row['created']); ?>&nbsp;</td>
-                <td><?php echo Format::datetime($row['updated']); ?>&nbsp;</td>
+                <td><?php echo Format::date($group->getCreateDate()); ?>&nbsp;</td>
+                <td><?php echo Format::datetime($group->getUpdateDate()); ?>&nbsp;</td>
             </tr>
             <?php
             } //end of while.
@@ -99,7 +116,7 @@ else
     <tfoot>
      <tr>
         <td colspan="7">
-            <?php if($res && $num){ ?>
+            <?php if ($count) { ?>
             <?php echo __('Select');?>:&nbsp;
             <a id="selectAll" href="#ckb"><?php echo __('All');?></a>&nbsp;&nbsp;
             <a id="selectNone" href="#ckb"><?php echo __('None');?></a>&nbsp;&nbsp;
@@ -112,7 +129,8 @@ else
     </tfoot>
 </table>
 <?php
-if($res && $num): //Show options..
+if ($count):
+    echo '<div>&nbsp;'.__('Page').':'.$pageNav->getPageLinks().'&nbsp;</div>';
 ?>
 <p class="centered" id="actions">
     <input class="button" type="submit" name="enable" value="<?php echo __('Enable');?>" >
diff --git a/include/staff/staff.inc.php b/include/staff/staff.inc.php
index 665797a0cc6e8343cfb6949853dae92c68b19c89..1bc7ca1d675f14a7be2c5346d14f173c9a1e3949 100644
--- a/include/staff/staff.inc.php
+++ b/include/staff/staff.inc.php
@@ -234,7 +234,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 <select name="group_id" id="group_id">
                     <option value="0">&mdash; <?php echo __('Select Group');?> &mdash;</option>
                     <?php
-                    foreach (Group::getGroupNames() as $id=>$name) {
+                    foreach (Group::getGroups() as $id=>$name) {
                         $sel=($info['group_id']==$id)?'selected="selected"':'';
                         echo sprintf('<option value="%d" %s>%s</option>',
                             $id, $sel, $name);
diff --git a/scp/css/scp.css b/scp/css/scp.css
index b97e1cc2bcfdc37b4a840095165b790d043311dc..add15fde893acb7e58be9e9a6f639e2492f61424 100644
--- a/scp/css/scp.css
+++ b/scp/css/scp.css
@@ -489,8 +489,12 @@ table.list tbody tr:hover td, table.list tbody tr.highlight td {  background: #F
 table.list tbody tr:hover td.nohover, table.list tbody tr.highlight td.nohover {}
 
 
-table.list tfoot td {
+table tfoot td {
     background:#eee;
+    padding: 1px;
+}
+
+table.list tfoot td {
     padding: 2px;
 }
 
@@ -1952,7 +1956,7 @@ tr.disabled th {
 
 .tab_content {
     position: relative;
-    padding: 10px;
+    padding: 5px 0;
 }
 .left-tabs {
     margin-left: 48px;
diff --git a/scp/groups.php b/scp/groups.php
index 8f273e1b11db8bf69320f2f94f4d209f0f9d5af0..494824bb108c2c83b5477ab56ed95d073f772361 100644
--- a/scp/groups.php
+++ b/scp/groups.php
@@ -22,39 +22,52 @@ if($_REQUEST['id'] && !($group=Group::lookup($_REQUEST['id'])))
 if($_POST){
     switch(strtolower($_POST['do'])){
         case 'update':
-            if(!$group){
+            if (!$group) {
                 $errors['err']=sprintf(__('%s: Unknown or invalid'), __('group'));
-            }elseif($group->update($_POST,$errors)){
+            } elseif (!$_POST['isactive']
+                    && ($thisstaff->getGroupId() == $group->getId())) {
+                $errors['err'] = sprintf(
+                        __("As an admin, you cannot %s a group you belong to - you might lockout all admins!"),
+                        __('disable'));
+            } elseif ($group->update($_POST, $errors)) {
                 $msg=sprintf(__('Successfully updated %s'),
                     __('this group'));
-            }elseif(!$errors['err']){
+            } elseif (!$errors['err']) {
                 $errors['err']=sprintf(__('Unable to update %s. Correct error(s) below and try again!'),
                     __('this group'));
             }
             break;
-        case 'create':
-            $group = Group::create();
-            if(($group->update($_POST,$errors))){
+        case 'add':
+            $_group = Group::create();
+            if (($_group->update($_POST,$errors))) {
                 $msg=sprintf(__('Successfully added %s'),Format::htmlchars($_POST['name']));
                 $_REQUEST['a']=null;
-            }elseif(!$errors['err']){
+            } elseif(!$errors['err']) {
                 $errors['err']=sprintf(__('Unable to add %s. Correct error(s) below and try again.'),
                     __('this group'));
             }
             break;
         case 'mass_process':
-            if(!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) {
+            $action = strtolower($_POST['a']);
+            if (!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) {
                 $errors['err'] = sprintf(__('You must select at least %s.'), __('one group'));
-            } elseif(in_array($thisstaff->getGroupId(), $_POST['ids'])) {
-                $errors['err'] = __("As an admin, you cannot disable/delete a group you belong to - you might lockout all admins!");
+            } elseif(in_array($thisstaff->getGroupId(), $_POST['ids'])
+                    && in_array($action, array('disable', 'delete'))) {
+                $errors['err'] = sprintf(
+                        __("As an admin, you cannot %s a group you belong to - you might lockout all admins!"),
+                        __('disable or delete'));
             } else {
-                $count=count($_POST['ids']);
-                switch(strtolower($_POST['a'])) {
+                $count = count($_POST['ids']);
+                switch($action) {
                     case 'enable':
-                        $sql='UPDATE '.GROUP_TABLE.' SET group_enabled=1, updated=NOW() '
-                            .' WHERE group_id IN ('.implode(',', db_input($_POST['ids'])).')';
-
-                        if(db_query($sql) && ($num=db_affected_rows())){
+                        $num = Group::objects()->filter(array(
+                            'id__in' => $_POST['ids']
+                        ))->update(array(
+                            'flags'=> SqlExpression::bitor(
+                                new SqlField('flags'),
+                                Group::FLAG_ENABLED)
+                        ));
+                        if ($num) {
                             if($num==$count)
                                 $msg = sprintf(__('Successfully activated %s'),
                                     _N('selected group', 'selected groups', $count));
@@ -67,9 +80,15 @@ if($_POST){
                         }
                         break;
                     case 'disable':
-                        $sql='UPDATE '.GROUP_TABLE.' SET group_enabled=0, updated=NOW() '
-                            .' WHERE group_id IN ('.implode(',', db_input($_POST['ids'])).')';
-                        if(db_query($sql) && ($num=db_affected_rows())) {
+                        $num = Group::objects()->filter(array(
+                            'id__in' => $_POST['ids']
+                        ))->update(array(
+                            'flags'=> SqlExpression::bitand(
+                                new SqlField('flags'),
+                                (~Group::FLAG_ENABLED))
+                        ));
+
+                        if ($num) {
                             if($num==$count)
                                 $msg = sprintf(__('Successfully disabled %s'),
                                     _N('selected group', 'selected groups', $count));
diff --git a/setup/inc/streams/core/install-mysql.sql b/setup/inc/streams/core/install-mysql.sql
index 900a1f47f9c399f633ca18e4ef24b68c74130aa2..e35b6a364b6e6de4ee4af0ff4ed01eda630f50ee 100644
--- a/setup/inc/streams/core/install-mysql.sql
+++ b/setup/inc/streams/core/install-mysql.sql
@@ -388,27 +388,17 @@ CREATE TABLE `%TABLE_PREFIX%file_chunk` (
   PRIMARY KEY (`file_id`, `chunk_id`)
 ) DEFAULT CHARSET=utf8;
 
-DROP TABLE IF EXISTS `%TABLE_PREFIX%groups`;
-CREATE TABLE `%TABLE_PREFIX%groups` (
-  `group_id` int(10) unsigned NOT NULL auto_increment,
-  `group_enabled` tinyint(1) unsigned NOT NULL default '1',
-  `group_name` varchar(50) NOT NULL default '',
-  `can_create_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `can_edit_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `can_post_ticket_reply` tinyint( 1 ) unsigned NOT NULL DEFAULT  '1',
-  `can_delete_tickets` tinyint(1) unsigned NOT NULL default '0',
-  `can_close_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `can_assign_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `can_transfer_tickets` tinyint(1) unsigned NOT NULL default '1',
-  `can_ban_emails` tinyint(1) unsigned NOT NULL default '0',
-  `can_manage_premade` tinyint(1) unsigned NOT NULL default '0',
-  `can_manage_faq` tinyint(1) unsigned NOT NULL default '0',
-  `can_view_staff_stats` tinyint( 1 ) unsigned NOT NULL DEFAULT  '0',
+DROP TABLE IF EXISTS `%TABLE_PREFIX%group`;
+CREATE TABLE `%TABLE_PREFIX%group` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `role_id` int(11) unsigned NOT NULL,
+  `flags` int(11) unsigned NOT NULL default '1',
+  `name` varchar(120) NOT NULL default '',
   `notes` text,
   `created` datetime NOT NULL,
   `updated` datetime NOT NULL,
-  PRIMARY KEY  (`group_id`),
-  KEY `group_active` (`group_enabled`)
+  PRIMARY KEY  (`id`),
+  KEY `role_id` (`role_id`)
 ) DEFAULT CHARSET=utf8;
 
 DROP TABLE IF EXISTS `%TABLE_PREFIX%role`;
@@ -427,8 +417,10 @@ DROP TABLE IF EXISTS `%TABLE_PREFIX%group_dept_access`;
 CREATE TABLE `%TABLE_PREFIX%group_dept_access` (
   `group_id` int(10) unsigned NOT NULL default '0',
   `dept_id` int(10) unsigned NOT NULL default '0',
+  `role_id` int(10) unsigned NOT NULL default '0',
   UNIQUE KEY `group_dept` (`group_id`,`dept_id`),
-  KEY `dept_id`  (`dept_id`)
+  KEY `dept_id`  (`dept_id`),
+  KEY `role_id`  (`role_id`)
 ) DEFAULT CHARSET=utf8;
 
 DROP TABLE IF EXISTS `%TABLE_PREFIX%help_topic`;