Index: /extensions/AMetaData/admin/amd_admin.tpl
===================================================================
--- /extensions/AMetaData/admin/amd_admin.tpl	(revision 4905)
+++ /extensions/AMetaData/admin/amd_admin.tpl	(revision 4905)
@@ -0,0 +1,8 @@
+<div class="titrePage">
+  <h2 style="position:absolute;right:0px;top:32px;height:auto;font-size:12px;font-weight:normal;">:: {$plugin.AMD_VERSION} ::</h2>
+  <h2>{'amd_title_page'|@translate} <span style="font-size:-1;font-weight:normal;">{$TABSHEET_TITLE}</span></h2>
+
+</div>
+
+{$AMD_BODY_PAGE}
+
Index: /extensions/AMetaData/admin/amd_database.tpl
===================================================================
--- /extensions/AMetaData/admin/amd_database.tpl	(revision 4905)
+++ /extensions/AMetaData/admin/amd_database.tpl	(revision 4905)
@@ -0,0 +1,258 @@
+{known_script id="jquery.ui" src=$ROOT_URL|@cat:"template-common/lib/ui/ui.core.packed.js"}
+{known_script id="jquery.ui.slider" src=$ROOT_URL|@cat:"template-common/lib/ui/ui.slider.packed.js"}
+{known_script id="jquery.ui.dialog" src=$ROOT_URL|@cat:"template-common/lib/ui/ui.dialog.packed.js"}
+
+{literal}
+<style>
+ .ui-slider {
+    width:350px;
+    height:10px;
+    border:1px solid;
+    margin-left:10px;
+  }
+ .ui-slider-handle {
+    width:12px;
+    height:12px;
+    position:relative;
+    top:-2px;
+    border:1px solid;
+    background:#cccccc;
+  }
+</style>
+
+<script type="text/javascript">
+
+  function init()
+  {
+    formatNbItemPerRequest({/literal}{$datas.NumberOfItemsPerRequest}{literal});
+    $("#iamd_nb_item_per_request_slider").slider(
+      {
+        min:5,
+        max:150,
+        steps:29,
+        startValue:{/literal}{$datas.NumberOfItemsPerRequest}{literal},
+        slide: function(event, ui) { formatNbItemPerRequest(ui.value); }
+      }
+    );
+    getStatus();
+  }
+
+  function formatNbItemPerRequest(nbItems)
+  {
+    $("#iamd_NumberOfItemsPerRequest").val(nbItems);
+    $("#iamd_nb_item_per_request_display").html(nbItems);
+  }
+
+  function getStatus()
+  {
+    data=$.ajax(
+      {
+        type: "POST",
+        url: "{/literal}{$datas.urlRequest}{literal}",
+        async: false,
+        data: { ajaxfct:"makeStatsGetStatus" }
+      }
+    ).responseText;
+
+    list=data.split(";");
+    $("#ianalyzestatus").html("<ul><li>"+list[0]+"</li><li>"+list[1]+"</li><li>"+list[2]+"</li></ul>");
+  }
+
+  function doAnalyze()
+  {
+    $("body").css("cursor", "wait");
+
+    mode="all";
+    modeLabel="{/literal}{'g003_analyze_all_pictures'|@translate}{literal}";
+    if($("#ianalyze_action0").get(0).checked)
+    {
+      mode="notAnalyzed";
+      modeLabel="{/literal}{'g003_analyze_not_analyzed_pictures'|@translate}{literal}";
+    }
+
+    doAnalyze="<br><form id='iDialogProgress' class='formtable'>"+
+      "<div id='iprogressbar_contener'>"+
+      "<span id='iprogressbar_bg' style='width:0%;'>&nbsp;</span>"+
+      "<span id='iprogressbar_fg'>0%</span>"+
+      "</div>{/literal}{'g003_analyze_in_progress'|@translate}{literal}</form>";
+
+    $("#dialog")
+    .html("")
+    .dialog(
+      {
+        resizable: false,
+        width:480,
+        height:120,
+        modal: true,
+        draggable:false,
+        title: '{/literal}{"g003_updating_metadata"|@translate}{literal}&nbsp;('+modeLabel+')',
+        overlay:
+        {
+          backgroundColor: '#000',
+          opacity: 0.5,
+        }
+      }
+    ).html(doAnalyze);
+
+    NumberOfItemsPerRequest=$("#iamd_NumberOfItemsPerRequest").val();
+
+    $.ajax(
+      {
+        type: "POST",
+        url: "{/literal}{$datas.urlRequest}{literal}",
+        async: false,
+        data: { ajaxfct:"makeStatsGetList", selectMode:mode, numOfItems:NumberOfItemsPerRequest },
+        success: function(msg)
+          {
+            doStep_getList(msg);
+          },
+        error: function()
+          {
+            alert('error');
+          }
+      }
+    );
+  }
+
+
+  function displayTime(eTime)
+  {
+    seconds=(eTime%60).toFixed(2);
+    minutes=((eTime-seconds)/60).toFixed(0);
+    returned=seconds+"s";
+    if(minutes>0) returned=minutes+"m"+returned;
+    return(returned);
+  }
+
+  function doStep_getList(data)
+  {
+    timeStart = new Date();
+    list=data.split(";");
+    for(i=0;i<list.length-1;i++)
+    {
+      tmp = $.ajax({
+        type: "POST",
+        url: "{/literal}{$datas.urlRequest}{literal}",
+        async: false,
+        data: { ajaxfct:"makeStatsDoAnalyze", imagesList:list[i] }
+       }).responseText;
+
+      pct=100*(i+1)/(list.length+2);
+      $("#iprogressbar_bg").css("width", pct+"%");
+      $("#iprogressbar_fg").html(Math.round(pct)+"%");
+    }
+
+    for(j=0;j<3;j++)
+    {
+      tmp = $.ajax({
+        type: "POST",
+        url: "{/literal}{$datas.urlRequest}{literal}",
+        async: false,
+        data: { ajaxfct:"makeStatsConsolidate", step:j }
+       }).responseText;
+
+      pct=100*(i+j+1)/(list.length+2);
+      $("#iprogressbar_bg").css("width", pct+"%");
+      $("#iprogressbar_fg").html(Math.round(pct)+"%");
+    }
+
+    timeEnd = new Date();
+    timeElapsed=timeEnd.getTime()-timeStart.getTime();
+
+
+    $("#dialog")
+    .dialog("destroy")
+    .html("")
+    .get(0).removeAttribute('style');
+
+    $("#dialog")
+    .dialog(
+      {
+        resizable: false,
+        width:480,
+        height:120,
+        modal: true,
+        draggable:false,
+        title: '{/literal}{"g003_updating_metadata"|@translate}{literal}',
+        overlay:
+        {
+          backgroundColor: '#000',
+          opacity: 0.5
+        },
+        open: function(event, ui)
+        {
+          bH=$("div.ui-dialog-buttonpane").get(0).clientHeight;
+          $("#dialog").css('height', (this.clientHeight-bH)+"px");
+        },
+        buttons:
+        {
+          '{/literal}{"g003_ok"|@translate}{literal}':
+            function()
+            {
+              $(this).dialog('destroy').html("").get(0).removeAttribute('style');
+            }
+        }
+      }
+    ).html("<br>{/literal}{'g003_analyze_is_finished'|@translate}{literal}&nbsp;("+displayTime(timeElapsed/1000)+")");
+
+    getStatus();
+    $("body").css("cursor", "default");
+  }
+
+
+
+</script>
+{/literal}
+
+<h3>{'g003_status_of_database'|@translate}</h3>
+
+<div id="dialog"></div>
+
+<div id="ianalyzestatus">
+  <ul>
+    <li>{'g003_loading'|@translate}</li>
+    <li>{'g003_loading'|@translate}</li>
+    <li>{'g003_loading'|@translate}</li>
+  </ul>
+</div>
+
+<div id='ianalyzearea'>
+  <fieldset>
+    <legend>{'g003_update_metadata'|@translate}</legend>
+      <form class="formtable">
+        <div class="warning">
+          <p style="font-weight:bold; font-size:+1;">{'g003_warning_on_analyze_0'|@translate}</p>
+          <p>{'g003_warning_on_analyze_1'|@translate}</p>
+          <p  style="font-weight:bold;">{'g003_warning_on_analyze_2'|@translate}</p>
+          <p>{'g003_warning_on_analyze_3'|@translate}</p>
+        </div>
+
+        <label>
+          <input type="radio" value="notAnalayzed" name="fAMD_analyze_action" id="ianalyze_action0" checked>&nbsp;
+          {'g003_analyze_not_analyzed_pictures'|@translate}
+        </label><br>
+
+        <label>
+          <input type="radio" value="all" name="fAMD_analyze_action" id="ianalyze_action1">&nbsp;
+          {'g003_analyze_all_pictures'|@translate}
+        </label><br>
+
+        <br>
+        {'g003_setting_nb_items_per_request'|@translate}&nbsp;
+        <input type="hidden" id="iamd_NumberOfItemsPerRequest" value="{$datas.NumberOfItemsPerRequest}">
+        <div id="iamd_nb_item_per_request_slider"></div>
+        <div id="iamd_nb_item_per_request_display"></div>
+        <br><br>
+
+        <input type="button" value="{'g003_analyze'|@translate}" onclick="doAnalyze();">
+
+      </form>
+  </fieldset>
+</div>
+
+
+
+
+<script type="text/javascript">
+  init();
+</script>
Index: /extensions/AMetaData/admin/amd_metadata.tpl
===================================================================
--- /extensions/AMetaData/admin/amd_metadata.tpl	(revision 4905)
+++ /extensions/AMetaData/admin/amd_metadata.tpl	(revision 4905)
@@ -0,0 +1,8 @@
+{known_script id="jquery.ui" src=$ROOT_URL|@cat:"template-common/lib/ui/ui.core.packed.js"}
+{known_script id="jquery.ui" src=$ROOT_URL|@cat:"template-common/lib/ui/ui.core.packed.js"}
+{known_script id="jquery.ui.sortable" src=$ROOT_URL|@cat:"template-common/lib/ui/ui.sortable.packed.js"}
+{known_script id="jquery.ui.dialog" src=$ROOT_URL|@cat:"template-common/lib/ui/ui.dialog.packed.js"}
+
+{$statTabsheet}
+{$sheetContent}
+
Index: /extensions/AMetaData/admin/amd_metadata_display.tpl
===================================================================
--- /extensions/AMetaData/admin/amd_metadata_display.tpl	(revision 4905)
+++ /extensions/AMetaData/admin/amd_metadata_display.tpl	(revision 4905)
@@ -0,0 +1,375 @@
+
+
+{literal}
+<script type="text/javascript">
+
+  function init()
+  {
+    $("#iGroups")
+    .html(
+      $.ajax(
+        {
+          type: "POST",
+          url: "{/literal}{$datas.urlRequest}{literal}",
+          async: false,
+          data: { ajaxfct:"groupGetList" }
+        }
+      ).responseText
+    )
+    .sortable(
+      {
+        connectWith: '.connectedSortable',
+        cursor: 'move',
+        opacity:0.6,
+        items: 'li.groupItems',
+        axis:'y',
+        tolerance:'intersect',
+        start: function (event, ui)
+          {
+            manageGroup(event.originalTarget.id.substr(8), 'n');
+          },
+        update: function (event, ui)
+          {
+            list="";
+            $("#iGroups li").each(
+                function ()
+                {
+                  if(list!="") list+=";";
+                  list+=this.id.substr(8);
+                }
+              );
+            list=list.substr(0, list.lastIndexOf(';'));
+            $.ajax(
+              {
+                type: "POST",
+                url: "{/literal}{$datas.urlRequest}{literal}",
+                async: false,
+                data: { ajaxfct:"groupSetOrder", listGroup:list }
+              }
+            ).responseText;
+          }
+      }
+    );
+  }
+
+  function initSubList(groupId)
+  {
+    $("#iGroupId"+groupId+"_tags").sortable(
+      {
+        connectWith: '.g'+groupId+'_connectedSortableTags',
+        cursor: 'move',
+        opacity:0.6,
+        items: 'li',
+        axis:'y',
+        tolerance:'pointer',
+        containment: 'parent',
+        update: function (event, ui)
+          {
+            list="";
+            $("#iGroupId"+groupId+"_tags li").each(
+                function ()
+                {
+                  if(list!="") list+=";";
+                  list+=this.id.substr(this.id.indexOf('t')+1);
+                }
+              );
+            list=list.substr(0, list.lastIndexOf(';'));
+            $.ajax(
+              {
+                type: "POST",
+                url: "{/literal}{$datas.urlRequest}{literal}",
+                async: false,
+                data: { ajaxfct:"groupSetOrderedTagList", id:groupId, listTag:list }
+              }
+            ).responseText;
+          }
+
+      }
+    );
+  }
+
+  function loadGroupTags(groupId)
+  {
+    $("#iGroupId"+groupId+"_tags").html(
+      $.ajax(
+        {
+          type: "POST",
+          url: "{/literal}{$datas.urlRequest}{literal}",
+          async: false,
+          data: { ajaxfct:"groupGetOrderedTagList", id:groupId }
+        }
+      ).responseText
+    );
+  }
+
+  function manageGroup(groupId, force)
+  {
+    if(force=='y')
+    {
+      currentVisibility='hidden';
+    }
+    else if(force=='n')
+    {
+      currentVisibility='visible';
+    }
+    else
+    {
+      currentVisibility=$("#iGroupId"+groupId+"_content").css('visibility');
+    }
+
+
+    if(currentVisibility=='visible')
+    {
+      $("div[name=fGroupId"+groupId+"_content]").css(
+       {
+         visibility:"hidden",
+         height:"0px"
+       }
+      );
+    }
+    else
+    {
+      $("div[name=fGroupId"+groupId+"_content]").css(
+       {
+         visibility:"visible",
+         height:"auto"
+       }
+      );
+      loadGroupTags(groupId);
+    }
+  }
+
+  function deleteGroup(groupId)
+  {
+    if(groupId!="")
+    {
+      groupName=$("#iGroupName"+groupId).val();
+      $("#dialog")
+      .html("")
+      .dialog(
+        {
+          resizable: true,
+          width:480,
+          height:120,
+          modal: true,
+          draggable:true,
+          title: "{/literal}{'g003_deleting_a_group'|@translate}{literal}",
+          overlay:
+          {
+            backgroundColor: '#000',
+            opacity: 0.5
+          },
+          buttons:
+          {
+            '{/literal}{"g003_yes"|@translate}{literal}':
+              function()
+              {
+                $.ajax(
+                  {
+                    type: "POST",
+                    url: "{/literal}{$datas.urlRequest}{literal}",
+                    async: false,
+                    data: { ajaxfct:"groupDelete", id:groupId }
+                  }
+                ).responseText;
+                $("#iGroups").html(
+                  $.ajax(
+                    {
+                      type: "POST",
+                      url: "{/literal}{$datas.urlRequest}{literal}",
+                      async: false,
+                      data: { ajaxfct:"groupGetList" }
+                    }
+                  ).responseText
+                );
+                $(this).dialog('destroy').html("").get(0).removeAttribute('style');
+              },
+            '{/literal}{"g003_no"|@translate}{literal}':
+              function()
+              {
+                $(this).dialog('destroy').html("").get(0).removeAttribute('style');
+              }
+          }
+        }
+      )
+      .html("<div class='dialogForm'>{/literal}{'g003_confirm_group_delete'|@translate}{literal}</div>".replace("%s", "<i>"+groupName+"</i>", "gi"));
+    }
+  }
+
+  function editGroup(groupId)
+  {
+    if(groupId=="")
+    {
+      dialogTitle="{/literal}{'g003_adding_a_group'|@translate}{literal}";
+    }
+    else
+    {
+      dialogTitle="{/literal}{'g003_editing_a_group'|@translate}{literal}";
+    }
+
+    $("#dialog")
+    .html("")
+    .dialog(
+      {
+        resizable: true,
+        width:480,
+        height:120,
+        modal: true,
+        draggable:true,
+        title: dialogTitle,
+        overlay:
+        {
+          backgroundColor: '#000',
+          opacity: 0.5
+        },
+        buttons:
+        {
+          '{/literal}{"g003_ok"|@translate}{literal}':
+            function()
+            {
+              list="";
+              $("form.dialogForm input[type='hidden']").each(
+                function ()
+                {
+                  if(list!="") list+="\n";
+                  list+=this.id.substr(6)+"="+this.value;
+                }
+              )
+
+              $.ajax(
+                {
+                  type: "POST",
+                  url: "{/literal}{$datas.urlRequest}{literal}",
+                  async: false,
+                  data: { ajaxfct:"groupSetNames", id:groupId, listNames:list }
+                }
+              ).responseText;
+              $("#iGroups").html(
+                $.ajax(
+                  {
+                    type: "POST",
+                    url: "{/literal}{$datas.urlRequest}{literal}",
+                    async: false,
+                    data: { ajaxfct:"groupGetList" }
+                  }
+                ).responseText
+              );
+              $(this).dialog('destroy').html("").get(0).removeAttribute('style');
+            },
+          '{/literal}{"g003_cancel"|@translate}{literal}':
+            function()
+            {
+              $(this).dialog('destroy').html("").get(0).removeAttribute('style');
+            }
+        }
+      }
+    )
+    .html(
+      $.ajax(
+        {
+          type: "POST",
+          url: "{/literal}{$datas.urlRequest}{literal}",
+          async: false,
+          data: { ajaxfct:"groupGetNames", id:groupId }
+        }
+      ).responseText
+    );
+  }
+
+
+  function editGroupList(groupId)
+  {
+    $("#dialog")
+    .html("")
+    .dialog(
+      {
+        resizable: false,
+        width:480,
+        height:320,
+        modal: true,
+        draggable:true,
+        title: '{/literal}{"g003_add_delete_tags"|@translate}{literal}',
+        overlay:
+        {
+          backgroundColor: '#000',
+          opacity: 0.5
+        },
+        open: function(event, ui)
+        {
+          bH=$("div.ui-dialog-buttonpane").get(0).clientHeight;
+          $("#dialog").css('height', (this.clientHeight-bH)+"px");
+        },
+        buttons:
+        {
+          '{/literal}{"g003_ok"|@translate}{literal}':
+            function()
+            {
+              list="";
+              $("#dialog table input").each(
+                function ()
+                {
+                  if(this.checked)
+                  {
+                    if(list!="") list+=",";
+                    list+=this.id.substr(6);
+                  }
+                }
+              )
+
+              $.ajax(
+                {
+                  type: "POST",
+                  url: "{/literal}{$datas.urlRequest}{literal}",
+                  async: false,
+                  data: { ajaxfct:"groupSetTagList", id:groupId, listTag:list }
+                }
+              ).responseText;
+              $(this).dialog('destroy').html("").get(0).removeAttribute('style');
+              loadGroupTags(groupId);
+            },
+          '{/literal}{"g003_cancel"|@translate}{literal}':
+            function()
+            {
+              $(this).dialog('destroy').html("").get(0).removeAttribute('style');
+            }
+        }
+      }
+    )
+    .html(
+      $.ajax(
+        {
+          type: "POST",
+          url: "{/literal}{$datas.urlRequest}{literal}",
+          async: false,
+          data: { ajaxfct:"groupGetTagList", id:groupId }
+        }
+      ).responseText
+    );
+  }
+
+</script>
+{/literal}
+
+
+<h3>{'g003_display_management'|@translate}</h3>
+
+<div class="addGroup">
+  <a onclick="editGroup('');">{'g003_add_a_group'|@translate}</a>
+</div>
+
+
+<div id="dialog"></div>
+
+
+<div id="iGroupContainer">
+  <ul class="connectedSortable" id="iGroups">
+  </ul>
+</div>
+
+
+<script type="text/javascript">
+  init();
+  {foreach from=$datas.groups key=name item=data}
+  initSubList({$data.id});
+  {/foreach}
+</script>
Index: /extensions/AMetaData/admin/amd_metadata_display_groupEdit.tpl
===================================================================
--- /extensions/AMetaData/admin/amd_metadata_display_groupEdit.tpl	(revision 4905)
+++ /extensions/AMetaData/admin/amd_metadata_display_groupEdit.tpl	(revision 4905)
@@ -0,0 +1,36 @@
+{literal}
+<script type="text/javascript">
+  function change_lang()
+  {
+    selectedLang=$("#iLang").get(0).options[$("#iLang").get(0).selectedIndex].value;
+    $("#iEditGroupName").val($("#iName_"+selectedLang).val());
+  }
+
+  function apply_change()
+  {
+    selectedLang=$("#iLang").get(0).options[$("#iLang").get(0).selectedIndex].value;
+    $("#iName_"+selectedLang).val($("#iEditGroupName").val());
+  }
+</script>
+{/literal}
+
+
+<form class='dialogForm'>
+  <label>{'g003_name'|@translate}&nbsp;
+    <input type='text' id='iEditGroupName' onkeyup='apply_change();' value="{$datasLang.default}">
+  </label>&nbsp;
+
+    {if isset($datasLang.language_list) and count($datasLang.language_list)}
+      {foreach from=$datasLang.language_list key=name item=language_row}
+        <input type='hidden' id='iName_{$name}' value='{$language_row.name}'>
+      {/foreach}
+    {/if}
+
+    <select id='iLang' onchange='change_lang();'>
+    {if isset($datasLang.language_list) and count($datasLang.language_list)}
+      {foreach from=$datasLang.language_list key=name item=language_row}
+        <option value='{$name}' {if $datasLang.lang_selected==$name}selected{/if}>{$language_row.langName}</option>
+      {/foreach}
+    {/if}
+    </select>
+</form>
Index: /extensions/AMetaData/admin/amd_metadata_display_groupList.tpl
===================================================================
--- /extensions/AMetaData/admin/amd_metadata_display_groupList.tpl	(revision 4905)
+++ /extensions/AMetaData/admin/amd_metadata_display_groupList.tpl	(revision 4905)
@@ -0,0 +1,31 @@
+{foreach from=$datas.groups key=name item=data}
+  <li id="iGroupId{$data.id}" class="groupItems">
+    <img src="{$themeconf.admin_icon_dir}/cat_move.png" class="button drag_button" alt="{'Drag to re-order'|@translate}" title="{'Drag to re-order'|@translate}"/>
+    <input type="hidden" id="iGroupName{$data.id}" value="{$data.name}">
+    {$data.name}
+
+    <a onclick="deleteGroup('{$data.id}');">
+      <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/delete.png"  class="button drag_button" alt="{'g003_click_to_delete_group'|@translate}" title="{'g003_click_to_delete_group'|@translate}"
+            style="float:right;"/>
+    </a>
+
+    <a onclick="editGroup('{$data.id}');">
+      <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/category_edit.png"  class="button drag_button" alt="{'g003_click_to_edit_group'|@translate}" title="{'g003_click_to_edit_group'|@translate}"
+            style="float:right;"/>
+    </a>
+
+    <a onclick="manageGroup('{$data.id}', '');">
+      <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/preferences.png"  class="button drag_button" alt="{'g003_click_to_manage_group'|@translate}" title="{'g003_click_to_manage_group'|@translate}"
+            style="float:right;"/>
+    </a>
+
+
+    <div name="fGroupId{$data.id}_content" id="iGroupId{$data.id}_content" style="visibility:hidden;height:0px;" class="groupTags">
+      <a onclick="editGroupList('{$data.id}');" class="button editGroupListButton">
+      <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/edit_s.png"  class="button drag_button" alt="{'g003_click_to_manage_list'|@translate}" title="{'g003_click_to_manage_list'|@translate}"/>
+      </a>
+      <ul id="iGroupId{$data.id}_tags" class="tagListOrder g{$data.id}_connectedSortableTags">
+      </ul>
+    </div>
+  </li>
+{/foreach}
Index: /extensions/AMetaData/admin/amd_metadata_display_groupListTagOrder.tpl
===================================================================
--- /extensions/AMetaData/admin/amd_metadata_display_groupListTagOrder.tpl	(revision 4905)
+++ /extensions/AMetaData/admin/amd_metadata_display_groupListTagOrder.tpl	(revision 4905)
@@ -0,0 +1,14 @@
+{foreach from=$datas key=name item=data}
+<li id="g{$group}t{$data.numId}">
+  <table class="tagListOrderItem">
+    <tr>
+      <td style="width:20px;"><img src="{$themeconf.admin_icon_dir}/cat_move.png" class="button drag_button" alt="{'Drag to re-order'|@translate}" title="{'Drag to re-order'|@translate}"/></td>
+      <td style="width:30%;">{$data.tagId}</td>
+      <td>{$data.name}</td>
+      <td style="width:35px;text-align:right;">{$data.nbItems}</td>
+      <td style="width:50px;text-align:right;">{$data.pct}%</td>
+      <td style="width:104px;"><span class="pctBar" style="display:inline-block;width:{$data.pct}px;"></td>
+    </tr>
+  </table>
+</li>
+{/foreach}
Index: /extensions/AMetaData/admin/amd_metadata_display_groupListTagSelect.tpl
===================================================================
--- /extensions/AMetaData/admin/amd_metadata_display_groupListTagSelect.tpl	(revision 4905)
+++ /extensions/AMetaData/admin/amd_metadata_display_groupListTagSelect.tpl	(revision 4905)
@@ -0,0 +1,19 @@
+{literal}
+<script type="text/javascript">
+  function switchState(tagId)
+  {
+    $("#"+tagId).get(0).checked=!$("#"+tagId).get(0).checked;
+  }
+</script>
+{/literal}
+
+
+<table class="littlefont listTags" style="width:100%;">
+  {foreach from=$datas key=name item=data}
+  <tr>
+    <td width="30px"><input type="checkbox" id="iTagId{$data.numId}" {$data.state}></td>
+    <td onclick="switchState('iTagId{$data.numId}');">{$data.tagId}</td>
+    <td onclick="switchState('iTagId{$data.numId}');">{$data.name}</td>
+  </tr>
+  {/foreach}
+</table>
Index: /extensions/AMetaData/admin/amd_metadata_select.tpl
===================================================================
--- /extensions/AMetaData/admin/amd_metadata_select.tpl	(revision 4905)
+++ /extensions/AMetaData/admin/amd_metadata_select.tpl	(revision 4905)
@@ -0,0 +1,134 @@
+{literal}
+<script type="text/javascript">
+
+  var globalTagId;
+
+  function loadTagList()
+  {
+    $("body").css("cursor", "wait");
+    order=$('#iSelectOrderTagList').val();
+    filter=$("#iSelectFilterTagList").val();
+    unusedTag=($("#iExcludeUnusedTagList").get(0).checked)?"y":"n";
+    selectedOnly=($("#iSelectedTagOnly").get(0).checked)?"y":"n";
+
+    $("#iListTags").html(
+      $.ajax({
+        type: "POST",
+        url: "{/literal}{$datas.urlRequest}{literal}",
+        async: false,
+        data: { ajaxfct:"showStatsGetListTags", orderType:order, filterType:filter, excludeUnusedTag:unusedTag, selectedTagOnly:selectedOnly }
+       }).responseText
+    );
+    $("body").css("cursor", "default");
+  }
+
+  function loadTagDetail(tag)
+  {
+    globalTagId=tag;
+    order=$('#iSelectOrderImageList').val();
+    $("#iListImages").html("<br>{/literal}{'g003_loading'|@translate}{literal}");
+
+    $.ajax(
+      {
+        type: "POST",
+        url: "{/literal}{$datas.urlRequest}{literal}",
+        async: true,
+        data: { ajaxfct:"showStatsGetListImages", orderType:order, tagId:tag,  },
+        success:
+          function(msg)
+          {
+            $("#iListImages").html(msg);
+          }
+      }
+    );
+  }
+
+  function updateTagSelect(numId)
+  {
+    $("body").css("cursor", "wait");
+    selected=($("#"+numId).get(0).checked)?"y":"n";
+
+    $("#iListImages").html(
+      $.ajax({
+        type: "POST",
+        url: "{/literal}{$datas.urlRequest}{literal}",
+        async: false,
+        data: { ajaxfct:"updateTagSelect", tagSelected:selected, numId:numId.substr(6) }
+       }).responseText
+    );
+    $("body").css("cursor", "default");
+  }
+
+
+</script>
+{/literal}
+
+
+<h3>{'g003_select_metadata'|@translate}</h3>
+
+<form>
+  <label>{'g003_order'|@translate}
+    <select id="iSelectOrderTagList" onchange="loadTagList();">
+      <option value="tag" {if $datas.config_GetListTags_OrderType=="tag"}selected{/if}>{'g003_tagOrder'|@translate}</option>
+      <option value="num" {if $datas.config_GetListTags_OrderType=="num"}selected{/if}>{'g003_numOrder'|@translate}</option>
+    </select>
+  </label>
+
+  <label>{'g003_filter'|@translate}
+    <select id="iSelectFilterTagList" onchange="loadTagList();">
+      <option value="" {if $datas.config_GetListTags_FilterType==""}selected{/if}>{'g003_no_filter'|@translate}</option>
+      <option value="exif" {if $datas.config_GetListTags_FilterType=="exif"}selected{/if}>Exif</option>
+      <option value="xmp" {if $datas.config_GetListTags_FilterType=="xmp"}selected{/if}>Xmp</option>
+      <option value="iptc" {if $datas.config_GetListTags_FilterType=="iptc"}selected{/if}>Iptc</option>
+    </select>
+  </label>
+
+  <label>
+    <input type="checkbox" id="iExcludeUnusedTagList" onchange="loadTagList();"  {if $datas.config_GetListTags_ExcludeUnusedTag=="y"}checked{/if}>&nbsp;{'g003_exclude_unused_tags'|@translate}
+  </label>
+
+  <label>
+    <input type="checkbox" id="iSelectedTagOnly" onchange="loadTagList();" {if $datas.config_GetListTags_SelectedTagOnly=="y"}checked{/if}>&nbsp;{'g003_selected_tags_only'|@translate}
+  </label>
+
+</form>
+
+<table id='iHeaderListTags' class="littlefont">
+  <tr>
+    <th style="width:35%;min-width:340px;">{'g003_TagId'|@translate}</th>
+    <th>{'g003_TagLabel'|@translate}</th>
+    <th width="80px">{'g003_NumOfImage'|@translate}</th>
+    <th width="40px">{'g003_Pct'|@translate}</th>
+    <th width="110px">&nbsp;</th>
+  </tr>
+</table>
+<div id='iListTags'>
+</div>
+
+
+<form>
+  <label>{'g003_order'|@translate}
+    <select id="iSelectOrderImageList" onchange="loadTagDetail(globalTagId);">
+      <option value="value"  {if $datas.config_GetListImages_OrderType=="value"}selected{/if}>{'g003_valueOrder'|@translate}</option>
+      <option value="num"  {if $datas.config_GetListImages_OrderType=="num"}selected{/if}>{'g003_numOrder'|@translate}</option>
+    </select>
+  </label>
+</form>
+
+<table id='iHeaderListImages' class="littlefont">
+  <tr>
+    <th>{'g003_Value'|@translate}</th>
+    <th width="80px">{'g003_NumOfImage'|@translate}</th>
+    <th width="40px">{'g003_Pct'|@translate}</th>
+    <th width="110px">&nbsp;</th>
+  </tr>
+</table>
+
+<div id='iListImages'>
+  <div style="width:100%;text-align:center;padding-top:20px;">{'g003_no_items_selected'|@translate}</div>
+</div>
+
+
+<script type="text/javascript">
+  loadTagList();
+</script>
Index: /extensions/AMetaData/admin/amd_metadata_select_iListImages.tpl
===================================================================
--- /extensions/AMetaData/admin/amd_metadata_select_iListImages.tpl	(revision 4905)
+++ /extensions/AMetaData/admin/amd_metadata_select_iListImages.tpl	(revision 4905)
@@ -0,0 +1,13 @@
+<table class="littlefont">
+  {foreach from=$datas key=name item=data}
+  <tr>
+    <td>{$data.value}</td>
+    <td width="80px">{$data.nb}</td>
+    <td width="40px">{$data.pct}</td>
+    <td width="110px">
+      <div class="pctBar" style="width:{$data.pct}px;"></div>
+    </td>
+
+  </tr>
+  {/foreach}
+</table>
Index: /extensions/AMetaData/admin/amd_metadata_select_iListTags.tpl
===================================================================
--- /extensions/AMetaData/admin/amd_metadata_select_iListTags.tpl	(revision 4905)
+++ /extensions/AMetaData/admin/amd_metadata_select_iListTags.tpl	(revision 4905)
@@ -0,0 +1,13 @@
+<table class="littlefont">
+  {foreach from=$datas key=name item=data}
+  <tr onclick="loadTagDetail('{$data.tagId}');">
+    <td style="width:35%;min-width:340px;"><input type="checkbox" id="iNumId{$data.numId}" onclick="updateTagSelect('iNumId{$data.numId}')" {$data.tagChecked}>&nbsp;{$data.tagId}</td>
+    <td>{$data.label}</td>
+    <td width="80px">{$data.nb}</td>
+    <td width="40px">{$data.pct}</td>
+    <td width="110px">
+      <div class="pctBar" style="width:{$data.pct}px;"></div>
+    </td>
+  </tr>
+  {/foreach}
+</table>
Index: /extensions/AMetaData/admin/amd_stat_status.tpl
===================================================================
--- /extensions/AMetaData/admin/amd_stat_status.tpl	(revision 4905)
+++ /extensions/AMetaData/admin/amd_stat_status.tpl	(revision 4905)
@@ -0,0 +1,132 @@
+{literal}
+<script type="text/javascript">
+
+  function getStatus()
+  {
+    $.get("{/literal}{$datas.urlRequest}{literal}", { ajaxfct:"makeStatsGetStatus" },
+      function (data)
+      {
+        list=data.split(";");
+        $("#ianalyzestatus").html("<ul><li>"+list[0]+"</li><li>"+list[1]+"</li><li>"+list[2]+"</li></ul>");
+      }
+    );
+  }
+
+  function doAnalyze()
+  {
+    $("body").css("cursor", "wait");
+
+    mode="all";
+    modeLabel="{/literal}{'g003_analyze_all_pictures'|@translate}{literal}";
+    if($("#ianalyze_action0").get(0).checked)
+    {
+      mode="notAnalyzed";
+      modeLabel="{/literal}{'g003_analyze_not_analyzed_pictures'|@translate}{literal}";
+    }
+
+    doAnalyze="<fieldset><legend>{/literal}{'g003_updating_metadata'|@translate}{literal}&nbsp;("+modeLabel+")</legend>"+
+      "<form class='formtable'>"+
+      "<div id='iprogressbar_contener'>"+
+      "<span id='iprogressbar_bg' style='width:0%;'>&nbsp;</span>"+
+      "<span id='iprogressbar_fg'>0%</span>"+
+      "</div><div id='iprogress'>{/literal}{'g003_analyze_in_progress'|@translate}{literal}</div></form></fieldset>";
+
+    $("#ianalyzearea").html(doAnalyze);
+
+    $.get("{/literal}{$datas.urlRequest}{literal}", { ajaxfct:"makeStatsGetList", selectMode:mode }, doStep_getList);
+  }
+
+
+  function displayTime(eTime)
+  {
+    seconds=(eTime%60).toFixed(2);
+    minutes=((eTime-seconds)/60).toFixed(0);
+    returned=seconds+"s";
+    if(minutes>0) returned=minutes+"m"+returned;
+    return(returned);
+  }
+
+  function doStep_getList(data)
+  {
+    timeStart = new Date();
+    list=data.split(";");
+    for(i=0;i<list.length-1;i++)
+    {
+      tmp = $.ajax({
+        type: "POST",
+        url: "{/literal}{$datas.urlRequest}{literal}",
+        async: false,
+        data: { ajaxfct:"makeStatsDoAnalyze", imagesList:list[i] }
+       }).responseText;
+
+      pct=100*(i+1)/(list.length+2);
+      $("#iprogressbar_bg").css("width", pct+"%");
+      $("#iprogressbar_fg").html(Math.round(pct)+"%");
+    }
+
+    for(j=0;j<3;j++)
+    {
+      tmp = $.ajax({
+        type: "POST",
+        url: "{/literal}{$datas.urlRequest}{literal}",
+        async: false,
+        data: { ajaxfct:"makeStatsConsolidate", step:j }
+       }).responseText;
+
+      pct=100*(i+j+1)/(list.length+2);
+      $("#iprogressbar_bg").css("width", pct+"%");
+      $("#iprogressbar_fg").html(Math.round(pct)+"%");
+    }
+
+    timeEnd = new Date();
+    timeElapsed=timeEnd.getTime()-timeStart.getTime();
+    $("#iprogress").html("{/literal}{'g003_analyze_is_finished'|@translate}{literal}&nbsp;("+displayTime(timeElapsed/1000)+")");
+    getStatus();
+    $("body").css("cursor", "default");
+  }
+
+
+</script>
+{/literal}
+
+
+<h3>{'g003_status_of_database'|@translate}</h3>
+
+<div id="ianalyzestatus">
+  <ul>
+    <li>{'g003_loading'|@translate}</li>
+    <li>{'g003_loading'|@translate}</li>
+    <li>{'g003_loading'|@translate}</li>
+  </ul>
+</div>
+
+<div id='ianalyzearea'>
+  <fieldset>
+    <legend>{'g003_update_metadata'|@translate}</legend>
+      <form class="formtable">
+        <label>
+          <input type="radio" value="notAnalayzed" name="fAMD_analyze_action" id="ianalyze_action0" checked>&nbsp;
+          {'g003_analyze_not_analyzed_pictures'|@translate}
+        </label><br>
+        <label>
+          <input type="radio" value="all" name="fAMD_analyze_action" id="ianalyze_action1">&nbsp;
+          {'g003_analyze_all_pictures'|@translate}
+        </label><br>
+        <div class="warning">
+          <p style="font-weight:bold; font-size:+1;">{'g003_warning_on_analyze_0'|@translate}</p>
+          <p>{'g003_warning_on_analyze_1'|@translate}</p>
+          <ul>
+            <li>{'g003_warning_on_analyze_2'|@translate}</li>
+            <li>{'g003_warning_on_analyze_3'|@translate}</li>
+          </ul>
+          <p  style="font-weight:bold;">{'g003_warning_on_analyze_4'|@translate}</p>
+          <p>{'g003_warning_on_analyze_5'|@translate}</p>
+        </div>
+        <input type="button" value="{'g003_analyze'|@translate}" onclick="doAnalyze();">
+      </form>
+  </fieldset>
+</div>
+
+<script type="text/javascript">
+  getStatus();
+</script>
Index: /extensions/AMetaData/admin/index.php
===================================================================
--- /extensions/AMetaData/admin/index.php	(revision 4905)
+++ /extensions/AMetaData/admin/index.php	(revision 4905)
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file          : $Id: index.php 1912 2007-03-16 06:30:07Z rub $
+// | last update   : $Date: 2007-03-16 07:30:07 +0100 (ven, 16 mar 2007) $
+// | last modifier : $Author: rub $
+// | revision      : $Revision: 1912 $
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/AMetaData/admin/plugin_admin.php
===================================================================
--- /extensions/AMetaData/admin/plugin_admin.php	(revision 4905)
+++ /extensions/AMetaData/admin/plugin_admin.php	(revision 4905)
@@ -0,0 +1,33 @@
+<?php
+/*
+ * -----------------------------------------------------------------------------
+ * Plugin Name: Advanced MetaData
+ * -----------------------------------------------------------------------------
+ * Author     : Grum
+ *   email    : grum@piwigo.org
+ *   website  : http://photos.grum.fr
+ *   PWG user : http://forum.piwigo.org/profile.php?id=3706
+ *
+ *   << May the Little SpaceFrog be with you ! >>
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * See main.inc.php for release information
+ *
+ * -----------------------------------------------------------------------------
+*/
+
+if (!defined('PHPWG_ROOT_PATH')) { die('Hacking attempt!'); }
+
+include(AMD_PATH."amd_aip.class.inc.php");
+
+global $prefixeTable;
+
+load_language('plugin.lang', AMD_PATH);
+
+$main_plugin_object = get_plugin_data($plugin_id);
+
+$plugin_ai = new AMD_AIP($prefixeTable, $main_plugin_object->get_filelocation());
+$plugin_ai->manage();
+
+?>
Index: /extensions/AMetaData/amd_aim.class.inc.php
===================================================================
--- /extensions/AMetaData/amd_aim.class.inc.php	(revision 4905)
+++ /extensions/AMetaData/amd_aim.class.inc.php	(revision 4905)
@@ -0,0 +1,45 @@
+<?php
+/*
+ * -----------------------------------------------------------------------------
+ * Plugin Name: Advanced MetaData
+ * -----------------------------------------------------------------------------
+ * Author     : Grum
+ *   email    : grum@piwigo.org
+ *   website  : http://photos.grum.fr
+ *   PWG user : http://forum.piwigo.org/profile.php?id=3706
+ *
+ *   << May the Little SpaceFrog be with you ! >>
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * See main.inc.php for release information
+ *
+ * AMD_AIM : classe to manage plugin integration into plugin menu
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+if (!defined('PHPWG_ROOT_PATH')) { die('Hacking attempt!'); }
+
+include_once('amd_root.class.inc.php');
+
+class AMD_AIM extends AMD_root
+{
+  function AMD_AIM($prefixeTable, $filelocation)
+  {
+    parent::__construct($prefixeTable, $filelocation);
+  }
+
+  /*
+    initialize events call for the plugin
+  */
+  function init_events()
+  {
+    parent::init_events();
+    add_event_handler('get_admin_plugin_menu_links', array(&$this, 'plugin_admin_menu') );
+  }
+
+} // amd_aim  class
+
+
+?>
Index: /extensions/AMetaData/amd_aip.class.inc.php
===================================================================
--- /extensions/AMetaData/amd_aip.class.inc.php	(revision 4905)
+++ /extensions/AMetaData/amd_aip.class.inc.php	(revision 4905)
@@ -0,0 +1,1572 @@
+<?php
+/*
+ * -----------------------------------------------------------------------------
+ * Plugin Name: Advanced MetaData
+ * -----------------------------------------------------------------------------
+ * Author     : Grum
+ *   email    : grum@piwigo.org
+ *   website  : http://photos.grum.fr
+ *   PWG user : http://forum.piwigo.org/profile.php?id=3706
+ *
+ *   << May the Little SpaceFrog be with you ! >>
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * See main.inc.php for release information
+ *
+ * AIP classe => manage integration in administration interface
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+if (!defined('PHPWG_ROOT_PATH')) { die('Hacking attempt!'); }
+
+include_once('amd_root.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');
+include_once(PHPWG_PLUGINS_PATH.'grum_plugins_classes-2/genericjs.class.inc.php');
+
+
+
+class AMD_AIP extends AMD_root
+{
+  protected $tabsheet;
+  protected $ajax;
+  protected $jpegMD;
+
+  /**
+   *
+   * constructor needs the prefix of piwigo's tables and the location of plugin
+   *
+   * @param String $prefixeTable
+   * @param String $filelocation
+   */
+  function __construct($prefixeTable, $filelocation)
+  {
+    parent::__construct($prefixeTable, $filelocation);
+
+    $this->load_config();
+    $this->init_events();
+
+    $this->tabsheet = new tabsheet();
+    $this->tabsheet->add('metadata',
+                          l10n('g003_metadata'),
+                          $this->page_link.'&amp;fAMD_tabsheet=metadata');
+    $this->tabsheet->add('database',
+                          l10n('g003_database'),
+                          $this->page_link.'&amp;fAMD_tabsheet=database');
+    $this->ajax = new Ajax();
+    $this->jpegMD=new JpegMetaData();
+  }
+
+  function __destruct()
+  {
+    unset($this->tabsheet);
+    unset($this->ajax);
+    unset($this->jpegMD);
+  }
+
+
+  /*
+   * ---------------------------------------------------------------------------
+   * Public classe functions
+   * ---------------------------------------------------------------------------
+   */
+
+
+  /**
+   * manage the plugin integration into piwigo's admin interface
+   */
+  public function manage()
+  {
+    global $template, $page;
+
+    $template->set_filename('plugin_admin_content', dirname(__FILE__)."/admin/amd_admin.tpl");
+
+    $this->initRequest();
+
+    $this->returnAjaxContent();
+
+    $this->tabsheet->select($_REQUEST['fAMD_tabsheet']);
+    $this->tabsheet->assign();
+    $selected_tab=$this->tabsheet->get_selected();
+    $template->assign($this->tabsheet->get_titlename(), "[".$selected_tab['caption']."]");
+
+    $template_plugin["AMD_VERSION"] = "<i>".$this->plugin_name."</i> ".l10n('g003_version').AMD_VERSION;
+    $template_plugin["AMD_PAGE"] = $_REQUEST['fAMD_tabsheet'];
+    $template_plugin["PATH"] = AMD_PATH;
+
+    $template->assign('plugin', $template_plugin);
+
+    if($_REQUEST['fAMD_tabsheet']=='database')
+    {
+      $this->displayDatabase();
+    }
+    elseif($_REQUEST['fAMD_tabsheet']=='metadata')
+    {
+      $this->displayMetaData($_REQUEST['fAMD_page']);
+    }
+
+    $template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content');
+  }
+
+  /**
+   * initialize events call for the plugin
+   */
+  public function init_events()
+  {
+    add_event_handler('loc_end_page_header', array(&$this->css, 'apply_CSS'));
+  }
+
+  /**
+   * ---------------------------------------------------------------------------
+   * Private & protected functions
+   * ---------------------------------------------------------------------------
+   */
+
+  /**
+   * manage the ajax requests
+   * this function function determine if there is an ajax call, manage the
+   * request and returns the content of the request
+   *
+   * no params are given, the function works with the "$_REQUEST" var
+   *
+   * @return String
+   */
+  protected function returnAjaxContent()
+  {
+    global $ajax, $template;
+
+    if(isset($_REQUEST['ajaxfct']))
+    {
+      //$this->debug("AJAXFCT:".$_REQUEST['ajaxfct']);
+      $result="<p class='errors'>".l10n('g002_error_invalid_ajax_call')."</p>";
+      switch($_REQUEST['ajaxfct'])
+      {
+        case 'makeStatsGetList':
+          $result=$this->ajax_amd_makeStatsGetList($_REQUEST['selectMode'], $_REQUEST['numOfItems']);
+          break;
+        case 'makeStatsDoAnalyze':
+          $result=$this->ajax_amd_makeStatsDoAnalyze($_REQUEST['imagesList']);
+          break;
+        case 'makeStatsConsolidate':
+          $result=$this->ajax_amd_makeStatsConsolidate($_REQUEST['step']);
+          break;
+        case 'makeStatsGetStatus':
+          $result=$this->ajax_amd_makeStatsGetStatus();
+          break;
+        case 'showStatsGetListTags':
+          $result=$this->ajax_amd_showStatsGetListTags($_REQUEST['orderType'], $_REQUEST['filterType'], $_REQUEST['excludeUnusedTag'], $_REQUEST['selectedTagOnly']);
+          break;
+        case 'showStatsGetListImages':
+          $result=$this->ajax_amd_showStatsGetListImages($_REQUEST['tagId'], $_REQUEST['orderType']);
+          break;
+        case 'updateTagSelect':
+          $result=$this->ajax_amd_updateTagSelect($_REQUEST['numId'], $_REQUEST['tagSelected']);
+          break;
+        case 'groupGetList':
+          $result=$this->ajax_amd_groupGetList();
+          break;
+        case 'groupDelete':
+          $result=$this->ajax_amd_groupDelete($_REQUEST['id']);
+          break;
+        case 'groupGetNames':
+          $result=$this->ajax_amd_groupGetNames($_REQUEST['id']);
+          break;
+        case 'groupSetNames':
+          $result=$this->ajax_amd_groupSetNames($_REQUEST['id'], $_REQUEST['listNames']);
+          break;
+        case 'groupSetOrder':
+          $result=$this->ajax_amd_groupSetOrder($_REQUEST['listGroup']);
+          break;
+        case 'groupGetTagList':
+          $result=$this->ajax_amd_groupGetTagList($_REQUEST['id']);
+          break;
+        case 'groupSetTagList':
+          $result=$this->ajax_amd_groupSetTagList($_REQUEST['id'], $_REQUEST['listTag']);
+          break;
+        case 'groupGetOrderedTagList':
+          $result=$this->ajax_amd_groupGetOrderedTagList($_REQUEST['id']);
+          break;
+        case 'groupSetOrderedTagList':
+          $result=$this->ajax_amd_groupSetOrderedTagList($_REQUEST['id'], $_REQUEST['listTag']);
+          break;
+      }
+      $this->ajax->return_result($result);
+    }
+  }
+
+
+  /**
+   * if empty, initialize the $_REQUEST var
+   *
+   * if not empty, check validity for the request values
+   *
+   */
+  private function initRequest()
+  {
+    //initialise $REQUEST values if not defined
+    if($this->getNumOfPictures()==0)
+    {
+      $defautTabsheet="database";
+    }
+    else
+    {
+      $defautTabsheet="metadata";
+    }
+
+    if(!isset($_REQUEST['fAMD_tabsheet']))
+    {
+      $_REQUEST['fAMD_tabsheet']=$defautTabsheet;
+    }
+
+    if($_REQUEST['fAMD_tabsheet']!="metadata" and
+       $_REQUEST['fAMD_tabsheet']!="database")
+    {
+      $_REQUEST['fAMD_tabsheet']=$defautTabsheet;
+    }
+
+    if($_REQUEST['fAMD_tabsheet']=="metadata" and !isset($_REQUEST['fAMD_page']))
+    {
+      $_REQUEST['fAMD_page']="select";
+    }
+
+    if($_REQUEST['fAMD_tabsheet']=="metadata" and
+       !($_REQUEST['fAMD_page']=="select" or
+         $_REQUEST['fAMD_page']=="display"))
+    {
+      $_REQUEST['fAMD_page']="select";
+    }
+
+    /*
+     * check ajax
+     */
+    if(isset($_REQUEST['ajaxfct']))
+    {
+      /*
+       * check makeStatsGetList values
+       */
+      if($_REQUEST['ajaxfct']=="makeStatsGetList" and !isset($_REQUEST['selectMode']))
+      {
+        $_REQUEST['selectMode']="notAnalyzed";
+      }
+
+      if($_REQUEST['ajaxfct']=="makeStatsGetList" and
+         !($_REQUEST['selectMode']=="notAnalyzed" or
+           $_REQUEST['selectMode']=="all"))
+      {
+        $_REQUEST['selectMode']="notAnalyzed";
+      }
+
+      if($_REQUEST['ajaxfct']=="makeStatsGetList" and !isset($_REQUEST['numOfItems']))
+      {
+        $_REQUEST['numOfItems']=25;
+      }
+
+      /*
+       * check makeStatsDoAnalyze values
+       */
+      if($_REQUEST['ajaxfct']=="makeStatsDoAnalyze" and !isset($_REQUEST['imagesList']))
+      {
+        $_REQUEST['imagesList']="";
+      }
+
+      /*
+       * check makeStatsConsolidate values
+       */
+      if($_REQUEST['ajaxfct']=="makeStatsConsolidate" and !isset($_REQUEST['step']))
+      {
+        $_REQUEST['step']="*";
+      }
+
+      /*
+       * check showStatsGetListTags values
+       */
+      if($_REQUEST['ajaxfct']=="showStatsGetListTags" and !isset($_REQUEST['orderType']))
+      {
+        $_REQUEST['orderType']="tag";
+      }
+
+      if($_REQUEST['ajaxfct']=="showStatsGetListTags" and
+         !($_REQUEST['orderType']=="tag" or
+           $_REQUEST['orderType']=="num"))
+      {
+        $_REQUEST['orderType']="tag";
+      }
+
+      if($_REQUEST['ajaxfct']=="showStatsGetListTags" and !isset($_REQUEST['filterType']))
+      {
+        $_REQUEST['filterType']="";
+      }
+
+      if($_REQUEST['ajaxfct']=="showStatsGetListTags" and
+         !($_REQUEST['filterType']=="" or
+           $_REQUEST['filterType']=="exif" or
+           $_REQUEST['filterType']=="xmp" or
+           $_REQUEST['filterType']=="iptc"))
+      {
+        $_REQUEST['filterType']="";
+      }
+
+      if($_REQUEST['ajaxfct']=="showStatsGetListTags" and !isset($_REQUEST['excludeUnusedTag']))
+      {
+        $_REQUEST['excludeUnusedTag']="n";
+      }
+
+      if($_REQUEST['ajaxfct']=="showStatsGetListTags" and
+         !($_REQUEST['excludeUnusedTag']=="y" or
+           $_REQUEST['excludeUnusedTag']=="n" ))
+      {
+        $_REQUEST['excludeUnusedTag']="n";
+      }
+
+      if($_REQUEST['ajaxfct']=="showStatsGetListTags" and !isset($_REQUEST['selectedTagOnly']))
+      {
+        $_REQUEST['selectedTagOnly']="n";
+      }
+
+      if($_REQUEST['ajaxfct']=="showStatsGetListTags" and
+         !($_REQUEST['selectedTagOnly']=="y" or
+           $_REQUEST['selectedTagOnly']=="n" ))
+      {
+        $_REQUEST['selectedTagOnly']="n";
+      }
+
+
+      /*
+       * check showStatsGetListImagess values
+       */
+      if($_REQUEST['ajaxfct']=="showStatsGetListImages" and !isset($_REQUEST['orderType']))
+      {
+        $_REQUEST['orderType']="num";
+      }
+
+      if($_REQUEST['ajaxfct']=="showStatsGetListImages" and
+         !($_REQUEST['orderType']=="value" or
+           $_REQUEST['orderType']=="num"))
+      {
+        $_REQUEST['orderType']="num";
+      }
+
+      if($_REQUEST['ajaxfct']=="showStatsGetListImages" and !isset($_REQUEST['tagId']))
+      {
+        $_REQUEST['tagId']="*";
+      }
+
+
+      /*
+       * check showStatsGetListImagess values
+       */
+      if($_REQUEST['ajaxfct']=="updateTagSelect" and !isset($_REQUEST['numId']))
+      {
+        $_REQUEST['numId']="";
+      }
+
+      if($_REQUEST['ajaxfct']=="updateTagSelect" and !isset($_REQUEST['tagSelected']))
+      {
+        $_REQUEST['tagSelected']="";
+      }
+
+
+
+
+      /*
+       * check groupDelete values
+       */
+      if($_REQUEST['ajaxfct']=="groupDelete" and !isset($_REQUEST['id']))
+      {
+        $_REQUEST['id']="";
+      }
+
+
+
+      /*
+       * check groupSetOrder values
+       */
+      if($_REQUEST['ajaxfct']=="groupSetOrder" and !isset($_REQUEST['listGroup']))
+      {
+        $_REQUEST['listGroup']="";
+      }
+
+      /*
+       * check groupGetNames values
+       */
+      if($_REQUEST['ajaxfct']=="groupGetNames" and !isset($_REQUEST['id']))
+      {
+        $_REQUEST['id']="";
+      }
+
+      /*
+       * check groupSetNames values
+       */
+      if($_REQUEST['ajaxfct']=="groupSetNames" and !isset($_REQUEST['listNames']))
+      {
+        $_REQUEST['listNames']="";
+      }
+
+      if($_REQUEST['ajaxfct']=="groupSetNames" and !isset($_REQUEST['id']))
+      {
+        $_REQUEST['id']="";
+      }
+
+
+      /*
+       * check groupGetTagList values
+       */
+      if($_REQUEST['ajaxfct']=="groupGetTagList" and !isset($_REQUEST['id']))
+      {
+        $_REQUEST['id']="";
+      }
+
+      /*
+       * check groupSetTagList values
+       */
+      if($_REQUEST['ajaxfct']=="groupSetTagList" and !isset($_REQUEST['id']))
+      {
+        $_REQUEST['id']="";
+      }
+
+      if($_REQUEST['ajaxfct']=="groupSetTagList" and !isset($_REQUEST['listTag']))
+      {
+        $_REQUEST['listTag']="";
+      }
+
+
+      /*
+       * check groupGetOrderedTagList values
+       */
+      if($_REQUEST['ajaxfct']=="groupGetOrderedTagList" and !isset($_REQUEST['id']))
+      {
+        $_REQUEST['id']="";
+      }
+
+      /*
+       * check groupSetOrderedTagList values
+       */
+      if($_REQUEST['ajaxfct']=="groupSetOrderedTagList" and !isset($_REQUEST['id']))
+      {
+        $_REQUEST['id']="";
+      }
+
+      if($_REQUEST['ajaxfct']=="groupSetOrderedTagList" and !isset($_REQUEST['listTag']))
+      {
+        $_REQUEST['listTag']="";
+      }
+
+    }
+  } //init_request
+
+
+  /**
+   * manage adviser profile
+   *
+   * @return Boolean : true if user is adviser, otherwise false (and push a
+   *                   message in the error list)
+   */
+  protected function adviser_abort()
+  {
+    if(is_adviser())
+    {
+      $this->display_result(l10n("g003_adviser_not_allowed"), false);
+      return(true);
+    }
+    return(false);
+  }
+
+
+  /**
+   * display and manage the database page
+   */
+  private function displayDatabase()
+  {
+    global $template, $page;
+
+    $template->set_filename('body_page', dirname(__FILE__).'/admin/amd_database.tpl');
+
+    $datas=array(
+      'urlRequest' => $this->page_link,
+      'NumberOfItemsPerRequest' => $this->my_config['amd_NumberOfItemsPerRequest'],
+    );
+
+    $template->assign("datas", $datas);
+
+    $template->assign_var_from_handle('AMD_BODY_PAGE', 'body_page');
+  } // display_config
+
+
+  /**
+   * display and manage the status page on the stat page
+   *
+   * the function automatically update the AMD tables :
+   *  - add new pictures in the AMD image table (assuming image is not analyzed
+   *    yet)
+   *  - remove deleted pictures in the AMD image & image_tags table
+   *
+   * @return String : the content of the page
+   */
+  protected function displayStatStatus()
+  {
+    $local_tpl = new Template(AMD_PATH."admin/", "");
+    $local_tpl->set_filename('body_page',
+                  dirname($this->filelocation).'/admin/amd_stat_status.tpl');
+
+    /*
+     * insert new image (from piwigo images table) in the AMD images table, with
+     * statut 'not analyzed'
+     */
+    $sql="INSERT INTO ".$this->tables['images']."
+            SELECT id, 'n', 0
+              FROM ".IMAGES_TABLE."
+              WHERE id NOT IN (SELECT imageId FROM ".$this->tables['images'].")";
+    pwg_query($sql);
+
+
+    /*
+     * delete image who are in the AMD images table and not in the piwigo image
+     * table
+     */
+    $sql="DELETE FROM ".$this->tables['images']."
+            WHERE imageId NOT IN (SELECT id FROM ".IMAGES_TABLE.")";
+    pwg_query($sql);
+
+
+    /*
+     * delete metdata for images that are not in the AMD image table
+     */
+    $sql="DELETE FROM ".$this->tables['images_tags']."
+            WHERE imageId NOT IN (SELECT imageId FROM ".$this->tables['images'].")";
+    pwg_query($sql);
+
+    $datas=array(
+      'urlRequest' => $this->page_link,
+    );
+
+    $local_tpl->assign('datas', $datas);
+
+    return($local_tpl->parse('body_page', true));
+  }
+
+
+  /**
+   * display and manage the metadata page
+   * the page have two tabsheet :
+   *  - select tag management, to manage tags to be selected on the galerie
+   *  - display tag management, to choose how the tags are displayed
+   *
+   * @param String $tab : the selected tab on the stat page
+   */
+  protected function displayMetaData($tab)
+  {
+    global $template, $user;
+    $template->set_filename('body_page', dirname(__FILE__).'/admin/amd_metadata.tpl');
+
+    $statTabsheet = new tabsheet('statTabsheet', $this->tabsheet->get_titlename());
+    $statTabsheet->select($tab);
+    $statTabsheet->add('select',
+                          l10n('g003_select'),
+                          $this->page_link.'&amp;fAMD_tabsheet=stat&amp;fAMD_page=select');
+    $statTabsheet->add('display',
+                          l10n('g003_display'),
+                          $this->page_link.'&amp;fAMD_tabsheet=stat&amp;fAMD_page=display');
+    $statTabsheet->assign();
+
+
+
+    if($tab=="select")
+    {
+      $template->assign('sheetContent', $this->displayMetaDataSelect());
+    }
+    else
+    {
+      $template->assign('sheetContent', $this->displayMetaDataDisplay());
+    }
+
+    $template->assign_var_from_handle('AMD_BODY_PAGE', 'body_page');
+  }
+
+  /**
+   * display and manage the metadata page allowing to make tags selection
+   *
+   * @return String : the content of the page
+   */
+  protected function displayMetaDataSelect()
+  {
+    global $template;
+
+    $template->set_filename('sheet_page',
+                  dirname($this->filelocation).'/admin/amd_metadata_select.tpl');
+
+    $datas=array(
+      'urlRequest' => $this->page_link,
+      'config_GetListTags_OrderType' => $this->my_config['amd_GetListTags_OrderType'],
+      'config_GetListTags_FilterType' => $this->my_config['amd_GetListTags_FilterType'],
+      'config_GetListTags_ExcludeUnusedTag' => $this->my_config['amd_GetListTags_ExcludeUnusedTag'],
+      'config_GetListTags_SelectedTagOnly' => $this->my_config['amd_GetListTags_SelectedTagOnly'],
+      'config_GetListImages_OrderType' => $this->my_config['amd_GetListImages_OrderType']
+    );
+
+
+    $template->assign('datas', $datas);
+
+    return($template->parse('sheet_page', true));
+  }
+
+
+  /**
+   * display and manage the metadata page allowing to choose tags order
+   *
+   * @return String : the content of the page
+   */
+  protected function displayMetaDataDisplay()
+  {
+    global $user, $template;
+
+    //$local_tpl = new Template(AMD_PATH."admin/", "");
+    $template->set_filename('sheet_page',
+                  dirname($this->filelocation).'/admin/amd_metadata_display.tpl');
+
+
+    $datas=array(
+      'urlRequest' => $this->page_link,
+      'selectedTags' => Array(),
+      'groups' => Array(),
+      'tagByGroup' => Array(),
+    );
+
+    $sql="SELECT st.tagId, st.order, st.groupId, ut.numId
+          FROM ".$this->tables['selected_tags']." st
+            LEFT JOIN ".$this->tables['used_tags']." ut
+              ON ut.tagId = st.tagId
+          ORDER BY st.groupId ASC, st.order ASC, st.tagId ASC";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_assoc($result))
+      {
+        if($row['groupId']==-1)
+        {
+          $datas['selectedTags'][]=Array(
+            'numId' => $row['numId'],
+            'tagId' => $row['tagId']
+          );
+        }
+        else
+        {
+          $datas['tagByGroup'][]=Array(
+            'numId' => $row['numId'],
+            'tagId' => $row['tagId'],
+            'group' => $row['groupId'],
+            'order' => $row['order']
+          );
+        }
+      }
+    }
+
+    $sql="SELECT g.groupId, gn.name
+          FROM ".$this->tables['groups']." g
+            LEFT JOIN ".$this->tables['groups_names']." gn
+              ON g.groupId = gn.groupId
+          WHERE gn.lang = '".$user['language']."'
+          ORDER BY g.order;";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_assoc($result))
+      {
+        $datas['groups'][]=Array(
+          'id' => $row['groupId'],
+          'name' => $row['name']
+        );
+      }
+    }
+
+    $template->assign('datas', $datas);
+    return($template->parse('sheet_page', true));
+  }
+
+
+
+  /**
+   * this function analyze tags from a picture, and insert the result into the
+   * database
+   *
+   * NOTE : only implemented tags are analyzed and stored
+   *
+   * @param String $fileName : filename of picture to analyze
+   * @param Integer $imageId : id of image in piwigo's database
+   */
+  protected function analyzeImageFile($fileName, $imageId)
+  {
+    /*
+     * the JpegMetaData object is instancied in the constructor
+     */
+    $this->jpegMD->load($fileName, Array(
+      'filter' => JpegMetaData::TAGFILTER_IMPLEMENTED,
+      'optimizeIptcDateTime' => true)
+    );
+
+    $sqlInsert="";
+    $massInsert=array();
+    $nbTags=0;
+    foreach($this->jpegMD->getTags() as $key => $val)
+    {
+      $value=$val->getLabel();
+
+      if($val->isTranslatable())
+        $translatable="y";
+      else
+        $translatable="n";
+
+      if($value instanceof DateTime)
+      {
+        $value=$value->format("Y-m-d H:i:s");
+      }
+      elseif(is_array($value))
+      {
+        /*
+         * array values are stored in a serialized string
+         */
+        $value=serialize($value);
+      }
+
+      $sql="SELECT numId FROM ".$this->tables['used_tags']." WHERE tagId = '$key'";
+      $result=pwg_query($sql);
+      if($result)
+      {
+        $numId=-1;
+        while($row=mysql_fetch_assoc($result))
+        {
+          $numId=$row['numId'];
+        }
+
+        if($numId>0)
+        {
+          $nbTags++;
+          if($sqlInsert!="") $sqlInsert.=", ";
+          $sqlInsert.="($imageId, '$numId', '".addslashes($value)."')";
+          $massInsert[]=array(
+            'imageId' => $imageId,
+            'numId' => $numId,
+            'value' => addslashes($value)
+          );
+
+          $sql="UPDATE ".$this->tables['used_tags']."
+                  SET numOfImg = numOfImg+1
+                  WHERE numId=$numId;";
+          pwg_query($sql);
+        }
+      }
+    }
+
+    /*if($sqlInsert!="")
+    {
+      $sqlInsert="INSERT INTO ".$this->tables['images_tags']." VALUES ".$sqlInsert;
+      pwg_query($sqlInsert);
+    }*/
+    mass_inserts($this->tables['images_tags'], array('imageId', 'numId', 'value'), $massInsert);
+
+    $sql="UPDATE ".$this->tables['images']."
+            SET analyzed = 'y', nbTags=".$nbTags."
+            WHERE imageId=$imageId;";
+    pwg_query($sql);
+
+
+    return("$imageId=$nbTags;");
+  }
+
+
+  /**
+   * returns the number of pictures analyzed
+   *
+   * @return Integer
+   */
+  protected function getNumOfPictures()
+  {
+    $numOfPictures=0;
+    $sql="SELECT COUNT(imageId) FROM ".$this->tables['images']."
+            WHERE analyzed='y';";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_row($result))
+      {
+        $numOfPictures=$row[0];
+      }
+    }
+    return($numOfPictures);
+  }
+
+
+  /*
+   * ---------------------------------------------------------------------------
+   * ajax functions
+   * ---------------------------------------------------------------------------
+   */
+
+  /**
+   * return a list of picture Id
+   *
+   * picture id are separated with a space " "
+   * picture id are grouped in blocks of 'amd_NumberOfItemsPerRequest' items and
+   * are separated with a semi-colon ";"
+   *
+   * client side just have to split blocks, and transmit it to the server
+   *
+   * There is two mode to determine the pictures being analyzed :
+   *  - "all"         : analyze all the images
+   *  - "notAnalyzed" : analyze only the images not yet analyzed
+   *
+   * @param String $mode
+   * @param Integer $nbOfItems : number of items per request
+   * @return String : list of image id to be analyzed, separated with a space
+   *                      "23 78 4523 5670"
+   */
+  private function ajax_amd_makeStatsGetList($mode, $nbOfItems)
+  {
+    $returned="";
+    $this->my_config['amd_NumberOfItemsPerRequest']=$nbOfItems;
+    $this->save_config();
+
+    $sql="SELECT imageId FROM ".$this->tables['images'];
+    if($mode=="notAnalyzed")
+    {
+      $sql.=" WHERE analyzed='n'";
+    }
+    else
+    {
+      pwg_query("UPDATE ".$this->tables['images']." SET analyzed='n', nbTags=0");
+      pwg_query("UPDATE ".$this->tables['used_tags']." SET numOfImg=0");
+      pwg_query("DELETE FROM ".$this->tables['images_tags']);
+    }
+
+    $result=pwg_query($sql);
+    if($result)
+    {
+      $i=0;
+      while($row=mysql_fetch_row($result))
+      {
+        $returned.=$row[0];
+        $i++;
+        if($i>=$nbOfItems)
+        {
+          $returned.=";";
+          $i=0;
+        }
+        else
+        {
+          $returned.=" ";
+        }
+      }
+    }
+
+    return(trim($returned).";");
+  }
+
+
+  /**
+   * extract metadata from images
+   *
+   * @param String $imageList : list of image id to be analyzed, separated with
+   *                            a space
+   *                                "23 78 4523 5670"
+   * @return String : list of the analyzed pictures, with number of tags found
+   *                  for each picture
+   *                    "23=0;78=66;4523=33;5670=91;"
+   */
+  private function ajax_amd_makeStatsDoAnalyze($imagesList)
+  {
+    $list=explode(" ", trim($imagesList));
+
+    $returned="";
+
+    if(count($list)>0)
+    {
+      // $path = path of piwigo's on the server filesystem
+      $path=dirname(dirname(dirname(__FILE__)));
+
+      $sql="SELECT id, path FROM ".IMAGES_TABLE." WHERE id IN (".implode(", ", $list).")";
+      $result=pwg_query($sql);
+      if($result)
+      {
+        while($row=mysql_fetch_assoc($result))
+        {
+          /*
+           * in some case (in a combination of some pictures), when there is too
+           * much pictures to analyze in the same request, a fatal error occurs
+           * with the message : "Allowed memory size of XXXXX bytes exhausted"
+           *
+           *
+           * tracking memory leak is not easy... :-(
+           *
+           */
+          //echo "analyzing:".$row['id']."\n";
+          //$mem1=memory_get_usage();
+          //echo "memory before analyze:".$mem1."\n";
+          $returned.=$this->analyzeImageFile($path."/".$row['path'], $row['id']);
+          //echo $returned."\n";
+          //$mem2=memory_get_usage();
+          //echo "memory after analyze:".$mem2." (".($mem2-$mem1).")\n";
+        }
+      }
+    }
+    return($returned);
+  }
+
+  /**
+   * returns a list of formated string, separated with a semi-colon :
+   *  - number of current analyzed pictures + number of current analyzed tags
+   *    for the analyzed pictures
+   *  - number of pictures not analyzed
+   *  - number of pictures without tag
+   *
+   * @return String
+   */
+  private function ajax_amd_makeStatsGetStatus()
+  {
+    $numOfMetaData=0;
+    $numOfPictures=0;
+    $numOfPicturesNotAnalyzed=0;
+
+    $sql="SELECT COUNT(imageId), SUM(nbTags) FROM ".$this->tables['images']."
+            WHERE analyzed='y';";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_row($result))
+      {
+        $numOfPictures=$row[0];
+        $numOfMetaData=$row[1];
+      }
+    }
+
+
+    $sql="SELECT COUNT(imageId) FROM ".$this->tables['images']."
+            WHERE analyzed='n';";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_row($result))
+      {
+        $numOfPicturesNotAnalyzed=$row[0];
+      }
+    }
+
+    $sql="SELECT COUNT(imageId) FROM ".$this->tables['images']."
+            WHERE nbTags=0;";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_row($result))
+      {
+        $numOfPicturesWithoutTags=$row[0];
+      }
+    }
+
+    return(sprintf(l10n("g003_numberOfAnalyzedPictures"), $numOfPictures, $numOfMetaData).";".
+              sprintf(l10n("g003_numberOfNotAnalyzedPictures"), $numOfPicturesNotAnalyzed).";".
+              sprintf(l10n("g003_numberOfPicturesWithoutTags"), $numOfPicturesWithoutTags));
+  }
+
+
+  /**
+   * make some stat consolidation
+   *  "0" : consolidate "exif.%" tags
+   *  "1" : consolidate "iptc.%" tags
+   *  "2" : consolidate "xmp.%" tags
+   *
+   * @param String $step
+   */
+  private function ajax_amd_makeStatsConsolidate($step)
+  {/*
+    $sql="INSERT INTO ".$this->tables['used_tags']."
+            SELECT tagId, count(distinct imageId)
+              FROM ".$this->tables['images_tags']."
+              WHERE tagId LIKE '%s'
+              GROUP BY tagId";
+
+    switch($step)
+    {
+      case "0":
+        pwg_query("DELETE FROM ".$this->tables['used_tags']);
+        $sql=sprintf($sql, "exif.%");
+        pwg_query($sql);
+        break;
+      case "1":
+        $sql=sprintf($sql, "iptc.%");
+        pwg_query($sql);
+        break;
+      case "2":
+        $sql=sprintf($sql, "xmp.%");
+        pwg_query($sql);
+        break;
+    }*/
+  }
+
+
+  /**
+   * return a formatted <table> (using the template "amd_stat_show_iListTags")
+   * of used tag with, for each tag, the number and the percentage of pictures
+   * where the tag was found
+   *
+   * @param String $orderType : order for the list (by tag 'tag' or by number of
+   *                            pictures 'num')
+   * @param String $filterType : filter for the list ('exif', 'xmp', 'iptc' or '')
+   * @return String
+   */
+  private function ajax_amd_showStatsGetListTags($orderType, $filterType, $excludeUnusedTag, $selectedTagOnly)
+  {
+    $this->my_config['amd_GetListTags_OrderType'] = $orderType;
+    $this->my_config['amd_GetListTags_FilterType'] = $filterType;
+    $this->my_config['amd_GetListTags_ExcludeUnusedTag'] = $excludeUnusedTag;
+    $this->my_config['amd_GetListTags_SelectedTagOnly'] = $selectedTagOnly;
+    $this->save_config();
+
+    $local_tpl = new Template(AMD_PATH."admin/", "");
+    $local_tpl->set_filename('body_page',
+                  dirname($this->filelocation).'/admin/amd_metadata_select_iListTags.tpl');
+
+    $numOfPictures=$this->getNumOfPictures();
+
+    $datas=array();
+    $sql="SELECT ut.numId, ut.tagId, ut.translatable, ut.name, ut.numOfImg, if(st.tagId IS NULL, 'n', 'y') as checked
+            FROM ".$this->tables['used_tags']." ut
+              LEFT JOIN ".$this->tables['selected_tags']." st
+                ON st.tagId = ut.tagId ";
+    $where="";
+
+    if($filterType!='')
+    {
+      $where.=" WHERE ut.tagId LIKE '".$filterType.".%' ";
+    }
+
+    if($excludeUnusedTag=='y')
+    {
+      ($where=="")?$where=" WHERE ":$where.=" AND ";
+      $where.=" ut.numOfImg > 0 ";
+    }
+
+    if($selectedTagOnly=='y')
+    {
+      ($where=="")?$where=" WHERE ":$where.=" AND ";
+      $where.=" st.tagId IS NOT NULL ";
+    }
+
+    $sql.=$where;
+
+    switch($orderType)
+    {
+      case 'tag':
+        $sql.=" ORDER BY tagId ASC";
+        break;
+      case 'num':
+        $sql.=" ORDER BY numOfImg DESC, tagId ASC";
+        break;
+    }
+
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_assoc($result))
+      {
+        $datas[]=array(
+          "numId" => $row['numId'],
+          "tagId" => $row['tagId'],
+          "label" => L10n::get($row['name']),
+          "nb"    => $row['numOfImg'],
+          "pct"   => ($numOfPictures!=0)?sprintf("%.2f", 100*$row['numOfImg']/$numOfPictures):"-",
+          "tagChecked" => ($row['checked']=='y')?"checked":""
+        );
+      }
+    }
+
+    $local_tpl->assign('datas', $datas);
+
+    return($local_tpl->parse('body_page', true));
+  }
+
+
+  /*
+   *
+   *
+   */
+  private function ajax_amd_showStatsGetListImages($tagId, $orderType)
+  {
+    $this->my_config['amd_GetListImages_OrderType'] = $orderType;
+    $this->save_config();
+
+    $local_tpl = new Template(AMD_PATH."admin/", "");
+    $local_tpl->set_filename('body_page',
+                  dirname($this->filelocation).'/admin/amd_metadata_select_iListImages.tpl');
+
+
+
+    $datas=array();
+    $sql="SELECT ut.translatable, ut.numOfImg, COUNT(it.imageId) AS Nb, it.value
+            FROM ".$this->tables['used_tags']." ut
+              LEFT JOIN ".$this->tables['images_tags']." it
+              ON ut.numId = it.numId
+            WHERE ut.tagId = '".$tagId."'
+              AND it.value IS NOT NULL
+            GROUP BY it.value
+            ORDER BY ";
+    switch($orderType)
+    {
+      case 'value':
+        $sql.="it.value ASC";
+        break;
+      case 'num':
+        $sql.="Nb DESC";
+        break;
+    }
+
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_assoc($result))
+      {
+        $datas[]=array(
+          "value" => ($row['translatable']=='y')?L10n::get($row['value']):$row['value'],
+          "nb"    => $row['Nb'],
+          "pct"   => ($row['numOfImg']!=0)?sprintf("%.2f", 100*$row['Nb']/$row['numOfImg']):"-"
+        );
+      }
+    }
+
+    if(count($datas)>0)
+    {
+      $local_tpl->assign('datas', $datas);
+      return($local_tpl->parse('body_page', true));
+    }
+    else
+    {
+      return("<div style='width:100%;text-align:center;padding-top:20px;'>".l10n('g003_selected_tag_isnot_linked_with_any_picture')."</div>");
+    }
+  }
+
+
+  /*
+   *
+   *
+   */
+  private function ajax_amd_updateTagSelect($numId, $selected)
+  {
+    if($selected=='y')
+    {
+      $sql="SELECT ut.tagId FROM ".$this->tables['selected_tags']." st
+              LEFT JOIN ".$this->tables['used_tags']." ut
+                ON ut.tagID = st.tagId
+              WHERE ut.numId = $numId;";
+      $result=pwg_query($sql);
+      if($result)
+      {
+        if(mysql_num_rows($result)==0)
+        {
+          $sql="INSERT INTO ".$this->tables['selected_tags']."
+                  SELECT ut.tagId, 0, -1
+                  FROM ".$this->tables['used_tags']." ut
+                    LEFT JOIN ".$this->tables['selected_tags']." st
+                      ON ut.tagID = st.tagId
+                  WHERE ut.numId = $numId;";
+          pwg_query($sql);
+        }
+      }
+    }
+    elseif($selected=='n')
+    {
+      $sql="DELETE FROM ".$this->tables['selected_tags']." st
+              USING phpwebgallery_amd_used_tags ut
+                LEFT JOIN phpwebgallery_amd_selected_tags st
+                  ON ut.tagID = st.tagId
+              WHERE ut.numId = $numId;";
+      pwg_query($sql);
+    }
+
+  }
+
+
+  /**
+   * this function return the list of tags :
+   *  - associated with the group
+   *  - not associated with a group
+   * the list is used to make tags selection
+   *
+   * @param String $id      : Id of the current group
+   * @return String : an HTML formatted list with checkbox
+   */
+  private function ajax_amd_groupGetTagList($id)
+  {
+    if($id!="")
+    {
+      $sql="SELECT st.tagId, st.groupId, ut.name, ut.numId
+            FROM ".$this->tables['selected_tags']." st
+              LEFT JOIN ".$this->tables['used_tags']." ut
+                ON st.tagId = ut.tagId
+            ORDER BY tagId";
+      $result=pwg_query($sql);
+      if($result)
+      {
+        $datas=Array();
+        while($row=mysql_fetch_assoc($result))
+        {
+          if($row['groupId']==$id)
+          {
+            $state="checked";
+          }
+          elseif($row['groupId']==-1)
+          {
+            $state="";
+          }
+          else
+          {
+            $state="n/a";
+          }
+
+          if($state!="n/a")
+            $datas[]=Array(
+              'tagId' => $row['tagId'],
+              'name'  => L10n::get($row['name']),
+              'state' => $state,
+              'numId' => $row['numId']
+            );
+        }
+
+        if(count($datas)>0)
+        {
+          $local_tpl = new Template(AMD_PATH."admin/", "");
+          $local_tpl->set_filename('body_page',
+                        dirname($this->filelocation).'/admin/amd_metadata_display_groupListTagSelect.tpl');
+          $local_tpl->assign('datas', $datas);
+          return($local_tpl->parse('body_page', true));
+        }
+        else
+        {
+          return(l10n("g003_no_tag_can_be_selected"));
+        }
+      }
+    }
+    else
+    {
+      return(l10n("g003_invalid_group_id"));
+    }
+  }
+
+
+  /**
+   * this function associate tags to a group
+   *
+   * @param String $id      : Id of group
+   * @param String $listTag : list of selected tags, items are separated by a
+   *                          semi-colon ";" char
+   */
+  private function ajax_amd_groupSetTagList($id, $listTag)
+  {
+    if($id!="")
+    {
+      $sql="UPDATE ".$this->tables['selected_tags']."
+            SET groupId = -1
+            WHERE groupId = $id;";
+      pwg_query($sql);
+
+      if($listTag!="")
+      {
+        $sql="UPDATE ".$this->tables['selected_tags']." st, ".$this->tables['used_tags']." ut
+              SET st.groupId = $id
+              WHERE st.tagId = ut.tagId
+                AND ut.numId IN ($listTag);";
+        pwg_query($sql);
+      }
+    }
+    else
+    {
+      return("KO");
+    }
+  }
+
+
+  /**
+   * this function returns an ordered list of tags associated with a group
+   *
+   * @param String $id        : the group Id
+   * @return String : an HTML formatted list
+   */
+  private function ajax_amd_groupGetOrderedTagList($id)
+  {
+    global $template;
+    if($id!="")
+    {
+      $numOfPictures=$this->getNumOfPictures();
+
+      $sql="SELECT st.tagId, ut.name, ut.numId, ut.numOfImg
+            FROM ".$this->tables['selected_tags']." st
+              LEFT JOIN ".$this->tables['used_tags']." ut
+                ON st.tagId = ut.tagId
+            WHERE st.groupId = $id
+            ORDER BY st.order ASC, st.tagId ASC";
+      $result=pwg_query($sql);
+      if($result)
+      {
+        $datas=Array();
+        while($row=mysql_fetch_assoc($result))
+        {
+          $datas[]=Array(
+            'tagId' => $row['tagId'],
+            'name'  => L10n::get($row['name']),
+            'numId' => $row['numId'],
+            'nbItems' => $row['numOfImg'],
+            'pct'   => sprintf("%.2f", 100*$row['numOfImg']/$numOfPictures)
+          );
+        }
+
+        if(count($datas)>0)
+        {
+          $template->set_filename('list_page',
+                        dirname($this->filelocation).'/admin/amd_metadata_display_groupListTagOrder.tpl');
+          $template->assign('datas', $datas);
+          $template->assign('group', $id);
+          return($template->parse('list_page', true));
+        }
+        else
+        {
+          return(l10n("g003_no_tag_can_be_selected"));
+        }
+      }
+    }
+    else
+    {
+      return(l10n("g003_invalid_group_id"));
+    }
+  }
+
+
+  /**
+   * this function update the tags order inside a group
+   *
+   * @param String $id        : the group Id
+   * @param String $listGroup : the ordered list of tags, items are separated
+   *                            by a semi-colon ";" char
+   */
+  private function ajax_amd_groupSetOrderedTagList($id, $listTag)
+  {
+    $tags=explode(';', $listTag);
+    if($id!="" and count($tags)>0)
+    {
+      /*
+       * by default, all items are set with order equals -1 (if list is not
+       * complete, forgotten items are sorted in head)
+       */
+      pwg_query("UPDATE ".$this->tables['selected_tags']." st
+                  SET st.order = -1
+                  WHERE st.groupId = $id;");
+
+      foreach($tags as $key=>$val)
+      {
+        $sql="UPDATE ".$this->tables['selected_tags']." st, ".$this->tables['used_tags']." ut
+              SET st.order = $key
+              WHERE st.groupId = $id
+                AND st.tagId = ut.tagId
+                AND ut.numId = $val;";
+        $result=pwg_query($sql);
+      }
+    }
+  }
+
+
+
+  /**
+   * this function update the groups order
+   *
+   * @param String $listGroup : the ordered list of groups, items are separated
+   *                            by a semi-colon ";" char
+   */
+  private function ajax_amd_groupSetOrder($listGroup)
+  {
+    $groups=explode(";",$listGroup);
+    if(count($groups)>0)
+    {
+      /*
+       * by default, all items are set with order equals -1 (if list is not
+       * complete, forgotten items are sorted in head)
+       */
+      pwg_query("UPDATE ".$this->tables['groups']." g SET g.order = -1;");
+
+      foreach($groups as $key=>$val)
+      {
+        $sql="UPDATE ".$this->tables['groups']." g
+              SET g.order = $key
+              WHERE g.groupId = $val;";
+        $result=pwg_query($sql);
+      }
+    }
+  }
+
+  /**
+   * this function is used to create a new group ($groupId = "") or update the
+   * group name (names are given in all langs in a list)
+   *
+   * @param String $groupId : the groupId to update, or "" to create a new groupId
+   * @param String $listNames : name of the group, in all language given as a
+   *                            list ; each lang is separated by a carraige
+   *                            return "\n" char, each items is defined as
+   *                            lang=value
+   *                              en_UK=the name group
+   *                              fr_FR=le nom du groupe
+   */
+  private function ajax_amd_groupSetNames($groupId, $listNames)
+  {
+    $names=explode("\n", $listNames);
+    if($groupId=="" and count($names)>0)
+    {
+      $sql="INSERT INTO ".$this->tables['groups']." VALUES('', 9999)";
+      $result=pwg_query($sql);
+      $groupId=mysql_insert_id();
+    }
+
+    if(is_numeric($groupId) and count($names)>0)
+    {
+      $sql="DELETE FROM ".$this->tables['groups_names']."
+            WHERE groupId = $groupId;";
+      pwg_query($sql);
+
+
+      $sql="";
+      foreach($names as $val)
+      {
+        $tmp=explode("=", $val);
+        if($sql!="") $sql.=", ";
+        $sql.=" ($groupId, '".$tmp[0]."', '".$tmp[1]."')";
+      }
+      $sql="INSERT INTO ".$this->tables['groups_names']." VALUES ".$sql;
+      pwg_query($sql);
+    }
+  }
+
+  /**
+   * this function returns an html form, allowing to manage the group
+   *
+   * @param String $groupId : the groupId to manage, or "" to return a creation
+   *                          form
+   * @return String : the form
+   */
+  private function ajax_amd_groupGetNames($groupId)
+  {
+    global $user;
+
+    $local_tpl = new Template(AMD_PATH."admin/", "");
+    $local_tpl->set_filename('body_page',
+                  dirname($this->filelocation).'/admin/amd_metadata_display_groupEdit.tpl');
+
+    $datasLang=array(
+      'language_list' => Array(),
+      'lang_selected' => $user['language'],
+      'fromlang' => substr($user['language'],0,2),
+      'default' => ''
+    );
+
+    $langs=get_languages();
+    foreach($langs as $key => $val)
+    {
+      $datasLang['language_list'][$key] = Array(
+        'langName' => str_replace("\n", "", $val),
+        'name' => ""
+      );
+    }
+
+    if($groupId!="")
+    {
+      $sql="SELECT lang, name FROM ".$this->tables['groups_names']."
+            WHERE groupId = $groupId;";
+      $result=pwg_query($sql);
+      if($result)
+      {
+        while($row=mysql_fetch_assoc($result))
+        {
+          if(array_key_exists($row['lang'], $datasLang['language_list']))
+          {
+            $datasLang['language_list'][$row['lang']]['name']=htmlentities($row['name'], ENT_QUOTES, 'UTF-8');
+            if($user['language']==$row['lang'])
+            {
+              $datasLang['default']=$datasLang['language_list'][$row['lang']]['name'];
+            }
+          }
+        }
+      }
+    }
+
+    $local_tpl->assign('datasLang', $datasLang);
+
+    return($local_tpl->parse('body_page', true));
+  }
+
+
+  /**
+   * this function returns an html form, allowing to manage the group
+   *
+   * @param String $groupId : the groupId to manage, or "" to return a creation
+   *                          form
+   * @return String : the form
+   */
+  private function ajax_amd_groupGetList()
+  {
+    global $user, $template;
+
+    //$local_tpl = new Template(AMD_PATH."admin/", "");
+    $template->set_filename('group_list',
+                  dirname($this->filelocation).'/admin/amd_metadata_display_groupList.tpl');
+
+
+    $datas=array(
+      'groups' => Array(),
+    );
+
+    $sql="SELECT g.groupId, gn.name
+          FROM ".$this->tables['groups']." g
+            LEFT JOIN ".$this->tables['groups_names']." gn
+              ON g.groupId = gn.groupId
+          WHERE gn.lang = '".$user['language']."'
+          ORDER BY g.order;";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_assoc($result))
+      {
+        $datas['groups'][]=Array(
+          'id' => $row['groupId'],
+          'name' => htmlentities($row['name'], ENT_QUOTES, "UTF-8")
+        );
+      }
+    }
+
+    $template->assign('datas', $datas);
+    return($template->parse('group_list', true));
+  }
+
+
+  /**
+   * delete the group
+   * associated tag returns in the available tag list
+   *
+   * @param String $groupId : the groupId to delete
+   */
+  private function ajax_amd_groupDelete($groupId)
+  {
+    if($groupId!="")
+    {
+      $sql="DELETE FROM ".$this->tables['groups']."
+            WHERE groupId = $groupId;";
+      pwg_query($sql);
+
+      $sql="DELETE FROM ".$this->tables['groups_names']."
+            WHERE groupId = $groupId;";
+      pwg_query($sql);
+
+      $sql="UPDATE ".$this->tables['selected_tags']."
+            SET groupId = -1
+            WHERE groupId = $groupId;";
+      pwg_query($sql);
+    }
+  }
+
+} // AMD_AIP class
+
+
+?>
Index: /extensions/AMetaData/amd_install.class.inc.php
===================================================================
--- /extensions/AMetaData/amd_install.class.inc.php	(revision 4905)
+++ /extensions/AMetaData/amd_install.class.inc.php	(revision 4905)
@@ -0,0 +1,126 @@
+<?php
+/*
+ * -----------------------------------------------------------------------------
+ * Plugin Name: Advanced MetaData
+ * -----------------------------------------------------------------------------
+ * Author     : Grum
+ *   email    : grum@piwigo.org
+ *   website  : http://photos.grum.fr
+ *   PWG user : http://forum.piwigo.org/profile.php?id=3706
+ *
+ *   << May the Little SpaceFrog be with you ! >>
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * See main.inc.php for release information
+ *
+ * AMD_install : classe to manage plugin install
+ * ---------------------------------------------------------------------------
+ */
+
+  @include_once('amd_root.class.inc.php');
+  include_once(PHPWG_PLUGINS_PATH.'grum_plugins_classes-2/tables.class.inc.php');
+
+
+  class AMD_install extends AMD_root
+  {
+    private $tablef;
+    private $exportfile;
+
+    public function AMD_install($prefixeTable, $filelocation)
+    {
+      parent::__construct($prefixeTable, $filelocation);
+      $this->tablef= new manage_tables($this->tables);
+      $this->exportfile=dirname($this->filelocation).'/'.$this->plugin_name_files.'.sql';
+    }
+
+    /*
+     * function for installation process
+     * return true if install process is ok, otherwise false
+     */
+    public function install()
+    {
+      $tables_def=array(
+"CREATE TABLE `".$this->tables['used_tags']."` (
+  `numId` int(10) unsigned NOT NULL auto_increment,
+  `tagId` varchar(80) NOT NULL default '',
+  `translatable` char(1) NOT NULL default 'n',
+  `name` varchar(200) NOT NULL default '',
+  `numOfImg` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`numId`),
+  KEY `by_tag` (`tagId`)
+);",
+"CREATE TABLE `".$this->tables['images_tags']."` (
+  `imageId` mediumint(8) unsigned NOT NULL default '0',
+  `numId` int(10) unsigned NOT NULL default '0',
+  `value` varchar(255) default NULL,
+  PRIMARY KEY  USING BTREE (`imageId`,`numId`)
+);",
+"CREATE TABLE `".$this->tables['images']."` (
+  `imageId` MEDIUMINT(8) UNSIGNED NOT NULL,
+  `analyzed` CHAR(1)  NOT NULL DEFAULT 'n',
+  `nbTags` int(10) unsigned NOT NULL default '0',
+  PRIMARY KEY (`imageId`)
+);",
+"CREATE TABLE `".$this->tables['selected_tag']."` (
+  `tagId` VARCHAR(80)  NOT NULL,
+  `order` INTEGER UNSIGNED NOT NULL DEFAULT 0,
+  `groupId` INTEGER  NOT NULL DEFAULT -1,
+  PRIMARY KEY (`tagId`)
+);",
+"CREATE TABLE `".$this->tables['groups_names']."` (
+  `groupId` INTEGER  NOT NULL,
+  `lang` CHAR(5)  NOT NULL,
+  `name` VARCHAR(80)  NOT NULL,
+  PRIMARY KEY (`groupId`, `lang`)
+);",
+"CREATE TABLE `".$this->tables['groups']."` (
+  `groupId` INTEGER  NOT NULL AUTO_INCREMENT,
+  `order` INTEGER UNSIGNED NOT NULL DEFAULT 0,
+  PRIMARY KEY (`groupId`)
+);"
+);
+      //$table_def array
+      $tables_def = create_table_add_character_set($tables_def);
+      $result=$this->tablef->create_tables($tables_def);
+
+      /*
+       * fill the 'used_tags' table with default values
+       */
+      foreach(JpegMetaData::getTagList(Array('filter' => JpegMetaData::TAGFILTER_IMPLEMENTED, 'xmp' => true, 'maker' => true, 'iptc' => true)) as $key => $val)
+      {
+        $sql="INSERT INTO ".$this->tables['used_tags']." VALUES('', '".$key."', '".(($val['translatable'])?'y':'n')."', '".$val['name']."', 0);";
+        pwg_query($sql);
+      }
+
+      return($result);
+    }
+
+
+    /*
+        function for uninstall process
+    */
+    public function uninstall()
+    {
+      $this->tablef->export($this->exportfile);
+      $this->delete_config();
+      $this->tablef->drop_tables();
+    }
+
+    public function activate()
+    {
+      global $template;
+
+      $this->init_config();
+      $this->load_config();
+      $this->save_config();
+    }
+
+
+    public function deactivate()
+    {
+    }
+
+  } //class
+
+?>
Index: /extensions/AMetaData/amd_pip.class.inc.php
===================================================================
--- /extensions/AMetaData/amd_pip.class.inc.php	(revision 4905)
+++ /extensions/AMetaData/amd_pip.class.inc.php	(revision 4905)
@@ -0,0 +1,170 @@
+<?php
+/*
+ * -----------------------------------------------------------------------------
+ * Plugin Name: Advanced MetaData
+ * -----------------------------------------------------------------------------
+ * Author     : Grum
+ *   email    : grum@piwigo.org
+ *   website  : http://photos.grum.fr
+ *   PWG user : http://forum.piwigo.org/profile.php?id=3706
+ *
+ *   << May the Little SpaceFrog be with you ! >>
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * See main.inc.php for release information
+ *
+ * PIP classe => manage integration in public interface
+ * -----------------------------------------------------------------------------
+*/
+
+if (!defined('PHPWG_ROOT_PATH')) { die('Hacking attempt!'); }
+
+include_once('amd_root.class.inc.php');
+include_once(PHPWG_PLUGINS_PATH.'grum_plugins_classes-2/ajax.class.inc.php');
+
+class AMD_PIP extends AMD_root
+{
+  protected $ajax;
+
+  function AMD_PIP($prefixeTable, $filelocation)
+  {
+    parent::__construct($prefixeTable, $filelocation);
+    $this->ajax = new Ajax();
+
+    $this->load_config();
+    $this->init_events();
+  }
+
+
+  /* ---------------------------------------------------------------------------
+  Public classe functions
+  --------------------------------------------------------------------------- */
+
+
+  /*
+    initialize events call for the plugin
+  */
+  public function init_events()
+  {
+    parent::init_events();
+    add_event_handler('loc_begin_picture', array(&$this, 'loadMetadata'));
+  }
+
+  /**
+   * override piwigo's metadata with picture metadata
+   *
+   */
+  public function loadMetadata()
+  {
+    global $conf, $template, $page, $user;
+
+    L10n::setLanguage($user['language']);
+
+    $path=dirname(dirname(dirname(__FILE__)));
+    $filename="";
+
+    $sql="SELECT path FROM ".IMAGES_TABLE." WHERE id=".$page['image_id'].";";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_assoc($result))
+      {
+        $filename=$row['path'];
+      }
+      $filename=$path."/".$filename;
+    }
+
+    $JpegMD = new JpegMetaData(
+      $filename,
+      Array(
+        'filter' => JpegMetaData::TAGFILTER_IMPLEMENTED,
+        'optimizeIptcDateTime' => true,
+        'exif' => true,
+        'iptc' => true,
+        'xmp' => true
+      )
+    );
+
+    $conf['show_exif']=false;
+    $conf['show_iptc']=false;
+
+    $tagsList=Array();
+    $sql="SELECT st.tagId, gn.name as gName
+          FROM (phpwebgallery_amd_selected_tags st
+            LEFT JOIN phpwebgallery_amd_groups gr
+              ON gr.groupId = st.groupId)
+            LEFT JOIN phpwebgallery_amd_groups_names gn
+              ON st.groupId = gn.groupId
+          WHERE gn.lang='".$user['language']."'
+            AND st.groupId <> -1
+          ORDER BY gr.order, st.order;";
+    $result=pwg_query($sql);
+    if($result)
+    {
+      while($row=mysql_fetch_assoc($result))
+      {
+        $tagsList[$row['tagId']]=$row['gName'];
+      }
+    }
+
+    $metadata=Array();
+    $md=null;
+    $group=null;
+
+    $picturesTags=$JpegMD->getTags();
+
+    foreach($tagsList as $key => $val)
+    {
+      if(array_key_exists($key, $picturesTags))
+      {
+        $value=$picturesTags[$key]->getLabel();
+
+        if($picturesTags[$key]->isTranslatable())
+          $translatable="y";
+        else
+          $translatable="n";
+
+        if($value instanceof DateTime)
+        {
+          $value=$value->format("Y-m-d H:i:s");
+        }
+        elseif(is_array($value))
+        {
+          /*
+           * array values are stored in a serialized string
+           */
+          $value=serialize($value);
+        }
+
+        if($group!=$val)
+        {
+          $group=$val;
+          if(!is_null($md))
+          {
+            $metadata[]=$md;
+            unset($md);
+          }
+          $md=Array(
+            'TITLE' => $val,
+            'lines' => Array()
+          );
+        }
+        $md['lines'][L10n::get($picturesTags[$key]->getName())]=$value;
+      }
+    }
+
+    if(!is_null($md))
+    {
+      $metadata[]=$md;
+    }
+
+    unset($JpegMD);
+
+    $template->assign('metadata', $metadata);
+  }
+
+} // AMD_PIP class
+
+
+?>
Index: /extensions/AMetaData/amd_root.class.inc.php
===================================================================
--- /extensions/AMetaData/amd_root.class.inc.php	(revision 4905)
+++ /extensions/AMetaData/amd_root.class.inc.php	(revision 4905)
@@ -0,0 +1,133 @@
+<?php
+/*
+ * -----------------------------------------------------------------------------
+ * Plugin Name: Advanced MetaData
+ * -----------------------------------------------------------------------------
+ * Author     : Grum
+ *   email    : grum@piwigo.org
+ *   website  : http://photos.grum.fr
+ *   PWG user : http://forum.piwigo.org/profile.php?id=3706
+ *
+ *   << May the Little SpaceFrog be with you ! >>
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * See main.inc.php for release information
+ *
+ * AMD_install : classe to manage plugin install
+ * ---------------------------------------------------------------------------
+ */
+
+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');
+
+include_once('JpegMetaData/JpegMetaData.class.php');
+include_once(JPEG_METADATA_DIR."Common/L10n.class.php");
+
+class AMD_root extends common_plugin
+{
+  protected $css;   //the css object
+
+  function AMD_root($prefixeTable, $filelocation)
+  {
+    $this->plugin_name="AMetaData";
+    $this->plugin_name_files="amd";
+    parent::__construct($prefixeTable, $filelocation);
+
+    $tableList=array('used_tags', 'images_tags', 'images', 'selected_tags', 'groups_names', 'groups');
+    $this->set_tables_list($tableList);
+
+    $this->css = new css(dirname($this->filelocation).'/'.$this->plugin_name_files.".css");
+  }
+
+  /* ---------------------------------------------------------------------------
+  common AIP & PIP functions
+  --------------------------------------------------------------------------- */
+
+  /* this function initialize var $my_config with default values */
+  public function init_config()
+  {
+    $this->my_config=array(
+      'amd_NumberOfItemsPerRequest' => 25,
+      'amd_GetListTags_OrderType' => "tag",
+      'amd_GetListTags_FilterType' => "",
+      'amd_GetListTags_ExcludeUnusedTag' => "n",
+      'amd_GetListTags_SelectedTagOnly' => "n",
+      'amd_GetListImages_OrderType' => "value"
+    );
+  }
+
+  public function load_config()
+  {
+    parent::load_config();
+    if(!$this->css->css_file_exists())
+    {
+      $this->css->make_CSS($this->generate_CSS());
+    }
+  }
+
+  public function init_events()
+  {
+    parent::init_events();
+  }
+
+  /*
+   * generate the css code
+   */
+  function generate_CSS()
+  {
+    $text = "
+      .formtable, .formtable P { text-align:left; display:block; }
+      .formtable tr { vertical-align:top; }
+      .littlefont { font-size:90%; }
+      .littlefont td { padding:1px; }
+      table.littlefont th { padding:3px; text-align:left;}
+      table.littlefont td { padding:1px 3px; }
+      #iprogressbar_contener { border:1px solid #606060; margin:0px; padding:0px; display:block; height:20px; }
+      #iprogressbar_bg { background:#606060; display:block; z-index:100; position:relative; height:20px; }
+      #iprogressbar_fg { color:#FF3363; width:100%; text-align:center; display: block; z-index:200; position:relative; top:-18px;  }
+      #iHeaderListTags { width:100%; border:1px solid; border-collapse: collapse; }
+      #iListTags, #iListImages { width:100%; border:1px solid; margin-bottom:20px; height:120px; border-top:0px; overflow:auto;}
+      #iListTags table, #iListImages table, table.listTags { width:100%; text-align:left; border-collapse: collapse; }
+      #iListTags table tr:hover { cursor:pointer; background:#303030; }
+      #iListImages table tr:hover, table.listTags tr:hover { background:#303030; cursor:default; }
+      #iHeaderListImages { width:100%; border:1px solid; }
+      .warning { color:#dd0000; border:1px solid #dd0000; margin-bottom:8px; margin-top:8px; padding:8px; }
+      .warning p { margin-top:0.5em; margin-bottom:0em; }
+      .warning ul { margin-top:0em; margin-bottom:0.5em; }
+      .pctBar { height:6px; background:#FF7700; }
+      li.groupItems { border:1px solid #666666; margin-bottom:5px; padding:0 5px; width:90%; cursor:move; padding:4px; }
+      div.addGroup { padding-left:40px; text-align:left; }
+      #iGroups { list-style: none; }
+      .ui-dialog { background: #222222; border:2px solid #FF3363; }
+      .ui-dialog-buttonpane { padding:4px; }
+      .ui-dialog-buttonpane button { margin-right:8px; }
+      .ui-dialog-titlebar { background:#111111; font-weight:bold; }
+      .ui-dialog-title-dialog { text-align: left; }
+      .ui-dialog-titlebar-close { float: right; }
+      .ui-dialog-content { overflow:auto; }
+      .ui-dialog-container { }
+      .ui-dialog-titlebar-close { display:none; }
+      .tagListOrder { list-style: none; padding:0px; margin-right:8px; margin-left:35px; }
+      .tagListOrder li { border:none; background:#333333; padding:1px; margin-bottom:2px; width:100%; }
+      .groupTags { padding-top:8px; }
+      .editGroupListButton { margin-left:8px; position:absolute; z-index:1000; }
+      table.tagListOrderItem { width:100%; border-collapse:collapse; }
+      .dialogForm { text-align:left; margin:8px; }
+      #ianalyzestatus { background: #333333; margin:8px; padding:8px; }
+      #ianalyzestatus ul { margin:0px; padding:0 0 0 20px; }
+      #iamd_nb_item_per_request_display { display:inline-block; width:70px; }
+      #iamd_nb_item_per_request_slider { display:inline-block; width:350px; }
+      #iDialogProgress { margin:16px 8px 8px; }
+    ";
+
+    return($text);
+  }
+
+} // amd_root  class
+
+
+
+?>
Index: /extensions/AMetaData/index.php
===================================================================
--- /extensions/AMetaData/index.php	(revision 4905)
+++ /extensions/AMetaData/index.php	(revision 4905)
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file          : $Id: index.php 1912 2007-03-16 06:30:07Z rub $
+// | last update   : $Date: 2007-03-16 07:30:07 +0100 (ven, 16 mar 2007) $
+// | last modifier : $Author: rub $
+// | revision      : $Revision: 1912 $
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/AMetaData/language/fr_FR/description.txt
===================================================================
--- /extensions/AMetaData/language/fr_FR/description.txt	(revision 4905)
+++ /extensions/AMetaData/language/fr_FR/description.txt	(revision 4905)
@@ -0,0 +1,1 @@
+Advanced MetaData est un plugin permettant d'exploiter au maximum les métadonnées présentes dans les photos.
Index: /extensions/AMetaData/language/fr_FR/index.php
===================================================================
--- /extensions/AMetaData/language/fr_FR/index.php	(revision 4905)
+++ /extensions/AMetaData/language/fr_FR/index.php	(revision 4905)
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file          : $Id: index.php 1912 2007-03-16 06:30:07Z rub $
+// | last update   : $Date: 2007-03-16 07:30:07 +0100 (ven, 16 mar 2007) $
+// | last modifier : $Author: rub $
+// | revision      : $Revision: 1912 $
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/AMetaData/language/fr_FR/plugin.lang.php
===================================================================
--- /extensions/AMetaData/language/fr_FR/plugin.lang.php	(revision 4905)
+++ /extensions/AMetaData/language/fr_FR/plugin.lang.php	(revision 4905)
@@ -0,0 +1,81 @@
+<?php
+
+$lang['Grum Plugin Classes is not installed'] = 'Le plugin <b>Grum Plugin Classes</b> n\'est pas installé';
+
+$lang['amd_title_page'] = 'Gestion avancée des métadonnées';
+$lang['g003_version'] = 'v';
+
+$lang['g003_error_invalid_ajax_call'] = "Appel de fonction invalide !";
+
+$lang['g003_stat'] = "Statistiques";
+$lang['g003_metadata'] = "Métadonnées";
+$lang['g003_database'] = "Référentiel";
+$lang['g003_status'] = "Status";
+$lang['g003_show'] = "Consulter";
+
+$lang['g003_performances'] = "Performances";
+$lang['g003_setting_nb_items_per_request'] = "Nombre d'éléments traités par requêtes";
+$lang['g003_apply'] = "Appliquer";
+
+$lang['g003_numberOfAnalyzedPictures'] = "%d images ont fait l'objet d'une analyse et représentent %d métadonnées";
+$lang['g003_numberOfNotAnalyzedPictures'] = "%d images n'ont pas fait l'objet d'une analyse";
+$lang['g003_analyze_not_analyzed_pictures'] = "Analyser les images manquantes";
+$lang['g003_analyze_all_pictures'] = "Analyser toutes les images";
+$lang['g003_analyze'] = "Analyser";
+$lang['g003_update_metadata'] = "Mettre à jour le référentiel de métadonnées";
+$lang['g003_status_of_database'] = "Etat du référentiel";
+$lang['g003_updating_metadata'] = "Mise à jour du référentiel";
+$lang['g003_analyze_in_progress'] = "Traitement en cours...";
+$lang['g003_analyze_is_finished'] = "Traitement terminé";
+$lang['g003_loading'] = "Chargement...";
+$lang['g003_numberOfPicturesWithoutTags'] = "%d images ne disposent pas de métadonnées";
+$lang['g003_no_items_selected'] = "Aucun tag n'est sélectionné";
+$lang['g003_selected_tag_isnot_linked_with_any_picture'] = "Le tag sélectionné n'est rattaché à aucune image";
+$lang['g003_TagId'] = "Tag";
+$lang['g003_TagLabel'] = "Nom";
+$lang['g003_NumOfImage'] = "Images";
+$lang['g003_Pct'] = "%";
+$lang['g003_select'] = "Sélection";
+$lang['g003_display'] = "Affichage";
+$lang['g003_order'] = "Trier par";
+$lang['g003_filter'] = "Filtrer";
+$lang['g003_tagOrder'] = "Tag";
+$lang['g003_numOrder'] = "Nombre d'images";
+$lang['g003_valueOrder'] = "Valeur";
+$lang['g003_no_filter'] = "Aucun filtre";
+$lang['g003_exclude_unused_tags'] = "Exclure les tags inutilisés";
+$lang['g003_Value'] = "Valeur";
+$lang['g003_selected_tags_only'] = "Ne restituer que les tags sélectionnés";
+
+$lang['g003_select_metadata'] = "Sélection des métadonnées";
+$lang['g003_display_management'] = "Gestion de l'affichage des métadonnées";
+
+$lang['g003_click_to_edit_group'] = "Cliquer pour éditer les propriétés du groupe";
+$lang['g003_click_to_delete_group'] = "Cliquer pour supprimer le groupe";
+$lang['g003_click_to_manage_group'] = "Cliquer pour gérer les éléments du groupe";
+$lang['g003_click_to_manage_list'] = "Cliquer pour ajouter/supprimer des tags";
+$lang['g003_add_a_group'] = "Ajouter un groupe";
+$lang['g003_adding_a_group'] = "Ajout d'un groupe";
+$lang['g003_editing_a_group'] = "Edition d'un groupe";
+$lang['g003_deleting_a_group'] = "Suppression d'un groupe";
+$lang['g003_new_group'] = "Nouveau groupe";
+$lang['g003_name'] = "Nom";
+$lang['g003_add_delete_tags'] = "Ajouter/Supprimer des tags";
+$lang['g003_confirm_group_delete'] = "Etes-vous sur de vouloir supprimer le groupe %s ?";
+
+$lang['g003_ok'] = "Ok";
+$lang['g003_cancel'] = "Annuler";
+$lang['g003_yes'] = "Oui";
+$lang['g003_no'] = "Non";
+
+
+$lang['g003_invalid_group_id'] = "Identifiant de groupe invalide";
+$lang['g003_no_tag_can_be_selected'] = "Aucun tag n'est disponible";
+
+$lang['g003_warning_on_analyze_0'] = "Attention !";
+$lang['g003_warning_on_analyze_1'] = "En fonction du nombre de photos dans votre galerie, l'alimentation du référentiel est un processus qui peut s'avérer être long (jusqu'à plusieurs minutes de traitement), et gourmand en ressources sur le serveur.";
+$lang['g003_warning_on_analyze_2'] = "Certains hébergeurs peuvent sanctionner ce type d'usage.";
+$lang['g003_warning_on_analyze_3'] = "L'alimentation du référentiel n'est pas nécessaire pour que le plugin puisse exploiter les métadonnées de vos photos : il n'est nécessaire que pour les analyses statistiques";
+
+
+?>
Index: /extensions/AMetaData/language/index.php
===================================================================
--- /extensions/AMetaData/language/index.php	(revision 4905)
+++ /extensions/AMetaData/language/index.php	(revision 4905)
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file          : $Id: index.php 1912 2007-03-16 06:30:07Z rub $
+// | last update   : $Date: 2007-03-16 07:30:07 +0100 (ven, 16 mar 2007) $
+// | last modifier : $Author: rub $
+// | revision      : $Revision: 1912 $
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/AMetaData/main.inc.php
===================================================================
--- /extensions/AMetaData/main.inc.php	(revision 4905)
+++ /extensions/AMetaData/main.inc.php	(revision 4905)
@@ -0,0 +1,77 @@
+<?php
+/*
+Plugin Name: Advanced MetaData
+Version: 0.1b
+Description: An advanced metadata manager
+Plugin URI: http://piwigo.org
+Author: Piwigo team
+Author URI: http://piwigo.org
+*/
+
+/*
+--------------------------------------------------------------------------------
+  Author     : Grum
+    email    : grum@piwigo.org
+    website  : http://photos.grum.fr
+    PWG user : http://forum.piwigo.org/profile.php?id=3706
+
+    << May the Little SpaceFrog be with you ! >>
+--------------------------------------------------------------------------------
+
+:: HISTORY
+
+| release | date       |
+| 0.0b    | 2010/01/21 | * initial release
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+|         |            |
+
+
+:: TO DO
+
+--------------------------------------------------------------------------------
+
+:: NFO
+  AMD_AIM : classe to manage plugin integration into plugin menu
+  AMD_AIP : classe to manage plugin admin pages
+  AMD_PIP : classe to manage plugin public integration
+
+--------------------------------------------------------------------------------
+*/
+
+// pour faciliter le debug - make debug easier :o)
+ini_set('error_reporting', E_ALL);
+ini_set('display_errors', true);
+
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+define('AMD_DIR' , basename(dirname(__FILE__)));
+define('AMD_PATH' , PHPWG_PLUGINS_PATH . AMD_DIR . '/');
+
+define('AMD_VERSION' , '0.1b'); //=> ne pas oublier la version dans l'entête !!
+
+global $prefixeTable, $page;
+
+
+if(defined('IN_ADMIN'))
+{
+  //AMD admin part loaded and active only if in admin page
+  include_once("amd_aim.class.inc.php");
+  $obj = new AMD_AIM($prefixeTable, __FILE__);
+  $obj->init_events();
+  set_plugin_data($plugin['id'], $obj);
+}
+else
+{
+  //AMD public part loaded and active only if in public page
+  include_once("amd_pip.class.inc.php");
+  $obj = new AMD_PIP($prefixeTable, __FILE__);
+  set_plugin_data($plugin['id'], $obj);
+}
+
+
+?>
Index: /extensions/AMetaData/maintain.inc.php
===================================================================
--- /extensions/AMetaData/maintain.inc.php	(revision 4905)
+++ /extensions/AMetaData/maintain.inc.php	(revision 4905)
@@ -0,0 +1,97 @@
+<?php
+/*
+ * -----------------------------------------------------------------------------
+ * Plugin Name: Advanced MetaData
+ * -----------------------------------------------------------------------------
+ * Author     : Grum
+ *   email    : grum@piwigo.org
+ *   website  : http://photos.grum.fr
+ *   PWG user : http://forum.piwigo.org/profile.php?id=3706
+ *
+ *   << May the Little SpaceFrog be with you ! >>
+ *
+ * -----------------------------------------------------------------------------
+ *
+ */
+
+if (!defined('PHPWG_ROOT_PATH')) { die('Hacking attempt!'); }
+
+//ini_set('error_reporting', E_ALL);
+//ini_set('display_errors', true);
+
+defined('AMD_DIR') || define('AMD_DIR' , basename(dirname(__FILE__)));
+defined('AMD_PATH') || define('AMD_PATH' , PHPWG_PLUGINS_PATH . AMD_DIR . '/');
+@include_once(PHPWG_PLUGINS_PATH.'grum_plugins_classes-2/tables.class.inc.php');
+
+
+global $gpc_installed, $lang; //needed for plugin manager compatibility
+
+/* -----------------------------------------------------------------------------
+AMD 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.4
+
+  if(checkGPCRelease(2,0,4))
+  {
+    @include_once("amd_install.class.inc.php");
+    $gpc_installed=true;
+  }
+}
+
+function gpcMsgError(&$errors)
+{
+  array_push($errors, sprintf(l10n('Grum Plugin Classes is not installed (release >= %s)'), "2.0.4"));
+}
+// -----------------------------------------------------------------------------
+
+
+
+load_language('plugin.lang', AMD_PATH);
+
+function plugin_install($plugin_id, $plugin_version, &$errors)
+{
+  global $prefixeTable, $gpc_installed;
+  if($gpc_installed)
+  {
+    $amd=new AMD_install($prefixeTable, __FILE__);
+    $result=$amd->install();
+  }
+  else
+  {
+    gpcMsgError($errors);
+  }
+}
+
+function plugin_activate($plugin_id, $plugin_version, &$errors)
+{
+  global $prefixeTable;
+
+  $amd=new AMD_install($prefixeTable, __FILE__);
+  $result=$amd->activate();
+}
+
+function plugin_deactivate($plugin_id)
+{
+}
+
+function plugin_uninstall($plugin_id)
+{
+  global $prefixeTable, $gpc_installed;
+  if($gpc_installed)
+  {
+    $amd=new AMD_install($prefixeTable, __FILE__);
+    $result=$amd->uninstall();
+  }
+  else
+  {
+    gpcMsgError($errors);
+  }
+}
+
+
+
+?>
