diff --git a/generic_data/jobs.json b/generic_data/jobs.json
index 107be9a..4734f8d 100644
--- a/generic_data/jobs.json
+++ b/generic_data/jobs.json
@@ -3,14 +3,14 @@
      [{"nodeType" : "bkgWorks","text" : "Plot","id" : "resPlot-treeRootNode" }, 
       {"nodeType" : "bkgWorks","text" : "Download","id" : "resDown-treeRootNode"},
       {"nodeType" : "bkgWorks","text" : "Data Mining","id" : "resSearch-treeRootNode"}, 
-      {"nodeType" : "bkgWorks","text" : "Catalog","id" : "resCatalog-treeRootNode"}
+      {"nodeType" : "bkgWorks","text" : "Statistics","id" : "resStatistics-treeRootNode"}
 ]
   }, 
   {"nodeType" : "bkgWorks", "text" : "Jobs in Progress", "id" : "bkgjobs-treeRootNode", "children" :  
      [{"nodeType" : "bkgWorks","text" : "Plot","id" : "bkgPlot-treeRootNode" }, 
       {"nodeType" : "bkgWorks","text" : "Download","id" : "bkgDown-treeRootNode"},
       {"nodeType" : "bkgWorks","text" : "Data Mining","id" : "bkgSearch-treeRootNode"},
-      {"nodeType" : "bkgWorks","text" : "Catalog","id" : "bkgCatalog-treeRootNode"}
+      {"nodeType" : "bkgWorks","text" : "Statistics","id" : "bkgStatistics-treeRootNode"}
     ]
   }    
 ]}
diff --git a/js/app/AmdaApp.js b/js/app/AmdaApp.js
index cdde7c9..5850111 100755
--- a/js/app/AmdaApp.js
+++ b/js/app/AmdaApp.js
@@ -20,10 +20,17 @@ Ext.define('amdaApp.AmdaApp', {
     ],
     
     dynamicModules: {
+	statistics : {
+    		id          : 'statistics-win',
+    		icon        : 'icon-statistics',
+    		title       : 'Statistics',
+    		source      : 'amdaDesktop.StatisticsModule',
+    		useLauncher : true
+    	},
 	catalog : {
     		id          : 'catalog-win',
     		icon        : 'icon-catalog',
-    		title       : 'Generate/Edit catalogs',
+    		title       : 'Manage catalogs',
     		source      : 'amdaDesktop.CatalogModule',
     		useLauncher : true
     	},
@@ -275,12 +282,13 @@ Ext.define('amdaApp.AmdaApp', {
                    { name: 'Create/Modify parameter',  iconCls: 'edit', module: 'param-win' },                     
                    { name: 'Plot data',  iconCls: 'plot', module: 'plot-win'},
                    { name: 'Data mining',  iconCls: 'search', module: 'search-win'},
+		   { name: 'Statistics',  iconCls: 'statistics', module: 'statistics-win'},
                    { name: 'Download data',  iconCls: 'download_manager', module: 'down-win'},
                    { name: 'Upload data',  iconCls: 'mydata', module: 'up-win'},
                    { name: 'Manage TimeTables',    iconCls: 'timeTable', module: 'timetab-win' },
                    { name: 'TimeTables operations',   iconCls: 'operations', module: 'ttsOpe-win' },
-                   { name: 'Generate/Edit catalogs',  iconCls: 'catalog', module: 'catalog-win'},
-           //      { name: 'Visualize catalogs',  iconCls: 'visu_catalog', module: 'visucatalog-win'},
+                   { name: 'Manage catalogs',  iconCls: 'catalog', module: 'catalog-win'},
+                   { name: 'Visualize catalogs',  iconCls: 'visu_catalog', module: 'visucatalog-win'},
                    { name: 'Interoperability',   iconCls: 'interop', module: 'interop-win' }
                ]
             }),
diff --git a/js/app/controllers/ExplorerModule.js b/js/app/controllers/ExplorerModule.js
index 16182a6..c58d252 100644
--- a/js/app/controllers/ExplorerModule.js
+++ b/js/app/controllers/ExplorerModule.js
@@ -23,6 +23,7 @@ Ext.define('amdaDesktop.ExplorerModule', {
         'amdaModel.AliasNode',
         'amdaModel.TimeTableNode',
 	'amdaModel.CatalogNode',
+	'amdaModel.StatisticsNode',	// singleton; not shown in the tree
         'amdaModel.sharedTimeTableNode',
         'amdaModel.MyDataParamNode',
         'amdaModel.MyDataNode',
@@ -35,7 +36,8 @@ Ext.define('amdaDesktop.ExplorerModule', {
         'amdaModel.Plot', 
         'amdaModel.Download',
         'amdaModel.TimeTable',
-	'amdaModel.Catalog',
+	'amdaModel.Catalog',	
+	'amdaModel.Statistics',
         'amdaModel.FileObject',
         'amdaModel.FileParamObject',
         'amdaModel.FilterInfo'
diff --git a/js/app/controllers/StatisticsModule.js b/js/app/controllers/StatisticsModule.js
new file mode 100644
index 0000000..c6f55d5
--- /dev/null
+++ b/js/app/controllers/StatisticsModule.js
@@ -0,0 +1,45 @@
+/**
+ * Project   AMDA-NG
+ * Name      StatisticsModule.js
+ * @class    amdaDesktop.StatisticsModule
+ * @extends  amdaDesktop.InteractiveModule
+ * @brief    Statistics Module controller definition 
+ * @author   elena
+ */
+
+Ext.define('amdaDesktop.StatisticsModule', {
+	extend: 'amdaDesktop.InteractiveModule',
+	
+	 requires: [
+         'amdaUI.StatisticsUI'
+     ],
+     
+      contentId : 'statisticsUI',
+      
+    /**
+     * @cfg {String} data models
+     * @required
+     */
+	nodeDataModel : 'amdaModel.StatisticsNode',
+	objectDataModel : 'amdaModel.Statistics',
+    /**
+     * @cfg {String} window definitions
+     * @required
+     */
+	width : 550,
+	height: 550,
+	uiType : 'panelStatistics',
+	helpTitle : 'Help on Statistics Module',
+	helpFile : 'statisticsHelp',
+    /**	
+     * @override
+     */
+    createWindow : function() {
+        if (!this.linkedNode){
+            this.setLinkedNode(amdaModel.StatisticsNode);
+        }
+        this.callParent(arguments);
+    },	
+	
+		
+});
diff --git a/js/app/models/AliasNode.js b/js/app/models/AliasNode.js
index 7132a5a..aff762d 100644
--- a/js/app/models/AliasNode.js
+++ b/js/app/models/AliasNode.js
@@ -52,14 +52,7 @@ Ext.define('amdaModel.AliasNode', {
 
         return menuItems;
     }, 
-    
-    getAllContextMenuItems: function(){
-        return this.allMenuItems();
-    },
-    
-    getMultiContextMenuItems: function(){
-        return this.allMenuMultiItems(amdaModel.AliasNode.objectName);
-    },
+       
     
     create: function(alias, param) {
 	      AmdaAction.createObject({name: alias, param: param, 
diff --git a/js/app/models/BkgJobNode.js b/js/app/models/BkgJobNode.js
index 1ceec5f..dace07b 100644
--- a/js/app/models/BkgJobNode.js
+++ b/js/app/models/BkgJobNode.js
@@ -6,11 +6,6 @@
  * @brief   Basic Model of Node corresponding to Amda processes in background
  * @author  elena
  * @version $Id: BkgJobNode.js 1963 2013-12-06 17:50:37Z elena $
- * @todo
- *******************************************************************************
- *    FT Id     :   Date   : Name - Description
- *******************************************************************************
- *  :           :08/07/2011: elena creation
  */
 
 Ext.define('amdaModel.BkgJobNode', {
@@ -25,19 +20,19 @@ Ext.define('amdaModel.BkgJobNode', {
             PLOT: 'request',//'plot',
             CONDITION: 'condition',
             DOWNLOAD: 'download',
-            CATALOG: 'catalog'
+            STATISTICS: 'statistics'
         },
         JOB_ROOT_NODE: {
             PLOT: 'bkgPlot-treeRootNode',
             CONDITION: 'bkgSearch-treeRootNode',
             DOWNLOAD: 'bkgDown-treeRootNode',
-            CATALOG: 'bkgCatalog-treeRootNode'
+            STATISTICS: 'bkgStatistics-treeRootNode'
         },
 	RES_ROOT_NODE: {
             PLOT: 'resPlot-treeRootNode',
             CONDITION: 'resSearch-treeRootNode',
             DOWNLOAD: 'resDown-treeRootNode',
-            CATALOG: 'resCatalog-treeRootNode'
+            STATISTICS: 'resStatistics-treeRootNode'
         },
         STATUS_LIST: {
             IN_PROGRESS: 'in_progress',
@@ -225,12 +220,18 @@ Ext.define('amdaModel.BkgJobNode', {
         var obj = null;
         switch (this.get('jobType'))
         {
-			case 'condition' : 
+		    case 'condition' : 
 				obj = Ext.create('amdaModel.Search',
 		    			 {name: result.name,
 	    	   		  	resultId : result.result,
 	    	   		  	folderId : result.folder});
 		    	break;
+		    case 'statistics' : 
+				obj = Ext.create('amdaModel.Statistics',
+		    			 {name: result.name,
+	    	   		  	resultId : result.result,
+	    	   		  	folderId : result.folder});
+		    	break;
 		    case 'request' : 
 		    	obj = Ext.create('amdaModel.Plot',
 		    			 {name: result.name, format: result.format,
@@ -355,8 +356,8 @@ Ext.define('amdaModel.BkgJobNode', {
 		    case amdaModel.BkgJobNode.JOB_TYPES.DOWNLOAD:		    
 			rootNodeId = amdaModel.BkgJobNode.JOB_ROOT_NODE.DOWNLOAD;
 			break;
-		    case amdaModel.BkgJobNode.JOB_TYPES.CATALOG:                   
-			rootNodeId = amdaModel.BkgJobNode.JOB_ROOT_NODE.CATALOG;
+		    case amdaModel.BkgJobNode.JOB_TYPES.STATISTICS:                   
+			rootNodeId = amdaModel.BkgJobNode.JOB_ROOT_NODE.STATISTICS;
 			break;
 		    default:
 			break;
@@ -373,8 +374,8 @@ Ext.define('amdaModel.BkgJobNode', {
 		    case amdaModel.BkgJobNode.JOB_TYPES.DOWNLOAD:		    
 			rootNodeId = amdaModel.BkgJobNode.RES_ROOT_NODE.DOWNLOAD;
 			break;
-		    case amdaModel.BkgJobNode.JOB_TYPES.CATALOG:                   
-			rootNodeId = amdaModel.BkgJobNode.RES_ROOT_NODE.CATALOG;
+		    case amdaModel.BkgJobNode.JOB_TYPES.STATISTICS:                   
+			rootNodeId = amdaModel.BkgJobNode.RES_ROOT_NODE.STATISTICS;
 			break;
 		    default:
 			break;
diff --git a/js/app/models/Catalog.js b/js/app/models/Catalog.js
index f43acb7..afc1c31 100644
--- a/js/app/models/Catalog.js
+++ b/js/app/models/Catalog.js
@@ -14,9 +14,7 @@ Ext.define('amdaModel.Catalog', {
     extend: 'amdaModel.TimeTable',
     
     fields : [
-	      { name: 'parameter' },             
-              { name: 'timeTables' }//,
-//	      { name: 'timesrc', type: 'string',  defaultValue : "TimeTable" }
+	      { name: 'parameters' }                        
 	],
     
     getJsonValues : function (hasId) {
@@ -25,7 +23,7 @@ Ext.define('amdaModel.Catalog', {
     		values.id = this.get('id');
     	}
     	
-	values.timesrc =  'TimeTable';
+	values.timesrc =   this.get('timesrc');
     	values.name = this.get('name');
     	values.created = this.get('created');
 	
@@ -40,8 +38,7 @@ Ext.define('amdaModel.Catalog', {
         values.folderId = this.get('folderId');
     	values.nbIntervals = this.get('nbIntervals');
     	values.cacheToken = this.get('cacheToken');
-    	values.parameter = this.get('parameter');
-	values.timeTables = this.get('timetable');
+   	values.parameters = this.get('parameters');
     	values.leaf = true;
     	values.nodeType = amdaModel.CatalogNode.nodeType;
     	return values;
diff --git a/js/app/models/CatalogNode.js b/js/app/models/CatalogNode.js
index 3108f74..a33173b 100644
--- a/js/app/models/CatalogNode.js
+++ b/js/app/models/CatalogNode.js
@@ -9,7 +9,7 @@
 
 Ext.define('amdaModel.CatalogNode', {
 
-    extend: 'amdaModel.ExecutableNode',
+    extend: 'amdaModel.TimeTableNode',
     
     statics: {
         nodeType: 'catalog',
@@ -23,6 +23,45 @@ Ext.define('amdaModel.CatalogNode', {
 	  this.set('ownerTreeId',amdaUI.ExplorerUI.RESRC_TAB.TREE_ID);
 	  this.set('objectDataModel',amdaModel.Catalog.$className);
 	  if (this.get('leaf')) this.set('iconCls', 'icon-catalog');
+    },
+    
+     localMenuItems : function() {
+        var menuItems =
+         [/*{
+            fnId : 'dire-shareNode',
+            text : 'Share content',
+            hidden : true
+        },{
+            fnId : 'leaf-shareLeaf',
+            text : 'Share '+this.self.objectName,
+            hidden : true
+        },*/{
+            fnId : 'leaf-download',
+            text : 'Download '+ this.self.objectName,
+            hidden : true
+        }/*,{
+            fnId : 'leaf-operations',
+            text : 'Operations',
+            hidden : true
+        }*/];
+     
+        return menuItems;
+    },
+
+    localMultiMenuItems : function() {
+        var menuItems =
+         [/*{
+            fnId : 'mult-shareMulti',
+            text : 'Share selected '+this.self.objectName+'s'
+        },*/{
+            fnId : 'mult-downloadMulti',
+            text : 'Download selected '+this.self.objectName+'s'
+        }/*,{
+            fnId : 'mult-operationsMulti',
+            text : 'Operations'
+        }*/];
+     
+        return menuItems;
     }
-          
+         
 });
diff --git a/js/app/models/DerivedParamNode.js b/js/app/models/DerivedParamNode.js
index a596de3..4393a87 100644
--- a/js/app/models/DerivedParamNode.js
+++ b/js/app/models/DerivedParamNode.js
@@ -53,15 +53,11 @@ Ext.define('amdaModel.DerivedParamNode', {
     
     getAllContextMenuItems: function(){
         
-        var menuItems = this.allMenuItems(amdaModel.DerivedParamNode.objectName);
+        var menuItems = this.allMenuItems();
         var locMenuItems = this.localMenuItems();
         
         return  Ext.Array.merge(menuItems,locMenuItems);       
-    },
-
-    getMultiContextMenuItems: function(){
-        return this.allMenuMultiItems(amdaModel.DerivedParamNode.objectName);
-    },
+    },  
     
     isParameter : function(){
         return this.get('isParameter');
diff --git a/js/app/models/InteractiveNode.js b/js/app/models/InteractiveNode.js
index 3c8ceba..ded9d7d 100644
--- a/js/app/models/InteractiveNode.js
+++ b/js/app/models/InteractiveNode.js
@@ -369,7 +369,8 @@ Ext.define('amdaModel.InteractiveNode', {
      * Generic part of Context Menu
      *  
      */ 
-    allMenuItems : function(src) {
+    allMenuItems : function() {
+        var src = this.self.objectName;
         var menuItems =
             [ {
                 fnId : 'root-createLeaf',
@@ -402,16 +403,24 @@ Ext.define('amdaModel.InteractiveNode', {
         return menuItems;
     },
 
-    allMenuMultiItems : function(src) {
+    allMenuMultiItems : function() {
         var menuMulti = [
             {
                 fnId : 'mult-deleteMulti',
-                text : 'Delete selected '+ src+'s'
+                text : 'Delete selected ' + this.self.objectName + 's'
             }
         ];
         return menuMulti;
     },
     
+    getAllContextMenuItems: function(){  
+        return  this.allMenuItems();       
+    },
+
+    getMultiContextMenuItems: function(){
+        return this.allMenuMultiItems();
+    },
+    
     /**
      * default implementation
      * no menu display if there's no override of this function
diff --git a/js/app/models/LocalParamNode.js b/js/app/models/LocalParamNode.js
index 495690b..afe6e10 100644
--- a/js/app/models/LocalParamNode.js
+++ b/js/app/models/LocalParamNode.js
@@ -126,11 +126,7 @@ Ext.define('amdaModel.LocalParamNode',
         return menuItems;
     },
 
-    getAllContextMenuItems: function()
-    {
-        return this.allMenuItems();
-    },
-  
+   
     onMenuItemClick : function(menu,item,event) 
     {
         switch (item.fnId) 
diff --git a/js/app/models/MyDataParamNode.js b/js/app/models/MyDataParamNode.js
index 8d11ab7..69bc238 100644
--- a/js/app/models/MyDataParamNode.js
+++ b/js/app/models/MyDataParamNode.js
@@ -23,7 +23,8 @@ Ext.define('amdaModel.MyDataParamNode', {
 	     ],
 	   
      statics:{
-        nodeType: 'myDataParam'
+        nodeType: 'myDataParam',
+	objectName : 'Parameter'
     },
     
     constructor : function(config){
@@ -75,12 +76,8 @@ Ext.define('amdaModel.MyDataParamNode', {
         return menuItems;
     },
 
-    getAllContextMenuItems: function(){
-
-        var menuItems = this.allMenuItems('Parameter');
-        var locMenuItems = this.localMenuItems();
-
-        return  Ext.Array.merge(menuItems,locMenuItems);
+    getAllContextMenuItems: function(){      
+        return  this.localMenuItems();
     },
 
     onMenuItemClick : function(menu,item,event) {
diff --git a/js/app/models/PlotNode.js b/js/app/models/PlotNode.js
index b0229ef..2002258 100644
--- a/js/app/models/PlotNode.js
+++ b/js/app/models/PlotNode.js
@@ -72,14 +72,7 @@ Ext.define('amdaModel.PlotNode', {
         return menuMulti;
     },
     
-    getAllContextMenuItems: function(){
-        return this.allMenuItems();
-    },
-    
-    getMultiContextMenuItems: function(){
-        return this.allMenuMultiItems();
-    },
-    
+  
     onMenuItemClick : function(menu,item,event) {
         // fnId parsing :
         var fnId = Ext.util.Format.substr(item.fnId, 5, item.fnId.length);
diff --git a/js/app/models/SearchNode.js b/js/app/models/SearchNode.js
index 67fc049..0762b4a 100644
--- a/js/app/models/SearchNode.js
+++ b/js/app/models/SearchNode.js
@@ -70,14 +70,7 @@ Ext.define('amdaModel.SearchNode', {
         return menuMulti;
     },    
     
-   getAllContextMenuItems: function(){
-       return this.allMenuItems();
-    },
-    
-    getMultiContextMenuItems: function(){
-        return this.allMenuMultiItems();
-    },
-        
+          
     onMenuItemClick : function(menu,item,event) {
         // fnId parsing :
         var fnId = Ext.util.Format.substr(item.fnId, 5, item.fnId.length);
diff --git a/js/app/models/Statistics.js b/js/app/models/Statistics.js
new file mode 100644
index 0000000..769e90a
--- /dev/null
+++ b/js/app/models/Statistics.js
@@ -0,0 +1,75 @@
+/**
+ * Project      : AMDA-NG
+ * Name         : Statistics.js 
+ * Description  : Statistics Object Definition
+ * @class amdaModel.Statistics
+ * @extends amdaModel.TimeTable 
+ * @author  elena
+ */
+
+  
+
+Ext.define('amdaModel.Statistics', {
+	
+    extend: 'amdaModel.AmdaTimeObject',
+    
+    fields : [
+	      { name: 'parameter' } ,
+	      { name: 'description' }
+	//      { name: 'timesrc', type: 'string'}
+	],
+    
+    getJsonValues : function (hasId) {
+    	var values  = new Object();	    
+    	if (hasId) {
+    		values.id = this.get('id');
+    	}
+    	
+	values.timesrc =  this.get('timesrc');
+    	values.name = 'test'; //this.get('name');
+    
+	
+    	if (this.get('description').match(/[a-z,0-9]/gi) != null) {
+    		values.description = this.get('description');
+    	}
+//     	if (this.get('history').match(/[a-z,0-9]/gi) != null) {
+//     		values.history = this.get('history');
+//     	}
+    	values.objName = this.get('objName');
+    	values.objFormat = this.get('objFormat');
+        	
+//    	values.cacheToken = this.get('cacheToken');
+    	values.parameter = this.get('parameter'); 
+	if (values.timesrc == amdaModel.AmdaTimeObject.inputTimeSrc[0]){
+	      // get complete timeTables collection
+	      var timeTables = this.get('timeTables');	    
+	      // init an empty array for timeTables
+	      values.timeTables=[];
+	      // for each interval record
+	      Ext.Array.each(timeTables, function(item, index, all){
+		if (!item.$className) {
+		      values.timeTables[index] = {timeTableName : item.timeTableName, id : item.id};
+		}
+		  // get Json simplified value 
+		else {
+		  values.timeTables[index] = item.getJsonValues();
+		}
+	      });            
+	  } else {
+	      values.startDate = this.get('startDate');
+	      values.stopDate = this.get('stopDate');
+	      values.durationDay = this.get('durationDay');
+	      values.durationHour = this.get('durationHour');
+	      values.durationMin = this.get('durationMin');
+	      values.durationSec = this.get('durationSec');
+	  } 
+	 
+    	values.leaf = true;
+    	values.nodeType = 'statistics';
+	
+    	return values;
+    }
+	
+	
+ 
+});
\ No newline at end of file
diff --git a/js/app/models/StatisticsNode.js b/js/app/models/StatisticsNode.js
new file mode 100644
index 0000000..dce3b2e
--- /dev/null
+++ b/js/app/models/StatisticsNode.js
@@ -0,0 +1,40 @@
+/** 
+ * Project  : AMDA-NG
+ * Name     : StatisticsNode.js
+ * @class   amdaModel.StatisticsNode
+ * @extends amdaModel.TimeTableNode
+ * @brief   Basic Model of Node corresponding to a amda statistics operation
+ * @author  elena
+ */
+
+Ext.define('amdaModel.StatisticsNode', {
+
+    extend: 'amdaModel.ExecutableNode',
+    
+    singleton: true,
+    
+    
+    fields: [ {name : 'downloadType', type : 'string'},
+              {name: 'object', type: 'object'},
+	      {name: 'realLinkedNode', type: 'amdaModel.AmdaNode'},
+	      {name: 'moduleId', type: 'string', defaultValue:'statistics-win'},
+	      {name: 'nodeType', type: 'string', defaultValue: 'statistics'},
+	      {name: 'objectDataModel', type: 'string', defaultValue:'amdaModel.Statistics'},
+	      {name: 'jobNode', type: 'string', defaultValue: 'amdaModel.BkgJobNode'}
+     ], 
+    
+     isExecutable: function(){
+        return true;
+      }
+    /*,
+
+    constructor : function(config){//	
+          this.callParent(arguments); 
+	  this.set('nodeType',amdaModel.StatisticsNode.nodeType);
+	  this.set('moduleId',myDesktopApp.dynamicModules.statistics.id);
+	  this.set('ownerTreeId',amdaUI.ExplorerUI.OPE_TAB.TREE_ID);
+	  this.set('objectDataModel',amdaModel.Statistics.$className);
+//	  if (this.get('leaf')) this.set('iconCls', 'icon-catalog');
+    }
+          */
+});
diff --git a/js/app/models/TimeTableNode.js b/js/app/models/TimeTableNode.js
index 974a3e9..3d50811 100644
--- a/js/app/models/TimeTableNode.js
+++ b/js/app/models/TimeTableNode.js
@@ -60,10 +60,10 @@ Ext.define('amdaModel.TimeTableNode', {
         var menuItems =
          [/*{
             fnId : 'mult-shareMulti',
-            text : 'Share selected '+amdaModel.TimeTableNode.objectName+'s'
+            text : 'Share selected '+this.self.objectName+'s'
         },*/{
             fnId : 'mult-downloadMulti',
-            text : 'Download selected '+amdaModel.TimeTableNode.objectName+'s'
+            text : 'Download selected '+this.self.objectName+'s'
         },{
             fnId : 'mult-operationsMulti',
             text : 'Operations'
@@ -73,18 +73,21 @@ Ext.define('amdaModel.TimeTableNode', {
     },
     
     getAllContextMenuItems: function(){
-
-        var menuItems = this.allMenuItems(amdaModel.TimeTableNode.objectName);
+        
+        var menuItems = this.allMenuItems();
         var locMenuItems = this.localMenuItems();
-        return  Ext.Array.merge(menuItems,locMenuItems);
+        
+        return  Ext.Array.merge(menuItems,locMenuItems);       
     },
     
-    getMultiContextMenuItems: function(){
-        var multiMenu = this.allMenuMultiItems(amdaModel.TimeTableNode.objectName);
-        var locMultiMenuItems = this.localMultiMenuItems();
-        return  Ext.Array.merge(multiMenu,locMultiMenuItems);
+     getMultiContextMenuItems: function(){
+        
+        var menuItems = this.allMenuMultiItems();
+        var locMenuItems = this.localMultiMenuItems();
+        
+        return  Ext.Array.merge(menuItems,locMenuItems);       
     },
-  
+    
     onMenuItemClick : function(menu,item,event) {
  
         this.callParent(arguments);
diff --git a/js/app/views/CatalogUI.js b/js/app/views/CatalogUI.js
index 8dd1286..1ade353 100644
--- a/js/app/views/CatalogUI.js
+++ b/js/app/views/CatalogUI.js
@@ -10,103 +10,255 @@
 Ext.define('amdaUI.CatalogUI', {
 	extend: 'Ext.container.Container',
 	alias: 'widget.panelCatalog',
+
+	isCatalog : true,
 	
-	requires : [	
-//	  'amdaModel.Function'
-	],
-	
-	statics : {	 
-//	  functionStore : null
-	},
-		
 	constructor: function(config) {
-	        this.init(config); 
-		this.callParent(arguments);
-	//	if (this.object) this.loadObject();
+	        this.init(config);
+		this.callParent(arguments);;
+	 	if (this.object) this.loadObject();	         
 	},
 	
-	addParam : function(ParamName,isLeaf) 
-        {                        	 
-	    var r = Ext.create('amdaModel.AmdaObject', { name: ParamName });
-	    this.paramGrid.getStore().add(r);
-	    this.paramGrid.getSelectionModel().select(this.paramGrid.getStore().getCount()-1);  
-        },
 	
-	addTT : function(TTname,TTid)
-	{ 
-	    Ext.define('tempObject', {
-	      extend: 'Ext.data.Model',
-	      fields: [
-		  {name: 'name',  type: 'string'},
-		  {name: 'hidden_id',   type: 'string'}
-	      ]});
-	    var r = Ext.create('tempObject', { name:TTname, hidden_id : TTid });
-	    this.ttGrid.getStore().add(r);
-	    this.ttGrid.getSelectionModel().select(this.paramGrid.getStore().getCount()-1); 
-	 
-	},
-	 
-	generateCatalog : function(){	     
-	  var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id);
-	  if (module) 
-		module.linkedNode.execute();	     
+	/**
+	 * set params description into this.object
+	 */
+	setParamInfo : function(parameters) {
+	  
+	   var params = [];
+	   Ext.Array.each(parameters, function(item, index) {
+	      params[index] = item;	     	  
+	   }, this);
+	   
+	   this.object.set('parameters', params);
+	  
 	},
 	
 	/**
 	 * update this.object from form
-	 */
+	 */	
+	updateObject : function(){  
+	// get the basic form	
+	  var basicForm = this.formPanel.getForm();        
+	  var updateStatus = true;
+
+	  var fieldsWithoutName = basicForm.getFields().items;
+	  Ext.Array.each(fieldsWithoutName, function(item, index,allItems){
+	      if(item !== this.fieldName) { 		     
+		  if (!item.isValid()) {
+		      // set update isn't allowed
+		      updateStatus = false;    
+		  }
+	      }
+	  }, this);
+	      // if the update is allowed
+	  if (updateStatus) {
+	  /// real object update
+	  // update TimeTable object with the content of form
+	      basicForm.updateRecord(this.object);	
+	  }
+	  // return the update status  
+	   return updateStatus;	    
+	},
 	
-	updateObject : function(){    
-	    // get the basic form of the left 
-	    var basicForm = this.formPanel.items.items[0].getForm();
-	   
-	    var formValues = basicForm.getValues();
-	    this.object.set('name',formValues.name);
-	    this.object.set('description',formValues.description);
-	    
-	    var recs = this.paramGrid.getStore().getNewRecords();
-	    var paramArr = new Array();
-	    Ext.Array.each(recs, function(rec, index,allItems){
-	      var obj =  new Object();
-	      obj.param = rec.get('name');
-	      obj.function = rec.get('function');
-              paramArr.push(obj);            	      
-	    });
-	    this.object.set('parameter', paramArr);
+	
+	updateCount : function() {
+		this.object.set('nbIntervals',this.TTGrid.getStore().getTotalCount());		
+		this.formPanel.getForm().findField('nbIntervals').setValue(this.object.get('nbIntervals'));
+	},
+	
+	/**
+	 * load object catalog into this view
+	 */
+	loadObject : function(){ 	  
+        // load object into form
+	  this.formPanel.getForm().loadRecord(this.object);
+	  
+	  this.status = null;
+		
+	  var me = this;
+	  
+	  var onAfterInit = function(result, e) {
+	  
+	    if (!result || !result.success)
+          	{
+          		if (result.message)
+          			myDesktopApp.errorMsg(result.message);
+          		else
+          			myDesktopApp.errorMsg('Unknown error during catalog cache initialisation');
+          		return;
+          	}
+          	
+          	
+	    var fields = [], columns = [], i = 2, width, index;
 	    
-	    // hidden_id - if real 'id' - getNewRecords (and other getRecords) methods doesn't work
-	    var tts = this.ttGrid.getStore().getNewRecords();
-	    var ttArr = new Array();
-	    Ext.Array.each(tts, function(rec, index, allItems){	 
-	      var obj =  new Object();
-	      obj.id = rec.get('hidden_id');
-              ttArr.push(obj);            	      
-	    });
-	    this.object.set('timetable', ttArr);
+	    fields[0] =  Ext.create('Ext.data.Field',{ name : 'start' });
+	    fields[1] =  Ext.create('Ext.data.Field',{ name : 'stop' }); 
+			    
+	    columns[0] =  Ext.create('Ext.grid.column.RowNumberer');
 	    
-	    var updateStatus = true;
+	    columns[1] = Ext.create('Ext.grid.column.Column', { text: 'Start Time', sortable : false,  dataIndex: 'start',  
+				  width : 120, menuDisabled: true });
+	    columns[2] = Ext.create('Ext.grid.column.Column', { text: 'Stop Time', sortable : false,  dataIndex: 'stop',  
+				  width : 120, menuDisabled: true });
 	    
-	    return updateStatus;	    
+	    Ext.Array.each(result.parameters, function(obj) {
+		    index = 'param'+i.toString();			
+		    fields[i] = Ext.create('Ext.data.Field',{ name : index });
+		    width = 50. *  parseInt(obj.size);
+		    columns[i+1] = Ext.create('Ext.grid.column.Column', { text: obj.name, sortable : false,  dataIndex: index,  
+				  width : width, menuDisabled: true });
+		    i++;
+	      });
+            
+
+             var store = Ext.create('Ext.data.Store', {
+		  fields: fields,
+		  autoDestroy: false,
+		  pageSize : 200,
+		  buffered : true, 
+		  purgePageCount: 0,
+		  remoteSort: true,
+		  proxy: {
+		    type: 'direct',
+		    api :
+		    {
+			  read   :  AmdaAction.readTTCacheIntervals
+		    },
+		  // remplir automatiquement tt, sharedtt , catalog, shared catalog
+		  extraParams : {'typeTT' : 'catalog'},
+		  reader:
+		  {
+		    type: 'json',
+		    root: 'intervals',
+		    totalProperty : 'totalCount'
+		  }
+		  },
+		  listeners: {
+		    scope : me,
+	            load: function(store,records) {        
+                       // myDesktopApp.EventManager.fireEvent('refresh');
+                        me.TTGrid.getView().refresh();
+                        me.TTGrid.getSelectionModel().refresh();
+                        me.updateCount();
+                        //Statistical plugin
+             		//   	this.fireEvent("refresh");
+	            }
+		  }
+                 });
+	   
+	      me.TTGrid.reconfigure(store, columns);
+	             	             
+//         	
+//         	me.TTGrid.getSelectionModel().deselectAll();
+//         	        	
+//         	// clear filters
+//         	me.TTGrid.getStore().clearFilter(true);
+//         
+//     		//clear sort
+//         	me.TTGrid.getStore().sorters.clear();
+//         	//me.TTGrid.getStore().sorters = new Ext.util.MixedCollection();
+//         	
+         	//set cache token to the Catalog object
+         	me.object.set('cacheToken', result.token);
+         	me.setParamInfo(result.parameters);
+		
+        	me.TTGrid.getStore().load();
+		
+         	me.status = result.status;
+
+	  };
+	  
+	if (this.object.get('fromPlugin'))
+        {
+        	if (this.object.get('objFormat') && this.object.get('objFormat') != '')
+        	{
+        		//From uploaded file
+        		//AmdaAction.initTTCacheFromUploadedFile(this.object.get('objName'), this.object.get('objFormat'), onAfterInit);
+        	}
+        	else
+        	{
+        		//From tmp object (ie Search result)		    
+        		AmdaAction.initTTCacheFromTmpObject(this.object.get('folderId'), this.object.get('objName'), this.isCatalog, onAfterInit);
+        	}
+        }
+        else
+        {
+        	var typeTT = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.tt.id).linkedNode.data.nodeType;
+        	if (this.object.get('id') == '')
+        	{
+        		//Init empty cache
+        		//AmdaAction.initTTCache(onAfterInit);
+        	}	
+        	else
+        	{
+        		//From existing TT file
+        		//AmdaAction.initTTCacheFromTT(this.object.get('id'), typeTT, onAfterInit);
+        	}
+        }
+	},
+	checkIntervalsStatusForSave : function(onStatusOk) {
+	  onStatusOk();
+	},
+	
+	/*	    
+	 * save method called by Save button
+	 */
+	saveProcess : function(toRename){
+            var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id); 
+	      
+            // if the name has been modified this is a creation
+             if (this.fclose()) {  
+	       
+	      if (this.object.isModified('name') || this.object.get('fromPlugin')) {
+	            
+                // if object already has an id : it's a 'rename' of an existing  
+                if (this.object.get('id')){
+                    // the context Node is the parent node of current edited one
+                    var contextNode = module.linkedNode.parentNode;
+                    // link a new node to the TimeTableModule
+                    module.createLinkedNode();
+                    // set the contextNode
+                    module.linkedNode.set('contextNode',contextNode);
+                    // create a new object linked
+                    module.createObject(this.object.getJsonValues());
+                    
+                    var obj = module.linkedNode.get('object');                                                    
+                    // synchronisation of objects
+                    this.object = obj;
+                    if (toRename) module.linkedNode.toRename = true;
+                } 
+                module.linkedNode.create({callback : function() {module.linkedNode.update();}, scope : this});
+	      } else {
+		  //update
+		module.linkedNode.update();
+	    }
+	    }
 	},
 	
+	/**
+	 * Check if changes were made before closing window 
+	 * @return true if changes
+	 */	
+	fclose : function() {
+		if (this.status == null)
+			return false;
+		
+		var isDirty = this.formPanel.getForm().isDirty() || (this.status.isModified) || (this.status.nbModified > 0) || (this.status.nbNew > 0);
+		return isDirty;
+	},
+
+		    
 	init : function (config) {
 	  
-// 	  var functions = Ext.create('Ext.data.Store', {
-// 	    fields: ['id', 'name'],
-// 	    data : [
-// 		{"id":"min", "name":"MIN"},
-// 		{"id":"max", "name":"MAX"},
-// 		{"id":"mean","name":"MEAN"}        
-// 	    ]
-// 	    });
-	     
+          this.object =   config.object;
+	  
 	  this.fieldName = new Ext.form.field.Text({
-	      fieldLabel: 'Name*',
+	      fieldLabel: 'Name',
 	      allowBlank : false,
 	      stripCharsRe: /(^\s+|\s+$)/g,
 	      emptyText: 'Please no spaces!',
 	      name: 'name',
-	      anchor: '100%',
 	      validateOnChange: false,
 	      validateOnBlur: false,
 	      validFlag: false,
@@ -115,209 +267,78 @@ Ext.define('amdaUI.CatalogUI', {
 		  }
 	  });
 	  
-	  var ttStore = Ext.create('Ext.data.Store', 
-	    {
-		fields: [ 'name', 'hidden_id']	
-	    });
-	  
-         this.ttGrid = Ext.create('Ext.grid.Panel', { 
-	    title: 'Select Time Table',  
-	    height: 100,
-	    store : ttStore,
-	    columns: [
-	      { xtype: 'rownumberer' },             
-	      { header: "Time Table Name", dataIndex: 'name', flex:1, sortable : false, menuDisabled: true },
-	      { menuDisabled: true,  width: 30, renderer: function()
-		  {
-		      return '<div class="icon-remover" style="width: 15px; height: 15px;"></div>';
-		  }
-	      }
-	    ],
-	    listeners : {
-                    render : function(o,op) {
-                    var me = this;
-                    var el = me.getEl();
-                    var dropTarget = Ext.create('Ext.dd.DropTarget', el, {
-                        ddGroup: 'explorerTree',
-                        notifyOver  : function(ddSource, e, data)
-                        {
-                                if ((data.records[0].get('nodeType') == 'timeTable' || data.records[0].get('nodeType') == 'sharedtimeTable') && (data.records[0].get('leaf')))
-                                {
-                                    this.valid = true;
-                                    return this.dropAllowed;
-                                }
-                                this.valid = false;
-                                return this.dropNotAllowed;
-                        },
-                        notifyDrop  : function(ddSource, e, data) 
-                        {
-                                if (!this.valid) return false;
-						
-				var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id);
-				if (module)
-				{				    
-				  module.getUiContent().addTT(data.records[0].get('text'),data.records[0].get('id'));					    
-				} 
-			    return true;
-			  }
-                        });
-                        },
-			
-		      cellclick : function(grid, cell, cellIndex, record){
-			    if (cellIndex == 2) 
-				  grid.getStore().remove(record);
-		      }
-	    }
-          });
-	
-	var store = Ext.create('Ext.data.Store', 
-        {
-            fields: ['name', 'function'] 
-        });
-	
-	this.paramGrid = Ext.create('Ext.grid.Panel', { 
-	      title: 'Select Parameter & Apply Function',
-	      selType : 'rowmodel',
-	      height: 200,
-	      store : store, 
-	      columns: [
-	        { xtype: 'rownumberer' },
-		{ header: 'parameter',  dataIndex: 'name', menuDisabled : true, sortable : false },
-		{ header: 'function',  dataIndex: 'function', menuDisabled : true, sortable : false,
-		  editor: {
-		    xtype: 'combo', queryMode : 'local',		    
-//		    emptyText : 'please click to select function',
-		    store: [ 'min', 'max', 'mean' ],
-		    triggerAction: 'all',  		         
-//		    lazyInit: false,
-		    listeners: {
-			focus: function(obj) {
-			    obj.expand();
-			}
-		    }
-		  },
-		  renderer: function(v)
-		      {
-			  if(v != null && v.length > 0 )
-			      return v;
-			  else
-			      return 'click to select';                    
-		      } 	  
-		},
-		{ menuDisabled : true, width: 30, renderer: function(){
-			return '<div class="icon-remover" style="width: 15px; height: 15px;"></div>';
-		    }
-		}
-	      ], 
-	      plugins: [
-		Ext.create('Ext.grid.plugin.CellEditing', {
-		    clicksToEdit: 1
-		})
-	      ],
-	    listeners :
-	      {
-		render : function(o,op)
-		{
-		  var me = this;
-		  var el = me.body.dom;
-		  var dropTarget = Ext.create('Ext.dd.DropTarget', el, {
-		      ddGroup: 'explorerTree',		    
-		      notifyOver  : function(ddSource, e, data)
-		      {                                    
-			  if (data.records[0].data.nodeType == 'localParam' && data.records[0].get('notyet')) {
-			      this.valid = false;
-			      return this.dropNotAllowed;   
-			  }	
-			  if (((data.records[0].data.nodeType == 'localParam')   ||
-				      (data.records[0].data.nodeType == 'remoteParam') || 
-				      (data.records[0].data.nodeType == 'remoteSimuParam') ||
-				      (data.records[0].data.nodeType == 'derivedParam') || 
-				      (data.records[0].data.nodeType == 'myDataParam') ||
-				      (data.records[0].data.nodeType == 'alias'))&&
-				      (data.records[0].isLeaf() || data.records[0].data.isParameter) &&
-				      !data.records[0].data.disable)
-			  {
-			      this.valid = true;
-			      return this.dropAllowed;
-			  }
-			  
-			  this.valid = false;
-			  return this.dropNotAllowed;
-		      },
-		      notifyDrop  : function(ddSource, e, data)
-		      {
-			if (!this.valid)
-			  return false;
-			  var nameToSent;
-			  switch (data.records[0].data.nodeType)
-			  {
-			      case 'localParam' :
-			      case 'remoteParam':
-			      case 'remoteSimuParam':                                           
-				  nameToSent = data.records[0].get('id');
-				  if (data.records[0].get('alias')!= "" )
-				  var nameToSent = "#"+data.records[0].get('alias');
-				  break;
-			      case 'alias' :
-				  nameToSent = "#"+data.records[0].get('text');
-				  break;
-			      case 'derivedParam' :
-				  nameToSent = "ws_"+data.records[0].get('text');
-				  break;
-			      case 'myDataParam' :
-				  nameToSent = "wsd_"+data.records[0].get('text');
-				  break;
-			      default :
-				  return false;
-			  }
-		 	  var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id);
-			  if (module)
-			  {
-			      if (data.records[0].get('needsArgs') && !data.records[0].get('isSpectra')) { 				    
-				      module.getUiContent().fireEvent('openParamEditor',nameToSent);
-			      }
-			      else {
-				      module.addParam(nameToSent,true);	
-			      }
-			  }
-			return true;
-		      }
-		  });
-		},	
-		cellclick : function(grid, cell, cellIndex, record){		     
-		      if (cellIndex == 3) 
-			    grid.getStore().remove(record);
-		}
-	      }    
-	}); 
-       
-	this.catalogGrid =  Ext.create('Ext.grid.Panel', { 
-	      title: 'Catalog', 
-	      height: 500,
+
+	this.TTGrid =  Ext.create('Ext.grid.Panel', { 
+//	      title: 'Catalog', 
+	      height: 530,
 	      columns: [
 		{ text: '',  dataIndex: '' }
 	    
-	  ]
+	      ],
+	      frame: true,
+	      dockedItems: [{
+                xtype: 'toolbar', 
+                items: [{
+                    iconCls: 'icon-add',
+                    scope: this,
+                    handler: function(){
+//                         cellEditing.cancelEdit();
+//                         
+//                         var selection = this.TTGrid.getView().getSelectionModel().getSelection()[0];
+//                         var row = 0;
+//                         if (selection)
+//                         	row = store.indexOf(selection) + 1;
+//                         this.TTGrid.getSelectionModel().deselectAll();
+//                         
+//                         var me = this;
+//                         AmdaAction.addTTCacheInterval({'index' : row}, function (result, e) {
+//                         	this.status = result.status;
+//                         	this.TTGrid.getStore().reload({
+//                         		callback : function(records, options, success) {
+//                         			me.TTGrid.getView().bufferedRenderer.scrollTo(row, false, function() {
+//                         				me.TTGrid.getView().select(row);
+//                         				cellEditing.startEditByPosition({row: row, column: 1});	
+//                         			}, me);	
+//                         		}
+//                         	});
+//                         }, this);
+                    }
+                }, {
+                    iconCls: 'icon-delete',
+                    disabled: true,
+                    itemId: 'delete',
+                    scope: this,
+                    handler:  function(){
+//                         var selection = this.TTGrid.getView().getSelectionModel().getSelection()[0];
+//                         if (selection) {
+//                         	var rowId = selection.get('cacheId');
+//                         	this.TTGrid.getSelectionModel().deselectAll();
+//                         	AmdaAction.removeTTCacheIntervalFromId(rowId, function (result, e) {
+//                         		this.status = result.status;
+//                             	this.TTGrid.getStore().reload();
+//                             }, this);
+//                         }
+                    }
+                }]
+	      }]
 	});
  
 	  this.formPanel =  Ext.create('Ext.form.Panel', { 
-	      height: 550,
-	      width: 800,
-	      layout:  'border',
-	      defaults: { layout: 'fit', border: false },
+	      region : 'center',
+	      layout:  'hbox', 
+	      bodyStyle: {background : '#dfe8f6'},
+	      defaults: { border : false, align: 'stretch', bodyStyle: {background : '#dfe8f6'},  padding: '3'},
 	      fieldDefaults: { labelWidth: 80, labelAlign : 'top' },
 	      items: [ 
 		{            
-		    xtype: 'form',
-		    region: 'center',           
+		    xtype: 'form',		            
 		    flex: 1,
 		    buttonAlign: 'left',
-		    bodyStyle: {background : '#dfe8f6'},
-		    padding: '5 5 5 5',
+//		    title : 'Information',		   
 		    layout: {type: 'vbox', pack: 'start', align: 'stretch'},
 		    items : [
-		      this.fieldName,
-		    {
+		     this.fieldName,
+		      {
 		      xtype: 'fieldcontainer',
 		      layout: 'hbox',		      
 		      items: [
@@ -328,65 +349,111 @@ Ext.define('amdaUI.CatalogUI', {
 			  },			  
 			  { xtype: 'splitter' },			 			 
 			  { xtype:'textfield', fieldLabel: 'Intervals', name: 'nbIntervals', disabled: true}
-		      ]                                                                       
-		  },
-		  {
-		      xtype: 'textarea',
-		      name: 'description',
-		      fieldLabel: 'Description',
-//		      anchor: '100% 50%'
-		  },		  		    
-		   
-		      this.paramGrid,
-		      this.ttGrid
-		    ],
-		    fbar:[
-			{   
-			    type: 'button',
-			    text: 'Generate Catalog',
-			    scope : this,
-			    handler: function(button){
-                            // update object with user's values
-                            // if the return is true (object had been updated)
-                         //   if(this.updateObject()){ 
-			        this.updateObject();
-                                this.generateCatalog();			   			 
-                        //    }
-                        }
-			},
-			{   
-			    type: 'button',
-			    text: 'Reset' 
-			} 
-		      ]
+			]                                                                       
+		      },
+		      {
+			  xtype: 'textarea',
+			  name: 'description',
+			  fieldLabel: 'Description',
+			  height: 200
+		      },
+		      {
+			  xtype: 'component',
+			  height: 180
+		      }
+		      ],
+		      fbar:[
+			  {   
+			      type: 'button',
+			      text: 'Save',
+			      scope : this,
+			      handler: function () {
+                            	if (this.updateObject()){
+				       
+                            		var basicForm = this.formPanel.getForm();      
+                            		// if there's at least one record in the store of TTGrid
+                            		if (this.TTGrid.getStore().getTotalCount() > 0) {
+                            			// update TimeTable object which the content of form
+                            			basicForm.updateRecord(this.object);
+
+                            			var me = this;
+                            			this.checkIntervalsStatusForSave(function () {
+						    //Name validation
+						    var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.catalog.id);	
+						    if (!module)
+							    return;
+						    module.linkedNode.isValidName(me.fieldName.getValue(), function (res) {
+							    if (!res)
+							    {
+								    me.fieldName.validFlag = 'Error during object validation';
+								    myDesktopApp.errorMsg(me.fieldName.validFlag);
+								    me.fieldName.validate();
+								    return;
+							    }
+									      
+							    if (!res.valid)
+							    {
+								    if (res.error)
+								    {
+									    if (res.error.search('subtree') != -1) {  							
+										    Ext.MessageBox.show({title:'Warning', 
+											    msg: res.error+'<br/>Do you want to overwrite it?',
+											    width: 300,
+											    buttons: Ext.MessageBox.OKCANCEL, 
+											    fn : me.overwriteProcess,
+											    icon: Ext.MessageBox.WARNING,
+											    scope : me
+										    });
+										    me.fieldName.validFlag = true;
+									    }
+									    else
+										    me.fieldName.validFlag = res.error;
+								    }
+								    else
+								    {
+									    me.fieldName.validFlag = 'Invalid object name';
+									    myDesktopApp.errorMsg(me.fieldName.validFlag);
+								    }
+								    me.fieldName.validate();
+								    return;
+							    }
+									      
+							    me.fieldName.validFlag = true;
+							    me.fieldName.validate();
+							    me.saveProcess(false);
+						    });
+                            			});                            
+  				              } else {
+  				                // warning:
+  				                Ext.Msg.alert('No intervals', 'Your time table is invalid, <br>you must have at least one interval');
+  				              }
+                                    }
+                           } 
+			  },{   
+			      type: 'button',
+			      text: 'Share',
+			      disabled: true 
+			  },
+			  {   
+			      type: 'button',
+			      text: 'Visualize' 
+			  } 
+			]
 		}, {
-		    xtype: 'form',
-		    region: 'east',            
+		    xtype: 'form',		               
 		    bodyStyle: {background : '#dfe8f6'},
-		    padding: '5 5 5 5',
+//		    padding: '3',
 		    flex: 2,
 		    items : [
-		      this.catalogGrid
-		    ],
-		    fbar:[
-			{   
-			    type: 'button',
-			    text: 'Save' 
-			},{   
-			    type: 'button',
-			    text: 'Share',
-			    disabled: true 
-			},
-			{   
-			    type: 'button',
-			    text: 'Visualize' 
-			} 
-		      ]
+		      this.TTGrid
+		    ] 
 		}
 	    ]  
 	  }); 
 	 
-	 
+	 this.TTGrid.getSelectionModel().on('selectionchange', function(selModel,selections){
+	        this.TTGrid.down('#delete').setDisabled(selections.length === 0); 
+        }, this); 
 	
 	var myConf = {
 		    layout: 'border',
diff --git a/js/app/views/StatisticsUI.js b/js/app/views/StatisticsUI.js
new file mode 100644
index 0000000..556a937
--- /dev/null
+++ b/js/app/views/StatisticsUI.js
@@ -0,0 +1,343 @@
+/**
+ * Project       AMDA-NG
+ * Name          StatisticsUI.js
+ * @class 	 amdaUI.statisticsUI
+ * @extends      Ext.container.Container
+ * @brief	 Statistics Module UI definition (View)
+ * @author 	 elena
+ */
+
+Ext.define('amdaUI.StatisticsUI', {
+	extend: 'Ext.container.Container',
+	alias: 'widget.panelStatistics',
+	
+	requires : [	
+//	  'amdaModel.Function'
+          'amdaUI.TimeSelectorUI'
+	],
+	
+	statics : {	 
+//	  functionStore : null
+	},
+		
+	constructor: function(config) {
+	        this.init(config); 
+		this.callParent(arguments);
+	//	if (this.object) this.loadObject();
+	},
+	
+	addParam : function(ParamName,isLeaf) 
+        {                        	 
+	    var r = Ext.create('amdaModel.AmdaObject', { name: ParamName });
+	    this.paramGrid.getStore().add(r);
+	    this.paramGrid.getSelectionModel().select(this.paramGrid.getStore().getCount()-1);  
+        },
+	
+	addTT : function(TTname,TTid)
+	{ 
+	    this.timeSelector.addTT(TTname, TTid); ; 
+	 
+	},
+	 
+	generateCatalog : function(){	     
+	  var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.statistics.id);
+	  if (module) 
+		module.linkedNode.execute();	     
+	},
+	
+	/**
+	 * update this.object from form
+	 */
+	
+	updateObject : function(){    
+	    // get the basic form of the left 
+	    var basicForm = this.formPanel.items.items[0].getForm();
+	    var updateStatus = true;
+	    
+	    var formValues = basicForm.getValues();
+	//    this.object.set('name',formValues.name);
+	//    this.object.set('description',formValues.description);
+	    	    	    
+	    var recs = this.paramGrid.getStore().getNewRecords();
+	    var paramArr = new Array();
+	    Ext.Array.each(recs, function(rec, index,allItems){
+	      var obj =  new Object();
+	      obj.param = rec.get('name');
+	      obj.function = rec.get('function');
+              paramArr.push(obj);            	      
+	    });
+	    this.object.set('parameter', paramArr);
+	    
+	    var timeSource = formValues.timesrc_statisticsTimeSelector; 
+
+	    if (timeSource === amdaModel.AmdaTimeObject.inputTimeSrc[0] // timeSource  'TimeTable'
+                        && this.timeSelector.TTGrid.getStore().count() == 0) {
+                    myDesktopApp.warningMsg('You\'ve chosen Time Selection `by TimeTable` but no timeTable was added!'
+                            +'<br>You must add one or choose Time Selection `by Interval`'); 
+                    return false;    
+              }
+             
+	    // basicForm.updateRecord(this.object);
+	    this.object.set('timesrc', timeSource);
+	    // set valid intervals into TimeTable object
+	    if (timeSource === amdaModel.AmdaTimeObject.inputTimeSrc[0])
+		    this.object.set('timeTables',this.timeSelector.TTGrid.getStore().data.items);          
+	  	      
+	    return updateStatus;	    
+	},
+	
+	/**
+	 * Check if changes were made before closing window 
+	 * @return true if changes
+	 */	
+	fclose : function() {
+		if (this.status == null)
+			return false;
+		
+		var isDirty = this.formPanel.getForm().isDirty() || (this.status.isModified) || (this.status.nbModified > 0) || (this.status.nbNew > 0);
+		return isDirty;
+	},
+	
+	/**
+	 * View configuration
+	 */
+	init : function (config) {
+	  
+// 	  var functions = Ext.create('Ext.data.Store', {
+// 	    fields: ['id', 'name'],
+// 	    data : [
+// 		{"id":"min", "name":"MIN"},
+// 		{"id":"max", "name":"MAX"},
+// 		{"id":"mean","name":"MEAN"}        
+// 	    ]
+// 	    });
+	     
+	  this.fieldName = new Ext.form.field.Text({
+	      fieldLabel: 'Catalog Name',
+	      allowBlank : false,
+	      stripCharsRe: /(^\s+|\s+$)/g,
+	      emptyText: 'Please no spaces!',
+	      name: 'name',
+//	      anchor: '100%',
+	      validateOnChange: false,
+	      validateOnBlur: false,
+	      validFlag: false,
+		  validator : function() {
+		      return this.validFlag;
+		  }
+	  });
+	  
+	var ttStore = Ext.create('Ext.data.Store', 
+	  {
+	      fields: [ 'name', 'hidden_id']	
+	  });
+	  
+	this.timeSelector = new amdaUI.TimeSelectorUI({id: 'statisticsTimeSelector', height : 160}); 
+	
+	var store = Ext.create('Ext.data.Store', 
+        {
+            fields: ['name', 'function'] 
+        });
+	
+	this.paramGrid = Ext.create('Ext.grid.Panel', { 
+	      title: 'Select Parameter & Apply Function',
+	      selType : 'rowmodel',
+//	      flex: 2,
+	      height :250,
+	      store : store, 
+	      columns: [
+	        { xtype: 'rownumberer' },
+		{ header: 'parameter',  dataIndex: 'name', menuDisabled : true, sortable : false },
+		{ header: 'function',  dataIndex: 'function', menuDisabled : true, sortable : false,
+		  editor: {
+		    xtype: 'combo', queryMode : 'local',		    
+//		    emptyText : 'please click to select function',
+		    store: [ 'min', 'max', 'mean' ],
+		    triggerAction: 'all',  		         
+//		    lazyInit: false,
+		    listeners: {
+			focus: function(obj) {
+			    obj.expand();
+			}
+		    }
+		  },
+		  renderer: function(v)
+		      {
+			  if(v != null && v.length > 0 )
+			      return v;
+			  else
+			      return 'click to select';                    
+		      } 	  
+		},
+		{ menuDisabled : true, width: 30, renderer: function(){
+			return '<div class="icon-remover" style="width: 15px; height: 15px;"></div>';
+		    }
+		}
+	      ], 
+	      plugins: [
+		Ext.create('Ext.grid.plugin.CellEditing', {
+		    clicksToEdit: 1
+		})
+	      ],
+	    listeners :
+	      {
+		render : function(o,op)
+		{
+		  var me = this;
+		  var el = me.body.dom;
+		  var dropTarget = Ext.create('Ext.dd.DropTarget', el, {
+		      ddGroup: 'explorerTree',		    
+		      notifyOver  : function(ddSource, e, data)
+		      {                                    
+			  if (data.records[0].data.nodeType == 'localParam' && data.records[0].get('notyet')) {
+			      this.valid = false;
+			      return this.dropNotAllowed;   
+			  }	
+			  if (((data.records[0].data.nodeType == 'localParam')   ||
+				      (data.records[0].data.nodeType == 'remoteParam') || 
+				      (data.records[0].data.nodeType == 'remoteSimuParam') ||
+				      (data.records[0].data.nodeType == 'derivedParam') || 
+				      (data.records[0].data.nodeType == 'myDataParam') ||
+				      (data.records[0].data.nodeType == 'alias'))&&
+				      (data.records[0].isLeaf() || data.records[0].data.isParameter) &&
+				      !data.records[0].data.disable)
+			  {
+			      this.valid = true;
+			      return this.dropAllowed;
+			  }
+			  
+			  this.valid = false;
+			  return this.dropNotAllowed;
+		      },
+		      notifyDrop  : function(ddSource, e, data)
+		      {
+			if (!this.valid)
+			  return false;
+			  var nameToSent;
+			  switch (data.records[0].data.nodeType)
+			  {
+			      case 'localParam' :
+			      case 'remoteParam':
+			      case 'remoteSimuParam':                                           
+				  nameToSent = data.records[0].get('id');
+				  if (data.records[0].get('alias')!= "" )
+				  var nameToSent = "#"+data.records[0].get('alias');
+				  break;
+			      case 'alias' :
+				  nameToSent = "#"+data.records[0].get('text');
+				  break;
+			      case 'derivedParam' :
+				  nameToSent = "ws_"+data.records[0].get('text');
+				  break;
+			      case 'myDataParam' :
+				  nameToSent = "wsd_"+data.records[0].get('text');
+				  break;
+			      default :
+				  return false;
+			  }
+		 	  var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.statistics.id);
+			  if (module)
+			  {
+			      if (data.records[0].get('needsArgs') && !data.records[0].get('isSpectra')) { 				    
+				      module.getUiContent().fireEvent('openParamEditor',nameToSent);
+			      }
+			      else {
+				      module.addParam(nameToSent,true);	
+			      }
+			  }
+			return true;
+		      }
+		  });
+		},	
+		cellclick : function(grid, cell, cellIndex, record){		     
+		      if (cellIndex == 3) 
+			    grid.getStore().remove(record);
+		}
+	      }    
+	}); 
+      	
+ 
+	  this.formPanel =  Ext.create('Ext.form.Panel', { 
+	      region: 'center',	     
+	      layout:  'hbox',
+//	      bodyStyle: {background : '#dfe8f6'},
+	      defaults: { bodyStyle: {background : '#dfe8f6'}, padding : '3'},
+	      fieldDefaults: { labelWidth: 80, labelAlign : 'top' },
+	      items: [ 	  		    
+		{  
+		    xtype: 'form',
+		    flex : 1,			    
+		    layout: {type: 'vbox', pack: 'start', align: 'stretch'},
+		    items : [
+		      this.paramGrid,
+		      this.timeSelector
+		    ]
+		},
+		{            
+		    xtype: 'form', 
+		    title: 'Additional Information', 
+		    flex : 1,
+		    layout: {type: 'vbox', pack: 'start', align: 'stretch', padding : '3'},
+		    items : [
+		      this.fieldName,
+		      {
+			xtype: 'textarea',
+			name: 'description',
+			fieldLabel: 'Description', 			
+			height: 200
+		      }   
+		    ],
+		    fbar:
+		        [
+			{   
+			    type: 'button',			   
+			    text: 'Generate Catalog',
+			    scope : this,
+			    handler: function(){
+                            // update object with user's values
+                            // if the return is true (object had been updated)
+                         //   if(this.updateObject()){ 
+			        this.updateObject();
+                                this.generateCatalog();			   			 
+                        //    }
+                        }
+			},
+			{   
+			    type: 'button',
+			    text: 'Reset',
+			    scope : this,
+			    handler: function() {
+			    }
+			} 
+		      ]
+		}
+	    ]  
+	  }); 
+	 
+	 
+	
+	var myConf = {
+		    layout: 'border',
+		    items: [		   
+			  this.formPanel, 		     
+			  {
+			    xtype: 'panel', 
+			    region: 'south',
+			    title: 'Information',
+			    collapsible: true,
+			    height: 100,
+			    autoHide: false,
+			    bodyStyle: 'padding:5px',
+			    iconCls: 'icon-information',
+			      loader: {
+				autoLoad: true,
+				url: helpDir+'downloadHOWTO'
+			      } 
+			  }
+		    ] 
+	      };
+	    
+	    Ext.apply (this, Ext.apply(arguments, myConf));	
+    }
+	 
+});	
diff --git a/js/app/views/TabResultUI.js b/js/app/views/TabResultUI.js
index d42fa32..773120b 100644
--- a/js/app/views/TabResultUI.js
+++ b/js/app/views/TabResultUI.js
@@ -37,6 +37,8 @@ Ext.define('amdaUI.TabResultUI', {
 			    break;	   
 	  case 'download': var title = 'Download Results';
 			    break;
+	  case 'statistics': var title = 'Statistics Results';
+			    break;
 	  default:
 	}
         var newConfig = {
@@ -54,7 +56,7 @@ Ext.define('amdaUI.TabResultUI', {
 	      scope : this,
 	      beforeclose : function() {
 		//delete linked nodes connected to ResultModule and corresponding to this Tab
-		       var module = myDesktopApp.getLoadeModule(myDesktopApp.dynamicModules.result.id);
+		       var module = myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.result.id);
 		       if (module.linkedNodes) {
 			  var indices = new Array();
 			  var i =0;
@@ -105,6 +107,16 @@ Ext.define('amdaUI.ResultItem', {
     		  this);       
     },
     
+    saveCatalog: function(folderId,ttName) {    
+      this.linkedNode = Ext.create('amdaModel.CatalogNode',{leaf : true});
+      AmdaAction.getTmpObject(
+    		  folderId,
+    		  ttName,
+    		  this.linkedNode.get('nodeType'),
+    		  this.getResultCallback,
+    		  this);       
+    },
+    
     getResultCallback : function(result,remoteEvent){//result, e) {
         var t = remoteEvent.getTransaction();
         //AKKA - catch error
@@ -120,8 +132,8 @@ Ext.define('amdaUI.ResultItem', {
         	return;
         }
         
-        var paramObj = Ext.create(this.linkedNode.get('objectDataModel'), result);	 
-        paramObj.set('fromPlugin',true);
+        var paramObj = Ext.create(this.linkedNode.get('objectDataModel'), result);
+         paramObj.set('fromPlugin',true);
          paramObj.set('intervals',result.intervals);
         // set parameter into node
         this.linkedNode.set('object',paramObj);
@@ -130,7 +142,7 @@ Ext.define('amdaUI.ResultItem', {
 	myDesktopApp.getLoadedModule(myDesktopApp.dynamicModules.result.id, true, function (module) {
 		module.setLinkedNode(me.linkedNode);
 		// Edition of parameter into parameter Module	    
-		me.linkedNode.editInModule();
+		   me.linkedNode.editInModule();
 	});
     },
     
@@ -251,6 +263,35 @@ Ext.define('amdaUI.ResultItem', {
 		}
 	     ]
 	  };
+	  var configCat = {
+	    intId : config.title, 
+	    height : height,	
+	    title: jobtitle,
+	    collapsible: true,
+	    defaultType: 'button',
+	    items :[
+	         {
+		   xtype: 'label',
+		   text: 'Catalog '
+		 }, 
+		{
+		text: 'Edit/Save',
+		scope : this,
+		handler: function() {
+			  this.saveCatalog(config.folderId,config.resultId);
+		  }
+		}, 
+	        {
+		text: 'Delete',
+		scope : this,
+		handler: function() {
+		      this.delete(config.processId);
+		      this.ownerCt.remove(this);
+		  }
+		}
+	     ]
+	  };
+	  
 //TODO make this properly
 	  	  
 	  var configPlot = {
@@ -329,6 +370,9 @@ Ext.define('amdaUI.ResultItem', {
 	    case 'condition' : 
 			      Ext.apply(this, configTT);	
 			    break;
+	    case 'statistics' : 
+			      Ext.apply(this, configCat);	
+			    break;
 	    case 'request' : 		      
 			      Ext.apply(this, configPlot);
 			    break; 
diff --git a/js/app/views/TimeTableUI.js b/js/app/views/TimeTableUI.js
index 435ff86..536e150 100755
--- a/js/app/views/TimeTableUI.js
+++ b/js/app/views/TimeTableUI.js
@@ -30,6 +30,7 @@ Ext.define('amdaUI.TimeTableUI', {
     },
        
     status: null,
+    isCatalog : false,
     
 	constructor: function(config) {          	 
 		this.init(config);
@@ -116,7 +117,7 @@ Ext.define('amdaUI.TimeTableUI', {
         	else
         	{
         		//From tmp object (ie Search result)
-        		AmdaAction.initTTCacheFromTmpObject(this.object.get('folderId'), this.object.get('objName'), onAfterInit);
+        		AmdaAction.initTTCacheFromTmpObject(this.object.get('folderId'), this.object.get('objName'), this.isCatalog, onAfterInit);
         	}
         }
         else
diff --git a/js/resources/css/amda.css b/js/resources/css/amda.css
index 42fb0b1..efdecb3 100644
--- a/js/resources/css/amda.css
+++ b/js/resources/css/amda.css
@@ -79,6 +79,10 @@
     background-image:url( ../images/16x16/search.png ) !important;
 }
 
+.icon-statistics {
+    background-image:url( ../images/16x16/statistics.png ) !important;
+}
+
 .icon-manage-ws {
     background-image:url( ../images/16x16/wsManager.png ) !important;
 }
@@ -385,3 +389,8 @@ p + p {
   font-style: italic !important;
   font-weight: bold !important;
 }
+
+.x-item-disabled .x-form-item-label {
+	filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100) !important;
+	opacity: 1.0 !important;
+}
diff --git a/js/resources/images/16x16/statistics.png b/js/resources/images/16x16/statistics.png
new file mode 100644
index 0000000..cf014cb
Binary files /dev/null and b/js/resources/images/16x16/statistics.png differ
diff --git a/js/resources/images/16x16/visu_catalog.png b/js/resources/images/16x16/visu_catalog.png
new file mode 100644
index 0000000..fabbb71
Binary files /dev/null and b/js/resources/images/16x16/visu_catalog.png differ
diff --git a/js/resources/images/64x64/statistics.png b/js/resources/images/64x64/statistics.png
new file mode 100644
index 0000000..4ef1fb3
Binary files /dev/null and b/js/resources/images/64x64/statistics.png differ
diff --git a/js/resources/images/64x64/visu_catalog.png b/js/resources/images/64x64/visu_catalog.png
new file mode 100644
index 0000000..ef79fda
Binary files /dev/null and b/js/resources/images/64x64/visu_catalog.png differ
diff --git a/php/classes/AmdaAction.php b/php/classes/AmdaAction.php
index 6abc472..d311923 100644
--- a/php/classes/AmdaAction.php
+++ b/php/classes/AmdaAction.php
@@ -581,7 +581,10 @@ class AmdaAction {
 	    switch ($nodeType) {
 		  case 'timeTable' : 
 			   $objectMgr = new TimeTableMgr();		  
-			   break;		  
+			   break; 
+		 case 'catalog' :
+			   $objectMgr = new CatalogMgr();		  
+			   break; 	   
 		  default:
 			    return array("error" => $nodeType." NOT_IMPLEMENTED_YET");
               }
@@ -631,6 +634,9 @@ class AmdaAction {
 			   break;
 		  case 'timeTable' : 
 			   $objectMgr = new TimeTableMgr();			  
+			   break; 
+		  case 'catalog' : 
+			   $objectMgr = new CatalogMgr();			  
 			   break;
 		  case 'condition' : 		  
 		  case 'request' :
@@ -667,6 +673,9 @@ class AmdaAction {
 			   break;
 		  case 'timeTable' : 
 			   $objectMgr = new TimeTableMgr();			  
+			   break;
+		  case 'catalog' : 
+			   $objectMgr = new Catalog();			  
 			   break;		  
 		  case 'condition' : 
 		  case 'request' : 
@@ -698,6 +707,9 @@ class AmdaAction {
                         break;		  
 		  case 'timeTable' : 
                         $objectMgr = new TimeTableMgr();			  
+			   break; 
+		  case 'catalog' : 
+                        $objectMgr = new CatalogMgr();			  
 			   break;
 		  case 'condition' :
 		  case 'request' : 
@@ -726,7 +738,10 @@ class AmdaAction {
 			   break;
 		  case 'timeTable' : 
 			   $objectMgr = new TimeTableMgr();			  
-			   break;  
+			   break;
+		  case 'catalog' : 
+			   $objectMgr = new CatalogMgr();			  
+			   break;  	   
 		  case 'condition' : 
 		  case 'request' :
 			   $objectMgr = new RequestMgr($obj->nodeType);			  
@@ -747,8 +762,12 @@ class AmdaAction {
 				$objectMgr = new DerivedParamMgr($obj->nodeType);
 				break;
 			case 'timeTable' :
+			case 'sharedtimeTable' :
 				$objectMgr = new TimeTableMgr();
 				break;
+			case 'catalog' :
+				$objectMgr = new CatalogMgr();
+				break;
 			case 'condition' :
 			case 'request' :
 				$objectMgr = new RequestMgr($obj->nodeType);
@@ -927,15 +946,27 @@ class AmdaAction {
         	return $cacheMgr->initTTCache();
         }
         
+//         public function initCatalogGridFromTmpObject($folderId, $name)
+//         {
+//         	$objMgr = new CatalogMgr();
+//         	return $objMgr->initCatalogGridFromTmpObject($folderId, $name);
+//         }
+        
         public function initTTCacheFromTT($id, $type)
         {
         	$cacheMgr = new TimeTableCacheMgr();
         	return $cacheMgr->initFromTT($id, $type);
         }
         
-        public function initTTCacheFromTmpObject($folderId, $name)
+        public function initTTCacheFromTmpObject($folderId, $name, $isCatalog = false)
         {
-        	$cacheMgr = new TimeTableCacheMgr();
+        	error_reporting(E_ERROR | E_WARNING | E_PARSE); 
+			if (!$isCatalog) $cacheMgr = new TimeTableCacheMgr();
+				 
+			else              $cacheMgr = new CatalogCacheMgr();
+					   
+			 
+		
         	return $cacheMgr->initFromTmpObject($folderId, $name);
         }
         
@@ -947,7 +978,9 @@ class AmdaAction {
         
         public function readTTCacheIntervals($o)
         {
-        	$cacheMgr = new TimeTableCacheMgr();
+        	if ($o->typeTT == 'catalog') $cacheMgr = new CatalogCacheMgr();
+        	else $cacheMgr = new TimeTableCacheMgr();
+        	
         	return $cacheMgr->getIntervals($o->start,$o->limit,$o->sort,$o->filter);
         }
     
@@ -1201,8 +1234,8 @@ class AmdaAction {
         //AKKA - New action to clean user WS
         public function cleanUserWS()
         {
-        	require_once(INTEGRATION_SRC_DIR."RequestManager.php");
-        	return $this->executeRequest($obj, FunctionTypeEnumClass::PROCESSCLEAN);
+//         	require_once(INTEGRATION_SRC_DIR."RequestManager.php");
+//         	return $this->executeRequest($obj, FunctionTypeEnumClass::PROCESSCLEAN);
         }
 
         public function deleteSpecialInfo($name)
diff --git a/php/classes/CatalogCacheMgr.php b/php/classes/CatalogCacheMgr.php
new file mode 100644
index 0000000..5aaf7f4
--- /dev/null
+++ b/php/classes/CatalogCacheMgr.php
@@ -0,0 +1,319 @@
+<?php
+
+/**
+ * @class CatalogCacheMgr
+ */
+ 
+ 
+class CatIntervalCacheObject extends IntervalCacheObject
+{
+        // for catalog   
+	private $params      = array();
+	
+	public function toArray() {
+		$result = array(
+			"cacheId" => $this->id,
+			"start"   => $this->getStartToISO(),
+			"stop"    => $this->getStopToISO()
+		);
+		if ($this->isNew)
+			$result["isNew"] = true;
+		if ($this->isModified)
+			$result["isModified"] = true;
+			
+		for ($i = 0; $i < count($this->params); $i++) {
+		    $paramObject = array();
+		    $index = 'param'.sprintf("%d",$i+2);
+		    $result[$index] = $this->params[$i];		    
+		}		 
+		return $result; 
+	}
+
+	// for catalog 
+	public function setParams($params) {
+	    $this->params = $params;
+		
+	}
+	
+	public function getParams() {		  	   
+	   return $this->params;		
+	}
+			
+	public function writeBin($handle, $paramsNumber, $paramsSizes) {
+	       fwrite($handle,pack('L6',$this->id,$this->index,$this->start,$this->stop,$this->isNew,$this->isModified));
+	       for ($i = 0; $i < $paramsNumber; $i++) {
+	         $paramString = $this->params[$i];
+	         $paramArray =  explode(',',$this->params[$i]);
+	         for ($j = 0; $j < $paramsSizes[$i]; $j++) fwrite($handle,pack('d', $paramArray[$j]));
+	       }
+	        
+	}
+	
+	public function loadBin($handle, $paramsNumber, $paramsSizes) {
+		$array = unpack('L6int',fread($handle,6*4));
+		$this->id         = $array['int1'];
+		$this->index      = $array['int2'];
+		$this->start      = $array['int3'];
+		$this->stop       = $array['int4'];
+		$this->isNew      = $array['int5'];
+		$this->isModified = $array['int6'];
+		
+		for ($i = 0; $i < $paramsNumber; $i++) {
+		  $this->params[$i] = null;
+		  for ($j = 0; $j < $paramsSizes[$i]; $j++) {
+			  $val = unpack('dval',fread($handle,8));
+			  $this->params[$i] .= $val['val'];
+			  if ($j != $paramsSizes[$i] - 1) $this->params[$i] .= ',';
+		      }		       
+		}
+		 
+	}
+	
+	public function dump() {
+		echo " => Interval : id = ".$this->id.", index = ".$this->index.", start = ".$this->start.", stop = ".$this->stop.", isNew = ".$this->isNew.", isModified = ".$this->isModified.PHP_EOL;
+	}
+} 
+ 
+class CatalogCacheObject extends TimeTableCacheObject
+{
+        private $paramsNumber;
+        private $paramsSizes = array();
+        
+	public function addInterval($startIso, $stopIso, $params, $isNew = false, $index = -1) {
+			$interval = new CatIntervalCacheObject($this->lastId, count($this->intervals));
+			++$this->lastId;
+			$interval->setStartFromISO($startIso);
+			$interval->setStopFromISO($stopIso);
+			// for catalog
+			$interval->setParams($params);
+
+			$interval->setIsNew($isNew);
+			array_push($this->intervals, $interval);
+			if ($index < 0)
+				array_push($this->indexes, count($this->intervals) - 1);
+			else
+				array_splice($this->indexes, $index, 0, array(count($this->intervals) - 1));
+			if ($isNew)
+				$this->isModified = true;
+				
+			return $interval;
+	}
+    
+	public function setParamsNumber($number){
+	    $this->paramsNumber = $number;
+	}
+	
+	public function setParamsSizes($params){
+	    for ($i = 0; $i < $this->paramsNumber; $i++)	         
+		  $this->paramsSizes[$i] = $params[$i]['size'];		   
+	}
+	
+	public function writeBin($handle) {
+	  //Magic key ("TTC")
+	  fwrite($handle,pack('C3',ord('T'),ord('T'),ord('C')));
+	  
+	  //Version
+	  fwrite($handle,pack('L',TimeTableCacheObject::$format_version));
+	  
+	  //Token
+	  for ($i = 0; $i < TimeTableCacheObject::$token_len; ++$i)
+		  fwrite($handle,pack('C',ord($this->token[$i])));
+	  
+	  //Modified
+	  fwrite($handle,pack('L',$this->isModified));
+	  
+	  //Filter
+	  $this->filter->writeBin($handle);
+	  
+	  //Sort
+	  $this->sort->writeBin($handle);
+	  
+	  //Params Number
+          fwrite($handle,pack('L',$this->paramsNumber));
+	
+          //Params Sizes
+          for ($i = 0; $i < $this->paramsNumber; $i++) 
+		  fwrite($handle,pack('L',$this->paramsSizes[$i]));
+          
+	  //Intervals
+	  fwrite($handle,pack('L2',count($this->intervals), $this->lastId));
+	  
+
+	  foreach($this->intervals as $interval)
+		  $interval->writeBin($handle,$this->paramsNumber,$this->paramsSizes);
+	  
+	  //Indexes
+	  fwrite($handle,pack('L',count($this->indexes)));
+	  foreach($this->indexes as $index)
+		  fwrite($handle,pack('L',$index));
+    }
+    
+    public function loadBin($handle) {
+		//Magic key ("TTC")
+		if (!$res = unpack('C3key',fread($handle,3)))
+			return false;
+		
+		if (($res['key1'] != ord('T')) || ($res['key2'] != ord('T')) || ($res['key3'] != ord('C')))
+			return false;
+		
+		//Version
+		if (!$res = unpack('Lversion',fread($handle,4)))
+			return false;
+		if (($res['version'] != TimeTableCacheObject::$format_version))
+			return false;
+
+		//Token
+		$token = "";
+		for ($i = 0; $i < TimeTableCacheObject::$token_len; ++$i)
+		{
+			if (!$res = unpack('Ctoken',fread($handle,1)))
+				return false;
+			$token .= chr($res['token']);
+		}
+		$this->token = $token;
+		
+		//Modified
+		if (!$res = unpack('Lmodified',fread($handle,4)))
+			return false;
+		$this->isModified = $res['modified'];
+		
+		//Filter
+		$this->filter->loadBin($handle);
+		
+		//Sort
+		$this->sort->loadBin($handle);
+		
+		//ParamsNumber
+		if (!$res = unpack('Lnumber',fread($handle,4)))
+			return false;
+		$this->paramsNumber = $res['number'];
+	
+		//ParamsSizes
+		for ($i = 0; $i < $this->paramsNumber; $i++) {
+		  if (!$res = unpack('Lsize',fread($handle,4)))
+			  return false;
+		  $this->paramsSizes[$i] = $res['size'];
+		}
+
+		//Intervals
+		$res = unpack('L2data',fread($handle,2*4));
+		$nbIntervals  = $res['data1'];
+		$this->lastId = $res['data2'];
+		
+		for ($i = 0; $i < $nbIntervals; ++$i)
+		{
+			$interval = new CatIntervalCacheObject(-1);
+			$interval->loadBin($handle, $this->paramsNumber, $this->paramsSizes);			
+			array_push($this->intervals, $interval);
+		}
+		 
+		//Indexes
+		$res = unpack('Ldata',fread($handle,4));
+		$nbIndexes  = $res['data'];
+		for ($i = 0; $i < $nbIndexes; ++$i)
+		{
+			$res = unpack('Lindex',fread($handle,4));
+			array_push($this->indexes, $res['index']);
+		}
+		
+		return true;
+	}
+
+}
+
+class CatalogCacheMgr extends TimeTableCacheMgr 
+{
+		
+	protected static $cache_file                = "cacheCat";
+	
+	protected $ttMgr = null;
+	protected $cache = null;
+
+	function __construct() {
+	         	        
+		$this->ttMgr = new CatalogMgr();
+	}
+	
+	
+	public function initFromTmpObject($folderId, $name) {
+	 
+		//Create new cache		 
+		$this->cache = new CatalogCacheObject();
+
+		//Load intervals from TmpObject file (Statistics Module)
+		$intervals_res = $this->ttMgr->getTmpObject($folderId, $name);
+ 
+		if (!isset($intervals_res))
+			return array('success' => false, 'message' => 'Cannot get Tmp Object');
+
+		if (array_key_exists('intervals', $intervals_res))
+		{
+			foreach ($intervals_res['intervals'] as $interval)
+			{
+				//Add interval
+				$this->cache->addInterval($interval['start'], $interval['stop'], $interval['paramTable']);
+				
+			}
+		}
+
+		$this->cache->setIsModified(true);
+		
+		$paramHeaders = $intervals_res['parameters'];
+		
+		$this->cache->setParamsNumber(count($paramHeaders));
+		$this->cache->setParamsSizes($paramHeaders);
+		
+		unset($intervals_res);		
+		
+		//Update cache
+		$this->cache->updateIndexes();
+
+		//Save cache file
+		return array('success' => $this->saveToFile(), 'token' => $this->cache->getToken(), 
+		             'status' => $this->cache->getStatus(), 'parameters' => $paramHeaders);
+	}
+	
+
+	protected function loadFromFile() {
+	
+		if (!file_exists($this->getCacheFilePath()))
+			return false;
+		$this->cache = new CatalogCacheObject();
+		$handle = fopen($this->getCacheFilePath(), 'rb');
+		$result = false;
+		if (flock($handle, LOCK_SH))
+		{
+			$this->cache->loadBin($handle);
+			flock( $handle, LOCK_UN );
+			$result = true;
+		}
+		fclose($handle);
+		return $result;
+	}
+	
+	protected function getCacheFilePath() {
+		return USERTTDIR.(self::$cache_file);
+	}
+
+       	public function saveInTT($id, $action, $token) {
+        
+		if (!$this->loadFromFile())
+			return array('success' => false, 'message' => 'Cannot load cache file');
+
+		if ($token != $this->cache->getToken())
+			return array('success' => false, 'message' => 'Cache token check error');
+		
+		$this->cache->updateIndexes();
+		$this->saveToFile();
+		
+		$intervals = $this->cache->getIntervalsArray(NULL,NULL,true);
+		
+		$this->cache->reset();
+ 
+		return $this->ttMgr->saveIntervals($id, $intervals, $action);
+	}
+
+	
+	
+   }
+?>
\ No newline at end of file
diff --git a/php/classes/CatalogMgr.php b/php/classes/CatalogMgr.php
new file mode 100644
index 0000000..27d093f
--- /dev/null
+++ b/php/classes/CatalogMgr.php
@@ -0,0 +1,227 @@
+<?php
+
+/**
+ * @class CatalogMgr
+ */
+
+class CatalogMgr extends TimeTableMgr {	
+             
+	function __construct() {
+		parent::__construct('Tt.xml');
+		$this->contentRootId = 'catalog-treeRootNode';
+		$this->contentRootTag = 'catalogList';
+		$this->attributes = array('name' => '', 'intervals' => ''); // +  'parameters' 
+		$this->optionalAttributes = array();
+		$this->objTagName =   'catalog';
+		$this->id_prefix = 'cat_'; // 'tt_' ?
+
+		if (!file_exists($this->xmlName)) {
+			  $this->createDom();
+			  $this->xp = new domxpath($this->contentDom); 
+		}
+	}	
+ 
+	public function getTmpObject($folderId, $name, $onlyDescription = false) {
+	
+		$filePath = USERWORKINGDIR.$folderId.'/'.$name.'.xml';
+		
+		if (!file_exists($filePath)) 
+			return array('error' => 'Cannot find result file');
+		
+		$dom = new DomDocument('1.0'); 
+		$dom->formatOutput = true;
+		
+		if (!$dom -> load($filePath))
+			return array('error' => 'Cannot load result file');
+		$nameNodes = $dom->getElementsByTagName('name');
+		if ($nameNodes->length > 0)
+			$attributesToReturn['name'] = $nameNodes->item(0)->nodeValue;
+		
+		$descNodes = $dom->getElementsByTagName('description');
+		if ($descNodes->length > 0)
+			$attributesToReturn['description'] = $descNodes->item(0)->nodeValue;
+		
+		$creatNodes = $dom->getElementsByTagName('created');
+		if ($creatNodes->length > 0)
+			$attributesToReturn['created'] = $creatNodes->item(0)->nodeValue;
+		
+		$histNodes = $dom->getElementsByTagName('history');
+		if ($histNodes->length > 0)
+			$attributesToReturn['history'] = $histNodes->item(0)->nodeValue;
+	
+		$attributesToReturn['objName'] = $name;
+		$attributesToReturn['folderId'] = $folderId;
+		$attributesToReturn['success'] = true;
+		
+		if (!$onlyDescription)
+		{
+			$intNodes = $dom->getElementsByTagName('intervals');
+			foreach ($intNodes as $intNode)
+			{
+				$startNodes = $intNode->getElementsByTagName('start');
+				if ($startNodes->length <= 0)
+					return array('error' => 'Error detected in result file');
+					
+				$stopNodes = $intNode->getElementsByTagName('stop');
+				if ($stopNodes->length <= 0)
+					return array('error' => 'Error detected in result file');
+					
+				// for catalog	
+				$paramNodes = $intNode->getElementsByTagName('param');
+				$params = array();
+				if ($paramNodes->length > 0) 
+					foreach ( $paramNodes as $paramNode ) $params[] = $paramNode->nodeValue;
+					
+					
+				$attributesToReturn['intervals'][] = array('start' => $startNodes->item(0)->nodeValue,
+									    'stop' => $stopNodes->item(0)->nodeValue,
+									    'paramTable' =>  $params);
+			}
+			// for catalog
+			$paramsNodes = $dom->getElementsByTagName('parameter');
+			
+			if ($paramsNodes->length > 0){
+			
+			  $paramsArray = array();		 
+			  foreach ($paramsNodes as $paramNode) {
+			  
+			    $oneParam = array();
+			    foreach ($paramNode->attributes as $attr) 			    
+				    $oneParam[$attr->nodeName] = $attr->nodeValue;
+			  
+			     if (substr($paramNode->getAttribute('id'),0,8) == 'stat_cov') {		    
+				    $oneParam['size'] = '1';
+				    $oneParam['name'] = 'Flag';
+			      }
+			      
+			    $paramsArray[] = $oneParam;
+			  }
+			$attributesToReturn['success'] = true;
+			$attributesToReturn['parameters'] = $paramsArray;
+			}
+			else 
+			    return array('error' => 'No information on parameters in result file');
+		
+				
+			}
+	
+		return  $attributesToReturn;
+	}
+
+	
+// 	public function loadIntervalsFromTT($id,$typeTT,$start = NULL, $limit = NULL)
+// 	{
+// 
+// 	    if ($typeTT == 'sharedtimeTable') {			
+// 		    $pathid = SHAREDPATH.'TT/'.$id;
+// 	      }
+// 	    else {
+// 		    $pathid = USERTTDIR.$id;		
+// 	    }
+// 			  
+// 	      //load intervals from TT id
+// 	      if (!file_exists($pathid.'.xml'))
+// 		return array('success' => false, 'message' => "Cannot find TT file ".$id);
+// 		
+// 	      $this->objectDom -> load($pathid.'.xml');
+// 	      
+// 	      if (!($objToGet = $this->objectDom->getElementById($id)))
+// 		return array('success' => false, 'message' => NO_SUCH_ID." ".$id);
+// 	      
+// 	      $xpath = new DOMXPath($this->objectDom);
+// 	      $intervals =  $xpath->query('//intervals');
+// 	      
+// 	      $result = array();
+// 	      
+// 	      if (!isset($start) || !isset($limit))
+// 	      {
+// 		  foreach ($intervals as $interval)
+// 		  {
+// 				  $startTime = $interval->getElementsByTagName('start')->item(0)->nodeValue;
+// 				  $stopTime  = $interval->getElementsByTagName('stop')->item(0)->nodeValue;
+// 				  array_push($result, array('start' => $startTime, 'stop' => $stopTime));
+// 			  }
+// 	      }
+// 	      else
+// 	      {
+// 		  for ($i = 0; $i < $limit; ++$i)
+// 		  {
+// 			  if ($start+$i >= $intervals->length)
+// 				  break;
+// 			  $startTime = $intervals->item($start+$i)->getElementsByTagName('start')->item(0)->nodeValue;
+// 			  $stopTime  = $intervals->item($start+$i)->getElementsByTagName('stop')->item(0)->nodeValue;
+// 			  array_push($result, array('start' => $startTime, 'stop' => $stopTime));
+// 		  }
+// 	      }
+// 	      
+// 	      return array(
+// 			  'totalCount' => $intervals->length,
+// 			  'intervals'  => $result,
+// 			  'start' => isset($start) ? $start : 0,
+// 			  'limit' => isset($limit) ? $limit : 0,
+// 			  'success'    => true
+// 	      );
+// 	  
+//       }
+
+        /*
+        *   catalog header
+        */
+        protected function setParamDescription($params) {
+                  
+          $paramsElement = $this->objectDom->createElement('parametres');
+          foreach ($params as $param) {
+             $paramElement = $this->objectDom->createElement('param');
+             $attrArray = (array)$param;            
+             foreach ($attrArray as $key => $value)
+		    $paramElement->setAttribute($key, $value);
+	     $paramsElement->appendChild($paramElement);    
+          }
+          
+          return $paramsElement;
+        }
+        
+      protected function createIntervalElement($interval) {
+	$newInterval = $this->objectDom->createElement('intervals');
+	$newInterval->appendChild($this->objectDom->createElement('start',$interval['start']));
+	$newInterval->appendChild($this->objectDom->createElement('stop',$interval['stop']));
+	foreach ($interval as $key =>$value) {
+		if (substr($key,0,5) == 'param')
+		      $newInterval->appendChild($this->objectDom->createElement('param', $value));
+	    
+	}
+	return $newInterval;
+      }
+      
+	public function createObject($p, $folder){
+	 
+		if ($p -> leaf)
+		{
+			$result = $this->createParameter($p, $folder);
+			if ($result['error'])
+				return $result;
+				
+			$cacheMgr = new CatalogCacheMgr();
+			
+			if (isset($p->cacheToken) && ($p->cacheToken != ''))
+			{
+				$resultSaveInt = $cacheMgr->saveInTT($result['id'], "update", $p->cacheToken);
+				if (!$resultSaveInt['success'])
+				{
+					if ($resultSaveInt['message'])
+						return array('error' => $resultSaveInt['message']);
+					else
+						return array('error' => 'Unknown error during intervals save');
+				}
+			}
+			return $result;
+		}
+		//      else return $this->createFolder($p);
+		//TODO check if this is possible?
+		else return array('error' => 'createFolder should be called from RENAME');
+	
+	}
+	
+	
+}
+?>
\ No newline at end of file
diff --git a/php/classes/IntervalCacheObject.php b/php/classes/IntervalCacheObject.php
new file mode 100644
index 0000000..56b7804
--- /dev/null
+++ b/php/classes/IntervalCacheObject.php
@@ -0,0 +1,114 @@
+<?php
+class IntervalCacheObject
+{
+	protected $id         = -1;
+	protected $index      = -1;
+	protected $start      = 0;
+	protected $stop       = 0;
+	protected $isNew      = false;
+	protected $isModified = false;
+
+	function __construct($id, $index) {
+		$this->id = $id;
+		$this->index = $index;
+	}
+
+	public function getId() {
+		return $this->id;
+	}
+	
+	public function getIndex() {
+		return $this->index;
+	}
+	
+	public function setIndex($index) {
+		$this->index = $index;
+	}
+
+	public function getStartToStamp() {
+		return $this->start;
+	}
+	
+	public function getStartToISO() {
+		return CacheTools::stamp2iso($this->start);
+	}
+
+	public function setStartFromStamp($stamp) {
+		$this->start = $stamp;
+	}
+	
+	public function setStartFromISO($iso) {
+		$this->start = CacheTools::iso2stamp($iso);
+	}
+
+	public function getStopToStamp() {
+		return $this->stop;
+	}
+	
+	public function getStopToISO() {
+		return CacheTools::stamp2iso($this->stop);
+	}
+
+	public function setStopFromStamp($stamp) {
+		$this->stop = $stamp;
+	}
+	
+	public function setStopFromISO($iso) {
+		$this->stop = CacheTools::iso2stamp($iso);
+	}
+	
+	public function getDuration() {
+		return ($this->stop-$this->start);
+	}
+
+	public function isModified() {
+		return $this->isModified;
+	}
+
+	public function setIsModified($isModified) {
+		$this->isModified = $isModified;
+	}
+
+	public function isNew() {
+		return $this->isNew;
+	}
+
+	public function setIsNew($isNew) {
+		$this->isNew = $isNew;
+	}
+	
+	public function toArray() {
+		$result = array(
+			"cacheId" => $this->id,
+			"start"   => $this->getStartToISO(),
+			"stop"    => $this->getStopToISO()
+		);
+		if ($this->isNew)
+			$result["isNew"] = true;
+		if ($this->isModified)
+			$result["isModified"] = true;
+		
+		return $result;
+	}
+
+	
+	
+	public function writeBin($handle) {
+		fwrite($handle,pack('L6',$this->id,$this->index,$this->start,$this->stop,$this->isNew,$this->isModified));
+	}
+	
+	public function loadBin($handle) {
+		$array = unpack('L6int',fread($handle,6*4));
+		$this->id         = $array['int1'];
+		$this->index      = $array['int2'];
+		$this->start      = $array['int3'];
+		$this->stop       = $array['int4'];
+		$this->isNew      = $array['int5'];
+		$this->isModified = $array['int6'];
+	}
+	
+	public function dump() {
+		echo " => Interval : id = ".$this->id.", index = ".$this->index.", start = ".$this->start.", stop = ".$this->stop.", isNew = ".$this->isNew.", isModified = ".$this->isModified.PHP_EOL;
+	}
+}
+?>
\ No newline at end of file
diff --git a/php/classes/TimeTableCacheMgr.php b/php/classes/TimeTableCacheMgr.php
index d3c9a02..7b98815 100644
--- a/php/classes/TimeTableCacheMgr.php
+++ b/php/classes/TimeTableCacheMgr.php
@@ -27,8 +27,8 @@ class SortPartCacheObject
 	public static $DIRECTION_ASC     = 1;
 	public static $DIRECTION_DES     = 2;
 	
-	private $type;
-	private $dir;
+	protected $type;
+	protected $dir;
 	
 	function __construct() {
 		$this->type = self::$TYPE_UNKNOWN;
@@ -172,7 +172,7 @@ class SortPartCacheObject
 
 class SortCacheObject
 {
-	private $parts = array();
+	protected $parts = array();
 
 	function __construct() {
 	}
@@ -286,9 +286,9 @@ class FilterPartCacheObject
 	public static $OPERATION_GT        = 2;
 	public static $OPERATION_EQ        = 3;
 	
-	private $type;
-	private $op;
-	private $value;
+	protected $type;
+	protected $op;
+	protected $value;
 	
 	function __construct() {
 		$this->type  = self::$TYPE_UNKNOWN;
@@ -470,7 +470,7 @@ class FilterPartCacheObject
 
 class FilterCacheObject
 {
-	private $parts = array();
+	protected $parts = array();
 	
 	function __construct() {
 		
@@ -555,631 +555,12 @@ class FilterCacheObject
 	}
 }
 
-class IntervalCacheObject
+ class TimeTableCacheMgr
 {
-	private $id         = -1;
-	private $index      = -1;
-	private $start      = 0;
-	private $stop       = 0;
-	private $isNew      = false;
-	private $isModified = false;
-
-	function __construct($id, $index) {
-		$this->id = $id;
-		$this->index = $index;
-	}
-
-	public function getId() {
-		return $this->id;
-	}
-	
-	public function getIndex() {
-		return $this->index;
-	}
-	
-	public function setIndex($index) {
-		$this->index = $index;
-	}
-
-	public function getStartToStamp() {
-		return $this->start;
-	}
-	
-	public function getStartToISO() {
-		return CacheTools::stamp2iso($this->start);
-	}
-
-	public function setStartFromStamp($stamp) {
-		$this->start = $stamp;
-	}
-	
-	public function setStartFromISO($iso) {
-		$this->start = CacheTools::iso2stamp($iso);
-	}
-
-	public function getStopToStamp() {
-		return $this->stop;
-	}
-	
-	public function getStopToISO() {
-		return CacheTools::stamp2iso($this->stop);
-	}
-
-	public function setStopFromStamp($stamp) {
-		$this->stop = $stamp;
-	}
-	
-	public function setStopFromISO($iso) {
-		$this->stop = CacheTools::iso2stamp($iso);
-	}
-	
-	public function getDuration() {
-		return ($this->stop-$this->start);
-	}
-
-	public function isModified() {
-		return $this->isModified;
-	}
-
-	public function setIsModified($isModified) {
-		$this->isModified = $isModified;
-	}
-
-	public function isNew() {
-		return $this->isNew;
-	}
-
-	public function setIsNew($isNew) {
-		$this->isNew = $isNew;
-	}
-	
-	public function toArray() {
-		$result = array(
-			"cacheId" => $this->id,
-			"start"   => $this->getStartToISO(),
-			"stop"    => $this->getStopToISO()
-		);
-		if ($this->isNew)
-			$result["isNew"] = true;
-		if ($this->isModified)
-			$result["isModified"] = true;
-		
-		return $result;
-	}
-
-	
-	
-	public function writeBin($handle) {
-		fwrite($handle,pack('L6',$this->id,$this->index,$this->start,$this->stop,$this->isNew,$this->isModified));
-	}
-	
-	public function loadBin($handle) {
-		$array = unpack('L6int',fread($handle,6*4));
-		$this->id         = $array['int1'];
-		$this->index      = $array['int2'];
-		$this->start      = $array['int3'];
-		$this->stop       = $array['int4'];
-		$this->isNew      = $array['int5'];
-		$this->isModified = $array['int6'];
-	}
-	
-	public function dump() {
-		echo " => Interval : id = ".$this->id.", index = ".$this->index.", start = ".$this->start.", stop = ".$this->stop.", isNew = ".$this->isNew.", isModified = ".$this->isModified.PHP_EOL;
-	}
-}
-
-class TimeTableCacheObject
-{
-	private static $format_version = 1;
-	private static $token_len = 8;
-	
-	private $token  = "";
-	
-	private $lastId = 0;
-	
-	private $intervals = array();
-	private $indexes   = array();
-	
-	private $isModified = false;
-	
-	private $filter = null;
-	
-	private $sort = null;
-
-	function __construct() {
-		$this->token  = $this->getRandomToken();
-		$this->filter = new FilterCacheObject();
-		$this->sort   = new SortCacheObject();
-	}
-
-	public function reset() {
-		$this->lastId = 0;
-		$this->isModified = false;
-		$this->intervals = array();
-		$this->indexes   = array();
-		unset($this->filter);
-		$this->filter = new FilterCacheObject();;
-		unset($this->sort);
-		$this->sort = new SortCacheObject();
-	}
-	
-	public function setIsModified($isModified) {
-		$this->isModified = $isModified;
-	}
-	
-	public function addInterval($startIso, $stopIso, $isNew = false, $index = -1) {
-		$interval = new IntervalCacheObject($this->lastId, count($this->intervals));
-		++$this->lastId;
-		$interval->setStartFromISO($startIso);
-		$interval->setStopFromISO($stopIso);
-		$interval->setIsNew($isNew);
-		array_push($this->intervals, $interval);
-		if ($index < 0)
-			array_push($this->indexes, count($this->intervals) - 1);
-		else
-			array_splice($this->indexes, $index, 0, array(count($this->intervals) - 1));
-		if ($isNew)
-			$this->isModified = true;
-		return $interval;
-	}
-	
-	public function removeIntervalFromId($id) {
-		for ($i = 0; $i < count($this->intervals); ++$i)
-		{
-			if ($this->intervals[$i]->getId() == $id)
-			{
-				//Remove interval
-				array_splice($this->intervals, $i, 1);
-				//Remove interval index if exist in indexes list
-				for ($j = 0; $j < count($this->indexes); ++$j)
-				{
-					if ($this->indexes[$j] == $i)
-					{
-						array_splice($this->indexes, $j, 1);
-						break;
-					}
-				}
-				//Update indexes list
-				for ($j = 0; $j < count($this->indexes); ++$j)
-				{
-					if ($this->indexes[$j] >=  $i)
-						$this->indexes[$j]--;
-				}
-				$this->isModified = true;
-				return true;
-			}
-		}
-		
-		return false;
-	}
-	
-	public function modifyIntervalFromId($id, $start, $stop) {
-		foreach ($this->intervals as $interval)
-		{
-			if ($interval->getId() == $id)
-			{
-				if (isset($start))
-					$interval->setStartFromISO($start);
-				if (isset($stop))
-					$interval->setStopFromISO($stop);
-				$interval->setIsModified(true);
-				$this->isModified = true;
-				return true;
-			}
-		}
-		
-		return false;
-	}
-	
-	public function operationIntervals($extendTime, $shiftTime) {
-		if (($extendTime == 0) && ($shiftTime == 0))
-			//Nothing to do
-			return true;
-		
-		for ($i = 0; $i < count($this->indexes); ++$i) {
-			$start = $this->intervals[$this->indexes[$i]]->getStartToStamp();
-			$start -= $extendTime;
-			$start += $shiftTime;
-			$this->intervals[$this->indexes[$i]]->setStartFromStamp($start);
-			
-			$stop = $this->intervals[$this->indexes[$i]]->getStopToStamp();
-			$stop += $extendTime;
-			$stop += $shiftTime;
-			$this->intervals[$this->indexes[$i]]->setStopFromStamp($stop);
-			
-			$this->intervals[$this->indexes[$i]]->setIsModified(true);
-			$this->isModified = true;
-		}
-		
-		return true;
-	}
-	
-	public function mergeIntervals() {
-		$this->sort->reset();
-		
-		$this->sort->loadFromObject(
-			array(
-				(object)array("property" => "start", "direction" => "DESC")
-			)	
-		);
-		
-		$this->updateIndexes();
-		
-		$merged_intervals = array();
-		
-		for ($i = 0; $i < count($this->indexes); ++$i) {
-			if (count($merged_intervals) == 0)
-			{
-				array_push($merged_intervals,array(
-					"start" => $this->intervals[$this->indexes[$i]]->getStartToStamp(),
-					"stop"  => $this->intervals[$this->indexes[$i]]->getStopToStamp(),
-					"mod"   => FALSE)
-				);
-				continue;
-			}
-			if (($merged_intervals[count($merged_intervals)-1]["stop"] >= $this->intervals[$this->indexes[$i]]->getStartToStamp()) &&
-				($merged_intervals[count($merged_intervals)-1]["stop"] < $this->intervals[$this->indexes[$i]]->getStopToStamp()))
-			{
-				$merged_intervals[count($merged_intervals)-1]["stop"] = $this->intervals[$this->indexes[$i]]->getStopToStamp();
-				$merged_intervals[count($merged_intervals)-1]["mod"] = TRUE;
-			}
-			else
-				array_push($merged_intervals,array(
-					"start" => $this->intervals[$this->indexes[$i]]->getStartToStamp(),
-					"stop"  => $this->intervals[$this->indexes[$i]]->getStopToStamp(),
-					"mod"   => FALSE)
-				);
-		}
-		
-		$this->reset();
-		
-		foreach ($merged_intervals as $merged_interval) {
-			$interval = new IntervalCacheObject($this->lastId, count($this->intervals));
-			++$this->lastId;
-			$interval->setStartFromStamp($merged_interval["start"]);
-			$interval->setStopFromStamp($merged_interval["stop"]);
-			$interval->setIsNew($merged_interval["mod"]);
-			if ($merged_interval["mod"])
-				$this->isModified = true;
-			array_push($this->intervals, $interval);
-			array_push($this->indexes, count($this->intervals) - 1);
-		}
-		
-		return true;
-	}
-	
-	public function getStatistics() {
-		$minTime  = NULL;
-		$maxTime  = NULL;
-		$minDuration  = NULL;
-		$maxDuration  = NULL;
-		$indexMinDuration = -1;
-		$indexMaxDuration = -1;
-		
-		$nbValid = 0;
-		$durationTotal = 0;
-		
-		//Min & Max
-		for ($i = 0; $i < count($this->indexes); ++$i) {
-			if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
-				//Invalid interval
-				continue;
-			
-			++$nbValid;
-			$durationTotal += $this->intervals[$this->indexes[$i]]->getDuration();
-			
-			if (!isset($minTime) || ($minTime > $this->intervals[$this->indexes[$i]]->getStartToStamp()))
-				$minTime = $this->intervals[$this->indexes[$i]]->getStartToStamp();
-			
-			if (!isset($maxTime) || ($maxTime < $this->intervals[$this->indexes[$i]]->getStopToStamp()))
-				$maxTime = $this->intervals[$this->indexes[$i]]->getStopToStamp();
-			
-			if (!isset($minDuration) || ($minDuration > $this->intervals[$this->indexes[$i]]->getDuration()))
-			{
-				$minDuration      = $this->intervals[$this->indexes[$i]]->getDuration();
-				$indexMinDuration = $i;
-			}
-			
-			if (!isset($maxDuration) || ($maxDuration < $this->intervals[$this->indexes[$i]]->getDuration()))
-			{
-				$maxDuration      = $this->intervals[$this->indexes[$i]]->getDuration();
-				$indexMaxDuration = $i;
-			}
-		}
-		
-		if (!isset($minTime))
-			$minTime = 0;
-		if (!isset($maxTime))
-			$maxTime = 0;
-		if (!isset($minDuration))
-			$minDuration = 0;
-		if (!isset($maxDuration))
-			$maxDuration = 0;
-		
-		
-		//Mean
-		if ($nbValid > 0)
-			$mean = $durationTotal / $nbValid;
-		else
-			$mean = 0;
-		
-		//Standard deviation
-		$pow = 0;
-		for ($i = 0; $i < count($this->indexes); ++$i) {
-			if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
-				//Invalid interval
-				continue;
-			
-			$pow += pow($this->intervals[$this->indexes[$i]]->getDuration()-$mean,2);
-		}
-		if ($nbValid > 0)
-			$variance = $pow/$nbValid;
-		else
-			$variance = 0;
-		$stdev = sqrt($variance);
-		
-		//Sort by duration to get median
-		$this->sort->reset();
-		
-		$this->sort->loadFromObject(
-				array(
-						(object)array("property" => "durationSec", "direction" => "DESC")
-				)
-		);
-		
-		$this->updateIndexes();
-		
-		$durations = array();
-		for ($i = 0; $i < count($this->indexes); ++$i) {
-			if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
-				//Invalid interval
-				continue;
-			
-			array_push($durations, $this->intervals[$this->indexes[$i]]->getDuration());
-		}
-		
-		if (count($durations) > 0)
-		{
-			if (count($durations)%2 > 0) {
-				$median = $durations[count($durations)/2-0.5];
-			} else { // else the number of intervals is an even number
-				$median = ($durations[count($durations)/2-1] + $durations[count($durations)/2])/2;
-			}
-		}
-		else
-			$median = 0;
-		
-		//Merge intervals to get density
-		$this->mergeIntervals();
-		
-		$durationMergedTotal = 0;
-		for ($i = 0; $i < count($this->indexes); ++$i) {
-			if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
-				//Invalid interval
-				continue;
-				
-			$durationMergedTotal += $this->intervals[$this->indexes[$i]]->getDuration();
-		}
-		
-		if (($maxTime-$minTime) > 0)
-			$density = (($durationMergedTotal/($maxTime-$minTime)));
-		else
-			$density = 0;
-		
-		return array(
-			"minDuration"     => $minDuration,
-			"minDurationIndex"=> $indexMinDuration,
-			"maxDuration"     => $maxDuration,
-			"maxDurationIndex"=> $indexMaxDuration,
-			"mean"    => $mean,
-			"stdev"   => $stdev,
-			"median"  => $median,
-			"density" => $density);
-	}
-	
-	public function getStatus() {
-		$nbFiltered = count($this->intervals) - count($this->indexes);
-		
-		$nbModified = 0;
-		$nbNew      = 0;
-		$nbInvalid  = 0;
-		$nbValid    = 0;
-		for ($i = 0; $i < count($this->indexes); ++$i) {
-			if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
-				++$nbInvalid;
-			else
-				++$nbValid;
-			if ($this->intervals[$this->indexes[$i]]->isModified())
-				++$nbModified;
-			if ($this->intervals[$this->indexes[$i]]->isNew())
-				++$nbNew;
-		}
-		
-		return array(
-			"nbFiltered" => $nbFiltered,
-			"nbModified" => $nbModified,
-			"nbNew"      => $nbNew,
-			"nbInvalid"  => $nbInvalid,
-			"nbValid"    => $nbValid,
-			"isModified" => $this->isModified
-		);
-	}
-	
-	public function getIntervalsArray($startIndex, $limit,$skipInvalid = false) {
-		$intervals = array();
-		
-		if (!isset($startIndex))
-			$startIndex = 0;
-		
-		if (!isset($limit))
-			$limit = count($this->indexes);
-		
-		for ($i = 0; $i < $limit; ++$i) {
-			if ($startIndex+$i >= count($this->indexes))
-				break;
-			if ($skipInvalid && ($this->intervals[$this->indexes[$startIndex+$i]]->getDuration() <= 0))
-				continue;
-			array_push($intervals, $this->intervals[$this->indexes[$startIndex+$i]]->toArray());
-		}
-		return $intervals;
-	}
-	
-	public function getLength() {
-		return count($this->indexes);
-	}
-	
-	public function getToken() {
-		return $this->token;
-	}
-	
-	public function getFilter() {
-		return $this->filter;
-	}
-	
-	public function getSort() {
-		return $this->sort;
-	}
-	
-	public function updateIndexes() {
-		$this->indexes = array();
-		
-		for ($i = 0; $i < count($this->intervals); ++$i)
-			$this->intervals[$i]->setIndex($i);
-		
-		//Apply sort
-		$sort_result = $this->sort->apply($this->intervals);
-		
-		//Apply filter
-		for ($i = 0; $i < count($sort_result); ++$i)
-		{
-			if (!$this->filter->toFiltered($this->intervals[$sort_result[$i]]))
-				array_push($this->indexes,$this->intervals[$sort_result[$i]]->getIndex());
-		}
-	}
-	
-	public function writeBin($handle) {
-		//Magic key ("TTC")
-		fwrite($handle,pack('C3',ord('T'),ord('T'),ord('C')));
-		
-		//Version
-		fwrite($handle,pack('L',TimeTableCacheObject::$format_version));
-		
-		//Token
-		for ($i = 0; $i < TimeTableCacheObject::$token_len; ++$i)
-			fwrite($handle,pack('C',ord($this->token[$i])));
-		
-		//Modified
-		fwrite($handle,pack('L',$this->isModified));
-		
-		//Filter
-		$this->filter->writeBin($handle);
-		
-		//Sort
-		$this->sort->writeBin($handle);
-		
-		//Intervals
-		fwrite($handle,pack('L2',count($this->intervals), $this->lastId));
-		foreach($this->intervals as $interval)
-			$interval->writeBin($handle);
-		
-		//Indexes
-		fwrite($handle,pack('L',count($this->indexes)));
-		foreach($this->indexes as $index)
-			fwrite($handle,pack('L',$index));
-	}
-	
-	public function loadBin($handle) {
-		//Magic key ("TTC")
-		if (!$res = unpack('C3key',fread($handle,3)))
-			return false;
-		
-		if (($res['key1'] != ord('T')) || ($res['key2'] != ord('T')) || ($res['key3'] != ord('C')))
-			return false;
-		
-		//Version
-		if (!$res = unpack('Lversion',fread($handle,4)))
-			return false;
-		if (($res['version'] != TimeTableCacheObject::$format_version))
-			return false;
-
-		//Token
-		$token = "";
-		for ($i = 0; $i < TimeTableCacheObject::$token_len; ++$i)
-		{
-			if (!$res = unpack('Ctoken',fread($handle,1)))
-				return false;
-			$token .= chr($res['token']);
-		}
-		$this->token = $token;
-		
-		//Modified
-		if (!$res = unpack('Lmodified',fread($handle,4)))
-			return false;
-		$this->isModified = $res['modified'];
-		
-		//Filter
-		$this->filter->loadBin($handle);
-		
-		//Sort
-		$this->sort->loadBin($handle);
-		
-		//Intervals
-		$res = unpack('L2data',fread($handle,2*4));
-		$nbIntervals  = $res['data1'];
-		$this->lastId = $res['data2'];
-		for ($i = 0; $i < $nbIntervals; ++$i)
-		{
-			$interval = new IntervalCacheObject(-1);
-			$interval->loadBin($handle);
-			array_push($this->intervals, $interval);
-		}
-		
-		//Indexes
-		$res = unpack('Ldata',fread($handle,4));
-		$nbIndexes  = $res['data'];
-		for ($i = 0; $i < $nbIndexes; ++$i)
-		{
-			$res = unpack('Lindex',fread($handle,4));
-			array_push($this->indexes, $res['index']);
-		}
-		
-		return true;
-	}
-	
-	private function getRandomToken() {
-		$letters = 'abcefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
-		return substr(str_shuffle($letters), 0, TimeTableCacheObject::$token_len);
-	}
-	
-	public function dump() {
-		echo " => TimeTableCacheObject : token = ".$this->token.", nb intervals = ".count($this->intervals).", last id = ".$this->lastId.", nb indexes = ".count($this->indexes).PHP_EOL;
-		echo PHP_EOL;
-		
-		$this->filter->dump();
-		echo PHP_EOL;
-		
-		$this->sort->dump();
-		echo PHP_EOL;
-		
-		foreach ($this->intervals as $interval)
-			$interval->dump();
-		echo PHP_EOL;
-		
-		echo " => Indexes list : ";
-		foreach ($this->indexes as $index)
-		{
-			echo $index.", ";
-		}
-		echo PHP_EOL;
-	}
-}
-
-class TimeTableCacheMgr
-{
-	private static $cache_file                = "cacheTT";
+	protected static $cache_file                = "cacheTT";
 	
-	private $ttMgr = null;
-	private $cache = null;
+	protected $ttMgr = null;
+	protected $cache = null;
 
 	function __construct() {
 		$this->ttMgr = new TimeTableMgr();
@@ -1449,11 +830,11 @@ class TimeTableCacheMgr
 		$this->cache->dump();
 	}
 	
-	private function getCacheFilePath() {
+	protected function getCacheFilePath() {
 		return USERTTDIR.(self::$cache_file);
 	}
 	
-	private function saveToFile() {
+	protected function saveToFile() {
 		if (!isset($this->cache))
 			return false;
 		$handle = fopen($this->getCacheFilePath(), 'wb');
@@ -1468,7 +849,7 @@ class TimeTableCacheMgr
 		return $result;
 	}
 	
-	private function loadFromFile() {
+	protected function loadFromFile() {
 		if (!file_exists($this->getCacheFilePath()))
 			return false;
 		$this->cache = new TimeTableCacheObject();
diff --git a/php/classes/TimeTableCacheObject.php b/php/classes/TimeTableCacheObject.php
new file mode 100644
index 0000000..d2fb579
--- /dev/null
+++ b/php/classes/TimeTableCacheObject.php
@@ -0,0 +1,509 @@
+<?php
+
+class TimeTableCacheObject
+{
+	protected static $format_version = 1;
+	protected static $token_len = 8;
+	
+	protected $token  = "";
+	
+	protected $lastId = 0;
+	
+	protected $intervals = array();
+	protected $indexes   = array();
+	
+	protected $isModified = false;
+	
+	protected $filter = null;
+	
+	protected $sort = null;
+
+	function __construct() {
+		$this->token  = $this->getRandomToken();
+		$this->filter = new FilterCacheObject();
+		$this->sort   = new SortCacheObject();
+	}
+
+	public function reset() {
+		$this->lastId = 0;
+		$this->isModified = false;
+		$this->intervals = array();
+		$this->indexes   = array();
+		unset($this->filter);
+		$this->filter = new FilterCacheObject();;
+		unset($this->sort);
+		$this->sort = new SortCacheObject();
+	}
+	
+	public function setIsModified($isModified) {
+		$this->isModified = $isModified;
+	}
+	
+	public function addInterval($startIso, $stopIso, $isNew = false, $index = -1) {
+		$interval = new IntervalCacheObject($this->lastId, count($this->intervals));
+		++$this->lastId;
+		$interval->setStartFromISO($startIso);
+		$interval->setStopFromISO($stopIso);
+		$interval->setIsNew($isNew);
+		array_push($this->intervals, $interval);
+		if ($index < 0)
+			array_push($this->indexes, count($this->intervals) - 1);
+		else
+			array_splice($this->indexes, $index, 0, array(count($this->intervals) - 1));
+		if ($isNew)
+			$this->isModified = true;
+		return $interval;
+	}
+	
+	public function removeIntervalFromId($id) {
+		for ($i = 0; $i < count($this->intervals); ++$i)
+		{
+			if ($this->intervals[$i]->getId() == $id)
+			{
+				//Remove interval
+				array_splice($this->intervals, $i, 1);
+				//Remove interval index if exist in indexes list
+				for ($j = 0; $j < count($this->indexes); ++$j)
+				{
+					if ($this->indexes[$j] == $i)
+					{
+						array_splice($this->indexes, $j, 1);
+						break;
+					}
+				}
+				//Update indexes list
+				for ($j = 0; $j < count($this->indexes); ++$j)
+				{
+					if ($this->indexes[$j] >=  $i)
+						$this->indexes[$j]--;
+				}
+				$this->isModified = true;
+				return true;
+			}
+		}
+		
+		return false;
+	}
+	
+	public function modifyIntervalFromId($id, $start, $stop) {
+		foreach ($this->intervals as $interval)
+		{
+			if ($interval->getId() == $id)
+			{
+				if (isset($start))
+					$interval->setStartFromISO($start);
+				if (isset($stop))
+					$interval->setStopFromISO($stop);
+				$interval->setIsModified(true);
+				$this->isModified = true;
+				return true;
+			}
+		}
+		
+		return false;
+	}
+	
+	public function operationIntervals($extendTime, $shiftTime) {
+		if (($extendTime == 0) && ($shiftTime == 0))
+			//Nothing to do
+			return true;
+		
+		for ($i = 0; $i < count($this->indexes); ++$i) {
+			$start = $this->intervals[$this->indexes[$i]]->getStartToStamp();
+			$start -= $extendTime;
+			$start += $shiftTime;
+			$this->intervals[$this->indexes[$i]]->setStartFromStamp($start);
+			
+			$stop = $this->intervals[$this->indexes[$i]]->getStopToStamp();
+			$stop += $extendTime;
+			$stop += $shiftTime;
+			$this->intervals[$this->indexes[$i]]->setStopFromStamp($stop);
+			
+			$this->intervals[$this->indexes[$i]]->setIsModified(true);
+			$this->isModified = true;
+		}
+		
+		return true;
+	}
+	
+	public function mergeIntervals() {
+		$this->sort->reset();
+		
+		$this->sort->loadFromObject(
+			array(
+				(object)array("property" => "start", "direction" => "DESC")
+			)	
+		);
+		
+		$this->updateIndexes();
+		
+		$merged_intervals = array();
+		
+		for ($i = 0; $i < count($this->indexes); ++$i) {
+			if (count($merged_intervals) == 0)
+			{
+				array_push($merged_intervals,array(
+					"start" => $this->intervals[$this->indexes[$i]]->getStartToStamp(),
+					"stop"  => $this->intervals[$this->indexes[$i]]->getStopToStamp(),
+					"mod"   => FALSE)
+				);
+				continue;
+			}
+			if (($merged_intervals[count($merged_intervals)-1]["stop"] >= $this->intervals[$this->indexes[$i]]->getStartToStamp()) &&
+				($merged_intervals[count($merged_intervals)-1]["stop"] < $this->intervals[$this->indexes[$i]]->getStopToStamp()))
+			{
+				$merged_intervals[count($merged_intervals)-1]["stop"] = $this->intervals[$this->indexes[$i]]->getStopToStamp();
+				$merged_intervals[count($merged_intervals)-1]["mod"] = TRUE;
+			}
+			else
+				array_push($merged_intervals,array(
+					"start" => $this->intervals[$this->indexes[$i]]->getStartToStamp(),
+					"stop"  => $this->intervals[$this->indexes[$i]]->getStopToStamp(),
+					"mod"   => FALSE)
+				);
+		}
+		
+		$this->reset();
+		
+		foreach ($merged_intervals as $merged_interval) {
+			$interval = new IntervalCacheObject($this->lastId, count($this->intervals));
+			++$this->lastId;
+			$interval->setStartFromStamp($merged_interval["start"]);
+			$interval->setStopFromStamp($merged_interval["stop"]);
+			$interval->setIsNew($merged_interval["mod"]);
+			if ($merged_interval["mod"])
+				$this->isModified = true;
+			array_push($this->intervals, $interval);
+			array_push($this->indexes, count($this->intervals) - 1);
+		}
+		
+		return true;
+	}
+	
+	public function getStatistics() {
+		$minTime  = NULL;
+		$maxTime  = NULL;
+		$minDuration  = NULL;
+		$maxDuration  = NULL;
+		$indexMinDuration = -1;
+		$indexMaxDuration = -1;
+		
+		$nbValid = 0;
+		$durationTotal = 0;
+		
+		//Min & Max
+		for ($i = 0; $i < count($this->indexes); ++$i) {
+			if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
+				//Invalid interval
+				continue;
+			
+			++$nbValid;
+			$durationTotal += $this->intervals[$this->indexes[$i]]->getDuration();
+			
+			if (!isset($minTime) || ($minTime > $this->intervals[$this->indexes[$i]]->getStartToStamp()))
+				$minTime = $this->intervals[$this->indexes[$i]]->getStartToStamp();
+			
+			if (!isset($maxTime) || ($maxTime < $this->intervals[$this->indexes[$i]]->getStopToStamp()))
+				$maxTime = $this->intervals[$this->indexes[$i]]->getStopToStamp();
+			
+			if (!isset($minDuration) || ($minDuration > $this->intervals[$this->indexes[$i]]->getDuration()))
+			{
+				$minDuration      = $this->intervals[$this->indexes[$i]]->getDuration();
+				$indexMinDuration = $i;
+			}
+			
+			if (!isset($maxDuration) || ($maxDuration < $this->intervals[$this->indexes[$i]]->getDuration()))
+			{
+				$maxDuration      = $this->intervals[$this->indexes[$i]]->getDuration();
+				$indexMaxDuration = $i;
+			}
+		}
+		
+		if (!isset($minTime))
+			$minTime = 0;
+		if (!isset($maxTime))
+			$maxTime = 0;
+		if (!isset($minDuration))
+			$minDuration = 0;
+		if (!isset($maxDuration))
+			$maxDuration = 0;
+		
+		
+		//Mean
+		if ($nbValid > 0)
+			$mean = $durationTotal / $nbValid;
+		else
+			$mean = 0;
+		
+		//Standard deviation
+		$pow = 0;
+		for ($i = 0; $i < count($this->indexes); ++$i) {
+			if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
+				//Invalid interval
+				continue;
+			
+			$pow += pow($this->intervals[$this->indexes[$i]]->getDuration()-$mean,2);
+		}
+		if ($nbValid > 0)
+			$variance = $pow/$nbValid;
+		else
+			$variance = 0;
+		$stdev = sqrt($variance);
+		
+		//Sort by duration to get median
+		$this->sort->reset();
+		
+		$this->sort->loadFromObject(
+				array(
+						(object)array("property" => "durationSec", "direction" => "DESC")
+				)
+		);
+		
+		$this->updateIndexes();
+		
+		$durations = array();
+		for ($i = 0; $i < count($this->indexes); ++$i) {
+			if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
+				//Invalid interval
+				continue;
+			
+			array_push($durations, $this->intervals[$this->indexes[$i]]->getDuration());
+		}
+		
+		if (count($durations) > 0)
+		{
+			if (count($durations)%2 > 0) {
+				$median = $durations[count($durations)/2-0.5];
+			} else { // else the number of intervals is an even number
+				$median = ($durations[count($durations)/2-1] + $durations[count($durations)/2])/2;
+			}
+		}
+		else
+			$median = 0;
+		
+		//Merge intervals to get density
+		$this->mergeIntervals();
+		
+		$durationMergedTotal = 0;
+		for ($i = 0; $i < count($this->indexes); ++$i) {
+			if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
+				//Invalid interval
+				continue;
+				
+			$durationMergedTotal += $this->intervals[$this->indexes[$i]]->getDuration();
+		}
+		
+		if (($maxTime-$minTime) > 0)
+			$density = (($durationMergedTotal/($maxTime-$minTime)));
+		else
+			$density = 0;
+		
+		return array(
+			"minDuration"     => $minDuration,
+			"minDurationIndex"=> $indexMinDuration,
+			"maxDuration"     => $maxDuration,
+			"maxDurationIndex"=> $indexMaxDuration,
+			"mean"    => $mean,
+			"stdev"   => $stdev,
+			"median"  => $median,
+			"density" => $density);
+	}
+	
+	public function getStatus() {
+		$nbFiltered = count($this->intervals) - count($this->indexes);
+		
+		$nbModified = 0;
+		$nbNew      = 0;
+		$nbInvalid  = 0;
+		$nbValid    = 0;
+		for ($i = 0; $i < count($this->indexes); ++$i) {
+			if ($this->intervals[$this->indexes[$i]]->getDuration() <= 0)
+				++$nbInvalid;
+			else
+				++$nbValid;
+			if ($this->intervals[$this->indexes[$i]]->isModified())
+				++$nbModified;
+			if ($this->intervals[$this->indexes[$i]]->isNew())
+				++$nbNew;
+		}
+		
+		return array(
+			"nbFiltered" => $nbFiltered,
+			"nbModified" => $nbModified,
+			"nbNew"      => $nbNew,
+			"nbInvalid"  => $nbInvalid,
+			"nbValid"    => $nbValid,
+			"isModified" => $this->isModified
+		);
+	}
+	
+	public function getIntervalsArray($startIndex, $limit,$skipInvalid = false) {
+		$intervals = array();
+		
+		if (!isset($startIndex))
+			$startIndex = 0;
+		
+		if (!isset($limit))
+			$limit = count($this->indexes);
+		
+		for ($i = 0; $i < $limit; ++$i) {
+			if ($startIndex+$i >= count($this->indexes))
+				break;
+			if ($skipInvalid && ($this->intervals[$this->indexes[$startIndex+$i]]->getDuration() <= 0))
+				continue;
+			array_push($intervals, $this->intervals[$this->indexes[$startIndex+$i]]->toArray());
+		}
+		return $intervals;
+	}
+	
+	public function getLength() {
+		return count($this->indexes);
+	}
+	
+	public function getToken() {
+		return $this->token;
+	}
+	
+	public function getFilter() {
+		return $this->filter;
+	}
+	
+	public function getSort() {
+		return $this->sort;
+	}
+	
+	public function updateIndexes() {
+		$this->indexes = array();
+		
+		for ($i = 0; $i < count($this->intervals); ++$i)
+			$this->intervals[$i]->setIndex($i);
+		
+		//Apply sort
+		$sort_result = $this->sort->apply($this->intervals);
+		
+		//Apply filter
+		for ($i = 0; $i < count($sort_result); ++$i)
+		{
+			if (!$this->filter->toFiltered($this->intervals[$sort_result[$i]]))
+				array_push($this->indexes,$this->intervals[$sort_result[$i]]->getIndex());
+		}
+	}
+	
+	public function writeBin($handle) {
+		//Magic key ("TTC")
+		fwrite($handle,pack('C3',ord('T'),ord('T'),ord('C')));
+		
+		//Version
+		fwrite($handle,pack('L',TimeTableCacheObject::$format_version));
+		
+		//Token
+		for ($i = 0; $i < TimeTableCacheObject::$token_len; ++$i)
+			fwrite($handle,pack('C',ord($this->token[$i])));
+		
+		//Modified
+		fwrite($handle,pack('L',$this->isModified));
+		
+		//Filter
+		$this->filter->writeBin($handle);
+		
+		//Sort
+		$this->sort->writeBin($handle);
+
+		//Intervals
+		fwrite($handle,pack('L2',count($this->intervals), $this->lastId));
+		foreach($this->intervals as $interval)
+			$interval->writeBin($handle);
+		
+		//Indexes
+		fwrite($handle,pack('L',count($this->indexes)));
+		foreach($this->indexes as $index)
+			fwrite($handle,pack('L',$index));
+	}
+	
+	public function loadBin($handle) {
+		//Magic key ("TTC")
+		if (!$res = unpack('C3key',fread($handle,3)))
+			return false;
+		
+		if (($res['key1'] != ord('T')) || ($res['key2'] != ord('T')) || ($res['key3'] != ord('C')))
+			return false;
+		
+		//Version
+		if (!$res = unpack('Lversion',fread($handle,4)))
+			return false;
+		if (($res['version'] != TimeTableCacheObject::$format_version))
+			return false;
+
+		//Token
+		$token = "";
+		for ($i = 0; $i < TimeTableCacheObject::$token_len; ++$i)
+		{
+			if (!$res = unpack('Ctoken',fread($handle,1)))
+				return false;
+			$token .= chr($res['token']);
+		}
+		$this->token = $token;
+		
+		//Modified
+		if (!$res = unpack('Lmodified',fread($handle,4)))
+			return false;
+		$this->isModified = $res['modified'];
+		
+		//Filter
+		$this->filter->loadBin($handle);
+		
+		//Sort
+		$this->sort->loadBin($handle);
+		
+		//Intervals
+		$res = unpack('L2data',fread($handle,2*4));
+		$nbIntervals  = $res['data1'];
+		$this->lastId = $res['data2'];
+		for ($i = 0; $i < $nbIntervals; ++$i)
+		{
+			$interval = new IntervalCacheObject(-1);
+			$interval->loadBin($handle);
+			array_push($this->intervals, $interval);
+		}
+		
+		//Indexes
+		$res = unpack('Ldata',fread($handle,4));
+		$nbIndexes  = $res['data'];
+		for ($i = 0; $i < $nbIndexes; ++$i)
+		{
+			$res = unpack('Lindex',fread($handle,4));
+			array_push($this->indexes, $res['index']);
+		}
+		
+		return true;
+	}
+	
+	protected function getRandomToken() {
+		$letters = 'abcefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
+		return substr(str_shuffle($letters), 0, TimeTableCacheObject::$token_len);
+	}
+	
+	public function dump() {
+		echo " => TimeTableCacheObject : token = ".$this->token.", nb intervals = ".count($this->intervals).", last id = ".$this->lastId.", nb indexes = ".count($this->indexes).PHP_EOL;
+		echo PHP_EOL;
+		
+		$this->filter->dump();
+		echo PHP_EOL;
+		
+		$this->sort->dump();
+		echo PHP_EOL;
+		
+		foreach ($this->intervals as $interval)
+			$interval->dump();
+		echo PHP_EOL;
+		
+		echo " => Indexes list : ";
+		foreach ($this->indexes as $index)
+		{
+			echo $index.", ";
+		}
+		echo PHP_EOL;
+	}
+}
+
+?>
\ No newline at end of file
diff --git a/php/classes/TimeTableMgr.php b/php/classes/TimeTableMgr.php
index 49ebf52..0f32209 100644
--- a/php/classes/TimeTableMgr.php
+++ b/php/classes/TimeTableMgr.php
@@ -22,8 +22,6 @@ function timeFormat($myString) {
 
 class TimeTableMgr extends AmdaObjectMgr {	
      
-//TODO add catalogs as for requestMgr
-
 
 	function __construct($user) {
 		parent::__construct('Tt.xml');
@@ -82,8 +80,13 @@ class TimeTableMgr extends AmdaObjectMgr {
 		//if (!($p->intervals)) return true;
 		return false;
 	}
+         
+        /*
+        *  In case of catalogs
+        */
+        protected function setParamDescription($param) { }
 
-
+        
 	/*
 	 *         Create Time Table
 	 */
@@ -95,12 +98,15 @@ class TimeTableMgr extends AmdaObjectMgr {
 		$this->id = $this->setId();
 		$this->created = date('Y-m-d\TH:i:s');
 		if (!$this->id) return array('error' => ID_CREATION_ERROR);
+		
 		$this->resFileName = USERTTDIR.$this->id.'.xml';
+		//TODO catalog root element = 'timetable'
 		$rootElement = $this->objectDom->createElement('timetable');
 		$rootElement->setAttribute('xml:id',$this->id);
 	 
 		foreach ($p as $key => $value)		
-		if ($key != 'id' && $key != 'leaf' && $key != 'nodeType') {
+		if ($key != 'id' && $key != 'leaf' && $key != 'nodeType' &&
+		    $key != 'objName' && $key != 'objFormat' && $key != 'folderId' && $key != 'cacheToken') {
 			if ($key == 'created') {
 				$rootElement->appendChild($this->objectDom->createElement($key, $this->created));
 			}
@@ -114,8 +120,14 @@ class TimeTableMgr extends AmdaObjectMgr {
 					$n_int++;
 				}
 			}*/
+			// it is catalog 
+			else if ($key == 'parameters') {
+			  $paramsElement = $this->setParamDescription($value);
+			  if ($paramsElement) $rootElement->appendChild($paramsElement);
+			  
+			}
 			else if ($key != 'intervals')
-			$rootElement->appendChild($this->objectDom->createElement($key, htmlspecialchars($value)));
+			    $rootElement->appendChild($this->objectDom->createElement($key, htmlspecialchars($value)));
 		}
 
 		$this->objectDom->appendChild($rootElement);
@@ -418,12 +430,20 @@ class TimeTableMgr extends AmdaObjectMgr {
 		'totalCount' => $intervals->length,
 		'intervals'  => $result,
 		'start' => isset($start) ? $start : 0,
-    	'limit' => isset($limit) ? $limit : 0,
+		'limit' => isset($limit) ? $limit : 0,
 		'success'    => true
     );
     
   }
-
+  
+  protected function createIntervalElement($interval) {
+  
+	$newInterval = $this->objectDom->createElement('intervals');
+	$newInterval->appendChild($this->objectDom->createElement('start',$interval->start));
+	$newInterval->appendChild($this->objectDom->createElement('stop',$interval->stop));
+	return $newInterval;
+      }
+	
   public function saveIntervals($id,$intervals,$action)
   {
   	 if (substr($id,0,6) == 'shared') {
@@ -457,11 +477,9 @@ class TimeTableMgr extends AmdaObjectMgr {
       
     //add new intervals
     foreach ($intervals as $interval)
-    {
-    	 $newInterval = $this->objectDom->createElement('intervals');
-					 $newInterval->appendChild($this->objectDom->createElement('start',$interval->start));
-					 $newInterval->appendChild($this->objectDom->createElement('stop',$interval->stop));
-					 $this->objectDom->documentElement->appendChild($newInterval);
+    {	 
+	$newInterval = $this-> createIntervalElement($interval);
+	$this->objectDom->documentElement->appendChild($newInterval);
     }
 
         //save modifications
--
libgit2 0.21.2