Index: /extensions/UserStat/admin/plugin_admin.php
===================================================================
--- /extensions/UserStat/admin/plugin_admin.php	(revision 4270)
+++ /extensions/UserStat/admin/plugin_admin.php	(revision 4270)
@@ -0,0 +1,27 @@
+<?php
+/* -----------------------------------------------------------------------------
+  Plugin     : UserStat
+  Author     : Grum
+    email    : grum@piwigo.org
+    website  : http://photos.grum.fr
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+  See main.inc.php for release information
+
+  --------------------------------------------------------------------------- */
+
+if (!defined('PHPWG_ROOT_PATH')) { die('Hacking attempt!'); }
+
+include(USERSTAT_PATH."userstat_aip.class.inc.php");
+
+global $prefixeTable;
+
+load_language('plugin.lang', USERSTAT_PATH);
+
+$main_plugin_object = get_plugin_data($plugin_id);
+
+$plugin_ai = new UserStat_AIP($prefixeTable, $main_plugin_object->get_filelocation());
+$plugin_ai->manage();
+
+?>
Index: /extensions/UserStat/admin/userstat_admin.tpl
===================================================================
--- /extensions/UserStat/admin/userstat_admin.tpl	(revision 4270)
+++ /extensions/UserStat/admin/userstat_admin.tpl	(revision 4270)
@@ -0,0 +1,15 @@
+<div class="titrePage">
+  <h2 style="position:absolute;right:0px;top:32px;height:auto;font-size:12px;font-weight:normal;">:: {$plugin.USERSTAT_VERSION} ::</h2>
+  <h2>{'us_titlePage'|@translate} <span style="font-size:-1;font-weight:normal;">{$TABSHEET_TITLE}</span></h2>
+
+  {$tabsheet}
+</div>
+
+{if isset($datas)}
+  {$datas.USERSTAT_NFO_STAT}
+  <h3>{$datas.L_STAT_TITLE}</h3>
+
+{/if}
+
+{$USERSTAT_BODY_PAGE}
+
Index: /extensions/UserStat/admin/userstat_global.tpl
===================================================================
--- /extensions/UserStat/admin/userstat_global.tpl	(revision 4270)
+++ /extensions/UserStat/admin/userstat_global.tpl	(revision 4270)
@@ -0,0 +1,62 @@
+
+
+<div class="table">
+
+{if isset($datas.propertiesUsers) and count($datas.propertiesUsers)}
+
+<table class="table2 littlefont" >
+  <tr class="throw">
+    <td>{'us_property'|@translate}</td>
+    <td>{'us_numberOfUsers'|@translate}</td>
+  </tr>
+  {foreach from=$datas.propertiesUsers key=name item=data}
+    {if $data.property == "total" || $data.property == "withMail" || $data.property == "withHD" }
+      <tr class="StatTableRow">
+        <td>{$data.label}</td>
+        <td>{$data.value}</td>
+      </tr>
+    {/if}
+  {/foreach}
+</table>
+{/if}
+
+</div>
+
+
+<div class="table">
+
+{if isset($datas.languagesUsers) and count($datas.languagesUsers)}
+<table class="table2 littlefont" >
+  <tr class="throw">
+    <td>{'us_lang'|@translate}</td>
+    <td>{'us_numberOfUsers'|@translate}</td>
+  </tr>
+  {foreach from=$datas.languagesUsers key=name item=data}
+    <tr class="StatTableRow">
+      <td>{$data.humanReadable}</td>
+      <td>{$data.nbUsers}</td>
+    </tr>
+  {/foreach}
+</table>
+{/if}
+
+</div>
+
+<div class="table">
+
+{if isset($datas.templatesUsers) and count($datas.templatesUsers)}
+<table class="table2 littlefont" >
+  <tr class="throw">
+    <td>{'us_template'|@translate}</td>
+    <td>{'us_numberOfUsers'|@translate}</td>
+  </tr>
+  {foreach from=$datas.templatesUsers key=name item=data}
+    <tr class="StatTableRow">
+      <td>{$data.template}</td>
+      <td>{$data.nbUsers}</td>
+    </tr>
+  {/foreach}
+</table>
+{/if}
+
+</div>
Index: /extensions/UserStat/admin/userstat_users.tpl
===================================================================
--- /extensions/UserStat/admin/userstat_users.tpl	(revision 4270)
+++ /extensions/UserStat/admin/userstat_users.tpl	(revision 4270)
@@ -0,0 +1,62 @@
+
+{literal}
+<script type="text/javascript">
+
+  function loadUser(userId)
+  {
+    $.get("{/literal}{$datas.ajaxUrl}{literal}",
+      { ajaxfct: "userStat", userId: userId },
+      function (data)
+      {
+        $("#userDetail").html(data);
+      }
+    );
+  }
+
+</script>
+
+{/literal}
+
+
+<div id="userList" style="margin-bottom:20px;">
+{if isset($datas.users) and count($datas.users)}
+<table class="table2 littlefont" >
+  <tr class="throw">
+    <td rowspan="2">{'us_userName'|@translate}</td>
+    <td colspan="7">{'us_userRating'|@translate}</td>
+    <td colspan="3">{'us_userComments'|@translate}</td>
+  </tr>
+  <tr class="throw">
+    <td>{'us_userNbRates'|@translate}</td>
+    <td>{'us_userMaxRate'|@translate}</td>
+    <td>{'us_userMinRate'|@translate}</td>
+    <td>{'us_userAvgRate'|@translate}</td>
+    <td>{'us_userDevRate'|@translate}</td>
+    <td>{'us_userLastDayR'|@translate}</td>
+    <td>{'us_userDelayR'|@translate}</td>
+    <td>{'us_userNbComments'|@translate}</td>
+    <td>{'us_userLastDayC'|@translate}</td>
+    <td>{'us_userDelayC'|@translate}</td>
+  </tr>
+  {foreach from=$datas.users key=name item=data}
+      <tr class="StatTableRow" style="cursor:pointer;" onclick="loadUser({$data.id})">
+        <td class="toLeft">{$data.name}</td>
+        <td>{$data.nbRates}</td>
+        <td>{$data.maxRate}</td>
+        <td>{$data.minRate}</td>
+        <td>{$data.avgRate}</td>
+        <td>{$data.devRate}</td>
+        <td>{$data.lastDayR}</td>
+        <td>{$data.delayR}</td>
+        <td>{$data.nbComments}</td>
+        <td>{$data.lastDayC}</td>
+        <td>{$data.delayC}</td>
+      </tr>
+  {/foreach}
+</table>
+{/if}
+</div>
+
+<div id="userDetail">
+</div>
+
Index: /extensions/UserStat/admin/userstat_userstat.tpl
===================================================================
--- /extensions/UserStat/admin/userstat_userstat.tpl	(revision 4270)
+++ /extensions/UserStat/admin/userstat_userstat.tpl	(revision 4270)
@@ -0,0 +1,40 @@
+{'us_detailledStatisticsForUser'|@translate}&nbsp;{$datas.userName}
+<table class="table2 littlefont" >
+  <tr class="throw">
+    <td rowspan="2">{'us_categoryName'|@translate}</td>
+    <td colspan="7">{'us_userRating'|@translate}</td>
+    <td colspan="3">{'us_userComments'|@translate}</td>
+  </tr>
+  <tr class="throw">
+    <td>{'us_userNbRates'|@translate}</td>
+    <td>{'us_userMaxRate'|@translate}</td>
+    <td>{'us_userMinRate'|@translate}</td>
+    <td>{'us_userAvgRate'|@translate}</td>
+    <td>{'us_userDevRate'|@translate}</td>
+    <td>{'us_userLastDayR'|@translate}</td>
+    <td>{'us_userDelayR'|@translate}</td>
+    <td>{'us_userNbComments'|@translate}</td>
+    <td>{'us_userLastDayC'|@translate}</td>
+    <td>{'us_userDelayC'|@translate}</td>
+  </tr>
+  {foreach from=$datas.list key=name item=data}
+      <tr class="StatTableRow">
+        <td class="toLeft">
+          {$data.categoryName}
+          {if $data.physical == "N"}
+          ({'us_virtual'|@translate})
+          {/if}
+        </td>
+        <td>{$data.nbRates}</td>
+        <td>{$data.maxRate}</td>
+        <td>{$data.minRate}</td>
+        <td>{$data.avgRate}</td>
+        <td>{$data.devRate}</td>
+        <td>{$data.lastDayR}</td>
+        <td>{$data.delayR}</td>
+        <td>{$data.nbComments}</td>
+        <td>{$data.lastDayC}</td>
+        <td>{$data.delayC}</td>
+      </tr>
+  {/foreach}
+</table>
Index: /extensions/UserStat/language/en_UK/plugin.lang.php
===================================================================
--- /extensions/UserStat/language/en_UK/plugin.lang.php	(revision 4270)
+++ /extensions/UserStat/language/en_UK/plugin.lang.php	(revision 4270)
@@ -0,0 +1,53 @@
+<?php
+
+/* -----------------------------------------------------------------------------
+  This file was created by 'Translator r2.0.0-beta' plugin
+
+  **** Export informations
+  Export date       : 2009-11-15 18:01:09
+  Number of items   : 27
+    Number exported : 27
+  Exported by       : grum
+
+  **** File informations
+  Language          : English [ISO en_UK]
+  Charset           : utf-8
+  Type              : plugin
+  Name (Release)    : UserStat (1.0.0)
+
+  **** Export options
+  Items exported    : "ok"
+  Translator export : NO
+----------------------------------------------------------------------------- */
+
+
+$lang['us_categoryName'] = 'Category';
+$lang['us_detailledStatisticsForUser'] = 'Detailled statistics for user';
+$lang['us_lang'] = 'Lang';
+$lang['us_numberOfUsers'] = 'Number of users';
+$lang['us_property'] = 'Property';
+$lang['us_template'] = 'Template/Theme';
+$lang['us_titlePage'] = 'User Statistics';
+$lang['us_total'] = 'Registered users';
+$lang['us_tsGlobal'] = 'General';
+$lang['us_tsUsers'] = 'Users';
+$lang['us_userAvgRate'] = 'Average';
+$lang['us_userComments'] = 'Comments';
+$lang['us_userDelayC'] = 'Number of days since <br/> the last comment';
+$lang['us_userDelayR'] = 'Number of days since <br/> the last rate';
+$lang['us_userDevRate'] = 'Standard deviation';
+$lang['us_userLastDayC'] = 'Latest comment';
+$lang['us_userLastDayR'] = 'Last rate';
+$lang['us_userMaxRate'] = 'The highest';
+$lang['us_userMinRate'] = 'The lowest';
+$lang['us_userName'] = 'User';
+$lang['us_userNbComments'] = 'Number';
+$lang['us_userNbRates'] = 'Number';
+$lang['us_userRating'] = 'Rates';
+$lang['us_version'] = 'r';
+$lang['us_virtual'] = 'virtual';
+$lang['us_withHD'] = 'With HD';
+$lang['us_withMail'] = 'With eMail';
+
+
+?>
Index: /extensions/UserStat/language/en_UK/plugin.lang.php.backup
===================================================================
--- /extensions/UserStat/language/en_UK/plugin.lang.php.backup	(revision 4270)
+++ /extensions/UserStat/language/en_UK/plugin.lang.php.backup	(revision 4270)
@@ -0,0 +1,40 @@
+<?php
+
+//en_UK.UTF-8
+
+$lang['us_titlePage'] = "User Statistics";
+$lang['us_tsGlobal'] = "Générales";
+$lang['us_tsUsers'] = "Utilisateurs";
+$lang['us_version'] = "v";
+
+$lang['us_property'] = "Propriété";
+$lang['us_lang'] = "Langue";
+$lang['us_template'] = "Template/Thème";
+$lang['us_numberOfUsers'] = "Nombre d'utilisateurs";
+$lang['us_total'] = "Utilisateurs inscrits";
+$lang['us_withMail'] = "Avec eMail";
+$lang['us_withHD'] = "Avec HD";
+
+$lang['us_userName'] = "Utilisateur";
+
+$lang['us_userRating'] = "Notes";
+$lang['us_userNbRates'] = "Nombre";
+$lang['us_userMaxRate'] = "La plus élevée";
+$lang['us_userMinRate'] = "La plus basse";
+$lang['us_userAvgRate'] = "Moyenne";
+$lang['us_userDevRate'] = "Ecart type";
+$lang['us_userLastDayR'] = "Dernière note le";
+$lang['us_userDelayR'] = "Nombre de jours depuis<br/>la dernière note";
+
+$lang['us_userComments'] = "Commentaires";
+$lang['us_userNbComments'] = "Nombre";
+$lang['us_userLastDayC'] = "Dernier commentaire le";
+$lang['us_userDelayC'] = "Nombre de jours depuis<br/>le dernier commentaire";
+
+$lang['us_categoryName'] = "Catégorie";
+$lang['us_detailledStatisticsForUser'] = "Détail des statistiques pour l'utilisateur";
+
+$lang['us_virtual'] = "virtuelle";
+
+
+?>
Index: /extensions/UserStat/language/fr_FR/plugin.lang.php
===================================================================
--- /extensions/UserStat/language/fr_FR/plugin.lang.php	(revision 4270)
+++ /extensions/UserStat/language/fr_FR/plugin.lang.php	(revision 4270)
@@ -0,0 +1,53 @@
+<?php
+
+/* -----------------------------------------------------------------------------
+  This file was created by 'Translator r2.0.0-beta' plugin
+
+  **** Export informations
+  Export date       : 2009-11-15 18:01:09
+  Number of items   : 27
+    Number exported : 27
+  Exported by       : grum
+
+  **** File informations
+  Language          : Français [ISO fr_FR]
+  Charset           : utf-8
+  Type              : plugin
+  Name (Release)    : UserStat (1.0.0)
+
+  **** Export options
+  Items exported    : "ok"
+  Translator export : NO
+----------------------------------------------------------------------------- */
+
+
+$lang['us_categoryName'] = 'Catégorie';
+$lang['us_detailledStatisticsForUser'] = 'Détail des statistiques pour l\'utilisateur';
+$lang['us_lang'] = 'Langue';
+$lang['us_numberOfUsers'] = 'Nombre d\'utilisateurs';
+$lang['us_property'] = 'Propriété';
+$lang['us_template'] = 'Template/Thème';
+$lang['us_titlePage'] = 'Statistiques Utilisateurs';
+$lang['us_total'] = 'Utilisateurs inscrits';
+$lang['us_tsGlobal'] = 'Générales';
+$lang['us_tsUsers'] = 'Utilisateurs';
+$lang['us_userAvgRate'] = 'Moyenne';
+$lang['us_userComments'] = 'Commentaires';
+$lang['us_userDelayC'] = 'Nombre de jours depuis<br/>le dernier commentaire';
+$lang['us_userDelayR'] = 'Nombre de jours depuis<br/>la dernière note';
+$lang['us_userDevRate'] = 'Ecart type';
+$lang['us_userLastDayC'] = 'Dernier commentaire le';
+$lang['us_userLastDayR'] = 'Dernière note le';
+$lang['us_userMaxRate'] = 'La plus élevée';
+$lang['us_userMinRate'] = 'La plus basse';
+$lang['us_userName'] = 'Utilisateur';
+$lang['us_userNbComments'] = 'Nombre';
+$lang['us_userNbRates'] = 'Nombre';
+$lang['us_userRating'] = 'Notes';
+$lang['us_version'] = 'v';
+$lang['us_virtual'] = 'virtuelle';
+$lang['us_withHD'] = 'Avec HD';
+$lang['us_withMail'] = 'Avec eMail';
+
+
+?>
Index: /extensions/UserStat/language/fr_FR/plugin.lang.php.backup
===================================================================
--- /extensions/UserStat/language/fr_FR/plugin.lang.php.backup	(revision 4270)
+++ /extensions/UserStat/language/fr_FR/plugin.lang.php.backup	(revision 4270)
@@ -0,0 +1,40 @@
+<?php
+
+//fr_FR.UTF-8
+
+$lang['us_titlePage'] = "Statistiques Utilisateurs";
+$lang['us_tsGlobal'] = "Générales";
+$lang['us_tsUsers'] = "Utilisateurs";
+$lang['us_version'] = "v";
+
+$lang['us_property'] = "Propriété";
+$lang['us_lang'] = "Langue";
+$lang['us_template'] = "Template/Thème";
+$lang['us_numberOfUsers'] = "Nombre d'utilisateurs";
+$lang['us_total'] = "Utilisateurs inscrits";
+$lang['us_withMail'] = "Avec eMail";
+$lang['us_withHD'] = "Avec HD";
+
+$lang['us_userName'] = "Utilisateur";
+
+$lang['us_userRating'] = "Notes";
+$lang['us_userNbRates'] = "Nombre";
+$lang['us_userMaxRate'] = "La plus élevée";
+$lang['us_userMinRate'] = "La plus basse";
+$lang['us_userAvgRate'] = "Moyenne";
+$lang['us_userDevRate'] = "Ecart type";
+$lang['us_userLastDayR'] = "Dernière note le";
+$lang['us_userDelayR'] = "Nombre de jours depuis<br/>la dernière note";
+
+$lang['us_userComments'] = "Commentaires";
+$lang['us_userNbComments'] = "Nombre";
+$lang['us_userLastDayC'] = "Dernier commentaire le";
+$lang['us_userDelayC'] = "Nombre de jours depuis<br/>le dernier commentaire";
+
+$lang['us_categoryName'] = "Catégorie";
+$lang['us_detailledStatisticsForUser'] = "Détail des statistiques pour l'utilisateur";
+
+$lang['us_virtual'] = "virtuelle";
+
+
+?>
Index: /extensions/UserStat/main.inc.php
===================================================================
--- /extensions/UserStat/main.inc.php	(revision 4270)
+++ /extensions/UserStat/main.inc.php	(revision 4270)
@@ -0,0 +1,70 @@
+<?php
+/*
+Plugin Name: UserStat
+Version: 1.0.0
+Description: Statistiques utilisateurs / Users statistics
+Plugin URI: http://phpwebgallery.net/ext/extension_view.php?eid=
+Author: grum@piwigo.org
+Author URI: http://photos.grum.fr/
+*/
+
+/*
+--------------------------------------------------------------------------------
+  Author     : Grum
+    email    : grum@piwigo.org
+    website  : http://photos.grum.fr
+    PWG user : http://forum.phpwebgallery.net/profile.php?id=3706
+
+    << May the Little SpaceFrog be with you ! >>
+--------------------------------------------------------------------------------
+
+:: HISTORY
+
+
+| release | date       |
+| 1.0.0   | 2009/11/15 | * first public release
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+
+
+
+:: TO DO
+
+--------------------------------------------------------------------------------
+
+:: NFO
+  UserStat_AIM : classe to manage plugin integration into plugin menu
+  UserStat_AIP : classe to manage plugin admin pages
+
+--------------------------------------------------------------------------------
+*/
+
+// pour faciliter le debug :o)
+// ini_set('error_reporting', E_ALL);
+// ini_set('display_errors', true);
+
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+define('USERSTAT_DIR' , basename(dirname(__FILE__)));
+define('USERSTAT_PATH' , PHPWG_PLUGINS_PATH . USERSTAT_DIR . '/');
+
+define('USERSTAT_VERSION' , '1.0.0'); // => ne pas oublier la version dans l'entête !!
+
+global $prefixeTable;
+
+//UserStat loaded and active only if in admin page
+if(basename($_SERVER["PHP_SELF"])=='admin.php')
+{
+  include_once("userstat_aim.class.inc.php");
+
+  $obj = new UserStat_AIM($prefixeTable, __FILE__);
+  $obj->init_events();
+  set_plugin_data($plugin['id'], $obj);
+}
+
+?>
Index: /extensions/UserStat/maintain.inc.php
===================================================================
--- /extensions/UserStat/maintain.inc.php	(revision 4270)
+++ /extensions/UserStat/maintain.inc.php	(revision 4270)
@@ -0,0 +1,100 @@
+<?php
+/* -----------------------------------------------------------------------------
+  Plugin     : UserStat
+  Author     : Grum
+    email    : grum@piwigo.org
+    website  : http://photos.grum.fr
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+  See main.inc.php for release information
+
+  --------------------------------------------------------------------------- */
+//ini_set('error_reporting', E_ALL);
+//ini_set('display_errors', true);
+
+if (!defined('PHPWG_ROOT_PATH')) { die('Hacking attempt!'); }
+
+define('USERSTAT_DIR' , basename(dirname(__FILE__)));
+define('USERSTAT_PATH' , PHPWG_PLUGINS_PATH . USERSTAT_DIR . '/');
+
+
+global $gpc_installed, $lang; //needed for plugin manager compatibility
+
+/* -----------------------------------------------------------------------------
+AStat-2 needs the Grum Plugin Classe
+----------------------------------------------------------------------------- */
+$gpc_installed=false;
+if(file_exists(PHPWG_PLUGINS_PATH.'grum_plugins_classes-2/common_plugin.class.inc.php'))
+{
+  @include_once(PHPWG_PLUGINS_PATH.'grum_plugins_classes-2/main.inc.php');
+  // need GPC release greater or equal than 2.0.1
+  if(checkGPCRelease(2,0,1))
+  {
+    @include_once("userstat_aim.class.inc.php");
+    $gpc_installed=true;
+  }
+}
+
+function gpcMsgError(&$errors)
+{
+  array_push($errors, sprintf(l10n('us_gpc2_not_installed'), "2.0.1"));
+}
+// -----------------------------------------------------------------------------
+
+
+load_language('plugin.lang', USERSTAT_PATH);
+
+function plugin_install($plugin_id, $plugin_version, &$errors)
+{
+  global $prefixeTable, $gpc_installed;
+  if($gpc_installed)
+  {
+    $obj = new UserStat_AIM($prefixeTable, __FILE__);
+    $obj->delete_config();
+    $obj->init_config();
+    $obj->save_config();
+  }
+  else
+  {
+    gpcMsgError($errors);
+  }
+}
+
+function plugin_activate($plugin_id, $plugin_version, &$errors)
+{
+  global $prefixeTable, $gpc_installed;
+  if($gpc_installed)
+  {
+    $obj = new UserStat_AIM($prefixeTable, __FILE__);
+    $obj->init_config();
+    $obj->load_config();
+    $obj->save_config();
+  }
+  else
+  {
+    gpcMsgError($errors);
+  }
+}
+
+function plugin_deactivate($plugin_id)
+{
+}
+
+function plugin_uninstall($plugin_id)
+{
+  global $prefixeTable, $gpc_installed;
+  if($gpc_installed)
+  {
+    $obj = new UserStat_AIM($prefixeTable, __FILE__);
+    $obj->delete_config();
+  }
+  else
+  {
+    gpcMsgError($errors);
+  }
+}
+
+
+
+?>
Index: /extensions/UserStat/userstat.css
===================================================================
--- /extensions/UserStat/userstat.css	(revision 4270)
+++ /extensions/UserStat/userstat.css	(revision 4270)
@@ -0,0 +1,13 @@
+
+.StatTableRow:hover { background-color:#303030; }
+.formtable, .formtable P { text-align:left; display:block; }
+.formtable tr { vertical-align:top; }
+.invisible { visibility:hidden; display:none; }
+.littlefont { font-size:90%; }
+table.table2.littlefont td { text-align:center;padding:0px;padding-left:3px;padding-right:3px; }
+.throw { line-height:auto; font-size:100%; }
+table.table2 tr.throw { height:26px; }
+table.table2 td.toLeft  { text-align:left; }
+div.table { margin-bottom:15px; }
+pointerHand { cursor:pointer; }
+    
Index: /extensions/UserStat/userstat_aim.class.inc.php
===================================================================
--- /extensions/UserStat/userstat_aim.class.inc.php	(revision 4270)
+++ /extensions/UserStat/userstat_aim.class.inc.php	(revision 4270)
@@ -0,0 +1,126 @@
+<?php
+/* -----------------------------------------------------------------------------
+  Plugin     : UserStat
+  Author     : Grum
+    email    : grum@piwigo.org
+    website  : http://photos.grum.fr
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+  See main.inc.php for release information
+
+  UserStat_AIM : classe to manage plugin integration into plugin menu
+
+  --------------------------------------------------------------------------- */
+
+if (!defined('PHPWG_ROOT_PATH')) { die('Hacking attempt!'); }
+
+include_once(PHPWG_PLUGINS_PATH.'grum_plugins_classes-2/common_plugin.class.inc.php');
+include_once(PHPWG_PLUGINS_PATH.'grum_plugins_classes-2/css.class.inc.php');
+
+class UserStat_AIM extends common_plugin
+{
+  protected $css = null;
+
+  function UserStat_AIM($prefixeTable, $filelocation)
+  {
+    $this->plugin_name="UserStat";
+    $this->plugin_name_files="userstat";
+    parent::__construct($prefixeTable, $filelocation);
+    $this->css = new css(dirname($this->filelocation).'/'.$this->plugin_name_files.".css");
+  }
+
+  /*
+    initialize events call for the plugin
+  */
+  function init_events()
+  {
+    add_event_handler('get_admin_plugin_menu_links', array(&$this, 'plugin_admin_menu') );
+  }
+
+
+  /*
+    initialization of config properties
+  */
+  function init_config()
+  {
+    $this->my_config=array(
+      'UserStat_MouseOverColor' => '303030',
+      /*'AStat_BarColor_Pages' => '6666ff',
+      'AStat_BarColor_Img' => '66ff66',
+      'AStat_BarColor_IP' => 'ff6666',
+      'AStat_NpIPPerPages' => '25',
+      'AStat_NpCatPerPages' => '50',
+      'AStat_MaxBarWidth' => '400',
+      'AStat_default_period' => 'global', //global, all, year, month, day
+      'AStat_ShowThumbCat' => 'true',
+      'AStat_DefaultSortCat' => 'page', //page, picture, nbpicture
+      'AStat_ShowThumbImg' => 'true',
+      'AStat_DefaultSortImg' => 'picture',  //picture, catname
+      'AStat_NbImgPerPages' => '100',
+      'AStat_BarColor_Cat' => 'fff966',
+      'AStat_DefaultSortIP' => 'page',    //page, ip, picture
+      'AStat_SeeTimeRequests' => 'false',
+      'AStat_BlackListedIP' => '',    // ip blacklisted (separator : ",")
+      'AStat_UseBlackList' => 'false'    // if false, blacklist usage is disabled, if "invert" then result are inverted*/
+      );
+
+  }
+
+  /*
+    surchage of common_plugin->save_config function
+  */
+  function load_config()
+  {
+    parent::load_config();
+    if(!$this->css->css_file_exists())
+    {
+      $this->css->make_CSS($this->generate_CSS());
+    }
+  }
+
+  /*
+    surchage of common_plugin->save_config function
+  */
+  function save_config()
+  {
+    if(parent::save_config())
+    {
+      $this->css->make_CSS($this->generate_CSS());
+      return(true);
+    }
+    return(false);
+  }
+
+  /*
+    generate the css code
+  */
+  function generate_CSS()
+  {
+    $text = "
+.StatTableRow:hover { background-color:#".$this->my_config['UserStat_MouseOverColor']."; }
+.formtable, .formtable P { text-align:left; display:block; }
+.formtable tr { vertical-align:top; }
+.invisible { visibility:hidden; display:none; }
+.littlefont { font-size:90%; }
+table.table2.littlefont td { text-align:center;padding:0px;padding-left:3px;padding-right:3px; }
+.throw { line-height:auto; font-size:100%; }
+table.table2 tr.throw { height:26px; }
+table.table2 td.toLeft  { text-align:left; }
+div.table { margin-bottom:15px; }
+pointerHand { cursor:pointer; }
+    ";
+
+    return($text);
+  }
+
+  /* ---------------------------------------------------------------------------
+  Function needed for plugin activation
+  --------------------------------------------------------------------------- */
+
+
+
+} // UserStat_Plugin class
+
+
+?>
Index: /extensions/UserStat/userstat_aip.class.inc.php
===================================================================
--- /extensions/UserStat/userstat_aip.class.inc.php	(revision 4270)
+++ /extensions/UserStat/userstat_aip.class.inc.php	(revision 4270)
@@ -0,0 +1,541 @@
+<?php
+/* -----------------------------------------------------------------------------
+  Plugin     : UserStat
+  Author     : Grum
+    email    : grum@piwigo.org
+    website  : http://photos.grum.fr
+
+    << May the Little SpaceFrog be with you ! >>
+  ------------------------------------------------------------------------------
+  See main.inc.php for release information
+
+  AI classe => manage integration in administration interface
+
+  --------------------------------------------------------------------------- */
+if (!defined('PHPWG_ROOT_PATH')) { die('Hacking attempt!'); }
+
+include_once('userstat_aim.class.inc.php');
+include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php');
+include_once(PHPWG_PLUGINS_PATH.'grum_plugins_classes-2/ajax.class.inc.php');
+
+class UserStat_AIP extends UserStat_AIM
+{
+  protected $tabsheet;
+  protected $ajax;
+
+  function UserStat_AIP($prefixeTable, $filelocation)
+  {
+    parent::__construct($prefixeTable, $filelocation);
+
+    $this->load_config();
+    $this->init_events();
+
+    $this->tabsheet = new tabsheet();
+    $this->tabsheet->add('global_stats',
+                          l10n('us_tsGlobal'),
+                          $this->page_link.'&amp;fUserStat_tabsheet=global_stats');
+    $this->tabsheet->add('users_stats',
+                          l10n('us_tsUsers'),
+                          $this->page_link.'&amp;fUserStat_tabsheet=users_stats');
+
+    $this->ajax = new Ajax();
+  }
+
+  /*
+    initialize events call for the plugin
+  */
+  function init_events()
+  {
+    add_event_handler('loc_end_page_header', array(&$this->css, 'apply_CSS'));
+  }
+
+
+
+  /* ---------------------------------------------------------------------------
+  Public classe functions
+  --------------------------------------------------------------------------- */
+
+  /*
+    manage plugin integration into piwigo's admin interface
+  */
+  public function manage()
+  {
+    global $template;
+
+    $this->returnAjaxContent();
+
+    $template->set_filename('plugin_admin_content', dirname(__FILE__)."/admin/userstat_admin.tpl");
+
+    $this->initRequest();
+
+
+    if($_REQUEST['fUserStat_tabsheet']=='global_stats')
+    {
+      $this->displayGlobalStats();
+    }
+    elseif($_REQUEST['fUserStat_tabsheet']=='users_stats')
+    {
+      $this->displayUsersStats();
+    }
+
+    $this->tabsheet->select($_REQUEST['fUserStat_tabsheet']);
+    $this->tabsheet->assign();
+    $selected_tab=$this->tabsheet->get_selected();
+    $template->assign($this->tabsheet->get_titlename(), "[".$selected_tab['caption']."]");
+
+    $template_plugin["USERSTAT_VERSION"] = "<i>UserStat</i> ".l10n('us_version').USERSTAT_VERSION;
+    $template_plugin["USERSTAT_PAGE"] = $_REQUEST['fUserStat_tabsheet'];
+
+    $template->assign('plugin', $template_plugin);
+    $template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content');
+  }
+
+  /* ---------------------------------------------------------------------------
+  Private classe functions
+  --------------------------------------------------------------------------- */
+
+  /*
+    return ajax content
+  */
+  protected function returnAjaxContent()
+  {
+    global $ajax, $template;
+
+    if(isset($_REQUEST['ajaxfct']))
+    {
+      //$this->debug("AJAXFCT:".$_REQUEST['ajaxfct']);
+      $result="<p class='errors'>An error has occured</p>";
+      switch($_REQUEST['ajaxfct'])
+      {
+        case 'userStat':
+          $result=$this->ajaxGetUserStat($_REQUEST['userId']);
+          break;
+      }
+      //$template->
+      $this->ajax->return_result($result);
+    }
+  }
+
+
+
+  private function initRequest()
+  {
+    //initialise $REQUEST values if not defined
+    if(!array_key_exists('fUserStat_tabsheet', $_REQUEST))
+    {
+      $_REQUEST['fUserStat_tabsheet']='global_stats';
+    }
+  }
+
+
+  private function displayGlobalStats()
+  {
+    global $template;
+
+    $template->set_filename('body_page', dirname(__FILE__)."/admin/userstat_global.tpl");
+
+    $template_datas = array();
+
+    $template_datas["propertiesUsers"] = $this->getNumberOfUsers();
+    $template_datas["languagesUsers"] = $this->getLanguagesOfUsers();
+    $template_datas["templatesUsers"] = $this->getTemplatesOfUsers();
+
+    $template->assign('datas', $template_datas);
+    $template->assign_var_from_handle('USERSTAT_BODY_PAGE', 'body_page');
+  }
+
+
+  private function displayUsersStats()
+  {
+    global $template;
+
+    $template->set_filename('body_page', dirname(__FILE__)."/admin/userstat_users.tpl");
+
+    $template_datas = array();
+
+    $template_datas["ajaxUrl"] = $this->page_link;
+    $template_datas["users"] = $this->getUsersGlobalStats();
+
+    $template->assign('datas', $template_datas);
+    $template->assign_var_from_handle('USERSTAT_BODY_PAGE', 'body_page');
+  }
+
+
+
+  private function makeUserStats($userId)
+  {
+    $returned=array();
+    $userStats=$this->getUserStats($userId);
+
+//$this->format_link($stats[$i]["CatName"], )." / ";
+
+    $catList = "";
+    foreach($userStats as $key => $val)
+    {
+      ($catList=="")?$catList=$val["upperCats"]:$catList.=",".$val["upperCats"];
+    }
+
+    $sql="
+SELECT name as categoryName,
+       id as categoryId,
+       '' AS nbRates,
+       '' AS maxRate,
+       '' AS minRate,
+       '' AS avgRate,
+       '' AS devRate,
+       '' AS nbDaysR,
+       '' AS lastDayR,
+       '' AS delayR,
+       '' AS nbComments,
+       '' AS nbDaysC,
+       '' AS lastDayC,
+       '' AS delayC,
+       IF(dir IS NULL, 'N', 'Y') AS physical,
+       global_rank,
+       uppercats
+FROM ".CATEGORIES_TABLE."
+WHERE id IN (".$catList.")
+ORDER BY global_rank;";
+
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_assoc($result))
+      {
+        $row['indent']=substr_count($row['global_rank'], '.');
+        if(array_key_exists($row['categoryId'], $userStats))
+        {
+          foreach($userStats[$row['categoryId']] as $key => $val)
+          {
+            $row[$key]=$val;
+          }
+        }
+        $row['categoryName']=$this->format_link($row['categoryName'], PHPWG_ROOT_PATH."index.php?/category/".$row['categoryId']);
+        if($row['indent']>0)
+        {
+          $row['categoryName']=str_repeat("&nbsp;", $row['indent']*5)."+ - - ".$row['categoryName'];
+        }
+        $returned[]=$row;
+      }
+    }
+
+    return($returned);
+  }
+
+
+  /*
+    format text : <a href="$link">$value</a>
+  */
+  private function format_link($value, $link)
+  {
+    return("<a href='$link'>$value</a>");
+  }
+
+
+  /* ---------------------------------------------------------------------------
+   * SQL Requests functions
+   * ------------------------------------------------------------------------- */
+
+  private function getUserName($userId)
+  {
+    $sql="SELECT username FROM ".USERS_TABLE." WHERE id = ".$userId;
+    $result=pwg_query($sql);
+    if($result)
+    {
+      $row=mysql_fetch_assoc($result);
+      return($row["username"]);
+    }
+    return("#".$userId);
+  }
+
+  /*
+   * returns an array
+   *   - "total" : total number of users
+   *   - "withmail" : total number with email
+   *   - "withoutMail" : total number without email
+  */
+  private function getNumberOfUsers()
+  {
+    $returned=Array(
+      "total" => 0,
+      "withMail" => 0,
+      "withoutMail" => 0);
+
+    $sql="SELECT 'total' AS property, count(id) AS counter
+          FROM ".USERS_TABLE."
+          GROUP BY property
+          UNION
+          SELECT IF(mail_address is null, 'withoutMail', 'withMail') AS property, COUNT(IF(mail_address is null, 'withoutMail', 'withMail')) AS counter
+          FROM ".USERS_TABLE."
+          GROUP BY property
+          UNION
+          SELECT IF(enabled_high != true, 'withoutHD', 'withHD') AS property, count(IF(enabled_high != true , 'withoutHD', 'withHD')) AS counter
+          FROM ".USER_INFOS_TABLE."
+          GROUP BY property
+          ";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_row($result))
+      {
+        $returned[]=Array(
+          "property" => $row[0],
+          "value" => $row[1],
+          "label" => l10n("us_".$row[0])
+        );
+      }
+    }
+    return($returned);
+  }
+
+  /*
+   * returns an array of used languages
+   * each row is an array :
+   *  "nbUsers" : number of users using the language
+   *  "language" : language used
+  */
+  private function getLanguagesOfUsers()
+  {
+    $returned = array();
+    $list = get_languages();
+
+    $sql="SELECT count(user_id) as nbUsers, language FROM ".USER_INFOS_TABLE." GROUP BY language ORDER BY nbUsers DESC";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_assoc($result))
+      {
+        $row["humanReadable"]=$list[$row["language"]];
+        $returned[]=$row;
+      }
+    }
+    return($returned);
+  }
+
+  /*
+   * returns an array of used templates/themes
+   * each row is an array :
+   *  "nbUsers"  : number of users using the language
+   *  "template" : template/theme used
+  */
+  private function getTemplatesOfUsers()
+  {
+    $returned = array();
+
+    $sql="SELECT count(user_id) as nbUsers, template FROM ".USER_INFOS_TABLE." GROUP BY template ORDER BY nbUsers DESC";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_assoc($result))
+      {
+        $returned[]=$row;
+      }
+    }
+    return($returned);
+  }
+
+  /*
+   * returns an array of users stats properties (global stats)
+   * each row is an array :
+   *  "name"       : the user name
+   *  "id"         : the user id
+   *  "nbRates"    : number of rates made by the user
+   *  "maxRate"    : highest rate made by the user
+   *  "minRate"    : lowest rate made by the user
+   *  "avgRate"    : average rate made by th user
+   *  "devRate"    : deviation rate made by the user
+   *  "nbDaysR"    : number of days where the user made a rate
+   *  "lastDayR"   : last date when a user made a rate
+   *  "delayR"     : delay (in days) between the first and the last rate
+   *  "nbComments" : number of comment post by the user
+   *  "nbDaysC"    : number of days where the user post a comment
+   *  "lastDayC"   : last date when a user post a comment
+   *  "delayC"     : delay (in days) between the first and the last posted comment
+  */
+  private function getUsersGlobalStats()
+  {
+    $returned=array();
+
+    $sql="
+SELECT name,
+       MAX(id) AS id,
+       MAX(nbRates) AS nbRates,
+       MAX(maxRate) AS maxRate,
+       MAX(minRate) AS minRate,
+       MAX(avgRate) AS avgRate,
+       MAX(devRate) AS devRate,
+       MAX(lastDayR) AS lastDayR,
+       MAX(delayR) AS delayR,
+       MAX(nbComments) AS nbComments,
+       MAX(lastDayC) AS lastDayC,
+       MAX(delayC) AS delayC
+FROM (
+      SELECT  username AS name,
+              user_id AS id,
+              COUNT(element_id) AS nbRates,
+              MAX(rate) AS maxRate,
+              MIN(rate) AS minRate,
+              ROUND(AVG(rate), 2) AS avgRate,
+              ROUND(STDDEV(rate), 2) AS devRate,
+              MAX(rt.date) AS lastDayR,
+              DATEDIFF(CURDATE(), MAX(rt.date)) AS delayR,
+              '' AS nbComments,
+              '' AS lastDayC,
+              '' AS delayC
+      FROM ".RATE_TABLE." as rt
+            JOIN ".USERS_TABLE." ut ON ut.id = rt.user_id
+      GROUP BY user_id
+      UNION
+      SELECT author AS name,
+          ut.id AS id,
+          '' AS nbRates,
+          '' AS maxRate,
+          '' AS minRate,
+          '' AS avgRate,
+          '' AS devRate,
+          '' AS lastDayR,
+          '' AS delayR,
+          COUNT(ct.id) AS nbComments,
+          MAX(DATE(date)) AS lastDayC,
+          DATEDIFF(CURDATE(), MAX(date)) AS delayC
+      FROM ".COMMENTS_TABLE." as ct
+           JOIN ".USERS_TABLE." ut ON ut.username = ct.author
+      GROUP BY author
+     ) AS t1
+GROUP BY id;";
+
+
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_assoc($result))
+      {
+        $returned[]=$row;
+      }
+    }
+
+    return($returned);
+  }
+
+
+  /*
+   * returns an array of user stats properties
+   *
+   * parameters :
+   *  $userId : the user id
+   *
+   * each row is an array :
+   *  "categoryId" : the category id
+   *  "catName"    : the categery name
+   *  "physical"   : "Y" if the category is physical, "N" if it's a virtual category
+   *  "nbRates"    : number of rates made by the user
+   *  "maxRate"    : highest rate made by the user
+   *  "minRate"    : lowest rate made by the user
+   *  "avgRate"    : average rate made by th user
+   *  "devRate"    : deviation rate made by the user
+   *  "nbDaysR"    : number of days where the user made a rate
+   *  "lastDayR"   : last date when a user made a rate
+   *  "delayR"     : delay (in days) between the first and the last rate
+   *  "nbComments" : number of comment post by the user
+   *  "nbDaysC"    : number of days where the user post a comment
+   *  "lastDayC"   : last date when a user post a comment
+   *  "delayC"     : delay (in days) between the first and the last posted comment
+  */
+  private function getUserStats($userId)
+  {
+    $returned=array();
+
+    $sql="
+SELECT t1.name AS name,
+       MAX(t1.id) AS id,
+       MAX(nbRates) AS nbRates,
+       MAX(maxRate) AS maxRate,
+       MAX(minRate) AS minRate,
+       MAX(avgRate) AS avgRate,
+       MAX(devRate) AS devRate,
+       MAX(lastDayR) AS lastDayR,
+       MAX(delayR) AS delayR,
+       MAX(nbComments) AS nbComments,
+       MAX(lastDayC) AS lastDayC,
+       MAX(delayC) AS delayC,
+       category_id as categoryId,
+       uppercats AS upperCats
+FROM (
+      SELECT username AS name,
+             user_id AS id,
+             COUNT(element_id) as nbRates,
+             MAX(rate) AS maxRate,
+             MIN(rate) AS minRate,
+             ROUND(AVG(rate),2) AS avgRate,
+             ROUND(STDDEV(rate),2) AS devRate,
+             MAX(rt.date) AS lastDayR,
+             DATEDIFF(CURDATE(), MAX(rt.date)) AS delayR,
+             '' AS nbComments,
+             '' AS lastDayC,
+             '' AS delayC,
+             category_id
+      FROM ".RATE_TABLE." AS rt
+           JOIN ".USERS_TABLE." AS ut ON ut.id = rt.user_id
+                LEFT OUTER JOIN ".IMAGE_CATEGORY_TABLE." AS ict ON ict.image_id = rt.element_id
+      WHERE ut.id = ".$userId."
+      GROUP BY id, category_id
+      UNION
+      SELECT author AS name,
+             ut2.id AS id,
+             '' AS nbRates,
+             '' AS maxRate,
+             '' AS minRate,
+             '' AS avgRate,
+             '' AS devRate,
+             '' AS lastDayR,
+             '' AS delayR,
+             COUNT(ct2.id) AS nbComments,
+             MAX(DATE(date)) AS lastDayC,
+             DATEDIFF(CURDATE(), MAX(date)) AS delayC,
+             category_id
+      FROM ".COMMENTS_TABLE." AS ct2
+           JOIN ".USERS_TABLE." AS ut2 ON ut2.username = ct2.author
+                LEFT OUTER JOIN ".IMAGE_CATEGORY_TABLE." AS ict2 ON ict2.image_id = ct2.image_id
+      WHERE ut2.id = ".$userId."
+      GROUP BY id
+     ) AS t1
+       LEFT OUTER JOIN ".CATEGORIES_TABLE." AS ct ON t1.category_id = ct.id
+GROUP BY t1.id, category_id";
+
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_assoc($result))
+      {
+        $returned[$row['categoryId']]=$row;
+      }
+    }
+
+    return($returned);
+  }
+
+
+
+
+  /* ---------------------------------------------------------------------------
+   * AJAX functions
+   * ------------------------------------------------------------------------- */
+
+  private function ajaxGetUserStat($userId)
+  {
+    $local_tpl = new Template(USERSTAT_PATH."admin/", "");
+    $local_tpl->set_filename('body_page',
+                  dirname($this->filelocation).'/admin/userstat_userstat.tpl');
+
+    $template_datas["list"] = $this->makeUserStats($userId);
+    $template_datas["userName"] = $this->getUserName($userId);
+
+    $local_tpl->assign('datas', $template_datas);
+    return($local_tpl->parse('body_page', true));
+  }
+
+
+} // UserStat_AI class
+
+
+?>
