1 var Class = require("../lib/mootools/mootools-node.js").Class;
  2 var JsonRpcResult = require("../lib/core/jsonrpc/JsonRpcResult.js").JsonRpcResult;
  3 var JsonRpcError = require("../lib/core/jsonrpc/JsonRpcError.js").JsonRpcError;
  4 var JsonRpcAbstract = require("../lib/core/jsonrpc/JsonRpcAbstract.js").JsonRpcAbstract;
  5 
  6 var EventDispatcher = require('../lib/core/event/EventDispatcher.js').EventDispatcher;
  7 
  8 var Event = require('../lib/core/event/Event.js').Event;
  9 var TemplateManager = require('../lib/TemplateManager.js').TemplateManager;
 10 
 11 /**
 12  * Representing template.
 13  * @class Template Base template class. 
 14  * @extends EventDispatcher
 15  * @requires Class
 16  * @requires Event 
 17  * @requires EventDispatcher
 18  * @requires JsonRpcAbstract
 19  * @requires JsonRpcError  
 20  * @requires JsonRpcResult
 21  * @requires TemplateManager
 22  * @param {String} name
 23  * @param {Object} configuration
 24  * @throws {Template.Exception.CONFIG_INVALID} if given <i>name</i> or <i>configuration</i> are invalid.
 25  */
 26 var Template = function(){
 27     /** @ignore */
 28     this.Extends = EventDispatcher;
 29    
 30     /**
 31      * Indicates if template is a child of parent.
 32      * @public
 33      * @type {Boolean}
 34      */
 35     this.hasParent = false;
 36     /**
 37      * Indicates if template was rendered.
 38      * @public
 39      * @type {Boolean}
 40      */
 41     this.isRendered = false;
 42     
 43     /**
 44      * configuration object
 45      * @private
 46      * @type {Object}
 47      */
 48     this._configuration = null;
 49     /**
 50      * generated content
 51      * @private
 52      * @type {Object}
 53      */
 54     this._content = null;
 55     /**
 56      * rendered children counter
 57      * @private
 58      * @type {Number}
 59      */ 
 60     this._counter = 0; 
 61     /**
 62      * template model
 63      * @private
 64      * @type {Object}
 65      */
 66     this._data = null;
 67     /**
 68      * template name within configuration
 69      * @private
 70      * @type {Boolean}
 71      */        
 72     this._name = "";
 73 
 74 
 75     /** @ignore */
 76     this.initialize = function(name, configuration){
 77 
 78         if(!name || !configuration || !configuration.hasOwnProperty("template")){
 79             throw Template.Exception.CONFIG_INVALID;
 80         }
 81         //public
 82         this.hasParent = false;
 83         this.isRendered = false;
 84         //private
 85         this._configuration = configuration;
 86         this._content = {
 87             result: null
 88         }; 
 89         this._counter = 0; 
 90         this._data = null;
 91         this._name = name;
 92     };
 93     
 94     /**
 95      * Abstract method. Needed to be overriden - otherwise Template.Exception.NOT_IMPLEMENTED will be throwed.
 96      * @public
 97      * @param {Object} data
 98      * @throw {Template.Exception.NOT_IMPLEMENTED}
 99      */
100     this.render = function(data){
101         throw Template.Exception.NOT_IMPLEMENTED;
102     };
103     
104     /**
105      * Dispatchig render action and handles its errors and exceptions.
106      * @public
107      * @param {Object} data
108      * @throws {Template.Exception.NOT_IMPLEMENTED} if method render wasn't overriden 
109      */
110     this.dispatchRender = function(data){
111         try{
112             console.log('   -- Template '+this._name+': rendering...');
113             this.render(data);
114         }
115         catch(e){
116             console.log('   -- Template '+this._name+': error while rendering...', e);
117             if(e == Template.Exception.NOT_IMPLEMENTED){
118                  //fallback in case of not implementing
119                 throw Template.Exception.NOT_IMPLEMENTED;
120             }
121 
122             switch(this.getErrorAction()){
123                 case Template.ACTION_ERROR_PROPAGATE:
124                     this.setRenderedData(JsonRpcError.factory(Template.Error.PROPAGATED).setData(e));
125                     break;
126                 case Template.ACTION_ERROR_DISCARD:
127                     this.setRenderedData(new JsonRpcResult(""));
128                     break;
129                 case Template.ACTION_ERROR_ABORT:
130                     this._templateManager.abort(JsonRpcError.factory(Template.Error.ABORTED).setData(e));
131                     break;    
132             }
133         }
134     };
135     
136     /**
137      * Handling model load. Called on DriverAbstract.LOADED
138      * @public
139      * @param {Event} e
140      */
141     this.onData = function(e){
142         if(this._templateManager.isAborted()){
143             return;
144         }
145         
146         console.log('   -- Template '+this._name+': received data');
147 
148         this._data = e.data;
149 
150         if(this._data && this._data.hasOwnProperty('#body')){
151             var children = this._data['#body'];
152             this._counter = children.length;
153         
154             console.log('   -- Template '+this._name+': have '+children.length +' children');
155         
156             for( var i = 0, max = children.length; i < max; i++ ){
157                 console.log('   -- Template '+this._name+': waiting for children: '+children[i]);
158                 var child = this.getTemplateManager().getTemplateByName(children[i]);
159                 if(child){
160                     this.addChild(child);
161                 }else{
162                     this._counter--;
163                 }
164             }
165         }else{
166             console.log('   -- Template '+this._name+': does\'nt have children');
167             this.dispatchRender(this._data);
168         }
169     };
170         
171     /**
172      * Handling model error. Called on DriverAbstract.ERROR
173      * @public
174      * @param {ErrorEvent} e
175      */
176     this.onDataError = function(e){
177         console.log('   -- Template '+this._name+': data error');
178         //TODO handle error
179     };
180     
181     /**
182      * Adding child template
183      * @public
184      * @param {Template} child
185      */
186     this.addChild = function(child){
187         child.addEventListener(Template.RENDERED, this._onTemplateRendered, this);
188         child.hasParent = true;
189         if(child.isRendered){
190             this._onTemplateRendered(new Event(Template.RENDERED, child));
191         }
192     };
193     
194     /**
195      * Setting rendering result
196      * @public
197      * @param {Object} data 
198      */
199     this.setRenderedData = function(data){
200         console.log('   -- Template '+this._name+': rendered.');
201         if(!(data instanceof JsonRpcAbstract)){
202             throw Template.Exception.WRONG_RENDER_DATA;
203         }
204 
205         this._content = data.toJson();
206 
207         console.log('   -- Template '+this._name+': dispaching...');
208         this.isRendered = true;
209         this.dispatchEvent(new Event(Template.RENDERED, this));
210     };
211     
212     /**
213      * Returns content generated by specific render engine
214      * @public
215      * @return {String}
216      */
217     this.getContent = function(){
218         return this._content;
219     };
220     
221     /**
222      * Returns error handler
223      * @public
224      * @return {CONST}
225      */
226     this.getErrorAction = function(){
227         return this._configuration.onerror ? this._configuration.onerror : Template.ACTION_ERROR_DEFAULT;
228     };
229 
230     /**
231      * Returns template manager who holds every template in the subtree
232      * @public
233      * @return {TemplateManager}
234      */
235     this.getTemplateManager = function(){
236         if(!this._templateManager){
237             throw Template.Exception.TEMPLATEMANAGER_NULL;
238         }
239         return this._templateManager;
240     };
241 
242     /**
243      * Sets template manager object which holds every template in the subtree
244      * @public
245      * @param {TemplateManager} templateManager
246      */
247     this.setTemplateManager = function(templateManager){
248         //FIXME: tutaj trzeba to poprawic
249         if(!templateManager){
250             throw Template.Exception.TEMPLATEMANAGER_NULL;
251         }
252         // else if(!(templateManager instanceof TemplateManager)){
253         //     throw Template.Exception.TEMPLATEMANAGER_NOT_CLASS_INSTANCE;
254         //     return;
255         // }
256         this._templateManager = templateManager;
257     };
258 
259     /**
260      * Returns template name
261      * @public
262      * @return {String}
263      */
264     this.getName = function(){
265         return this._name;
266     };
267 
268     /**
269      * Returns template location path
270      * @public
271      * @return {String} template path
272      */
273     this.getPath = function(){
274         return this._configuration.template;
275     };
276     
277     /**
278      * Callback function called on rendered child template
279      * @private
280      * @param {Event} e
281      */
282     this._onTemplateRendered = function(e){
283         this._counter--;
284 
285         console.log('   -- Template '+this._name+': received children: '+e.data.getName());
286 
287         if(this._counter === 0){
288 
289             console.log('   -- Template '+this._name+': have all children');
290         
291             if(this._data.hasOwnProperty('#body')){
292                 var children = this._data['#body'];
293                 this._data.body = [];
294 
295                 for(var i=0,max=children.length;i<max;i++){
296                     this._data.body.push(this.getTemplateManager().getTemplateByName(children[i]).getContent());
297                 }
298                 delete this._data['#body'];
299             }
300 
301             this.dispatchRender(this._data);
302         } else {
303             console.log('   -- Template '+this._name+': children left: '+this._counter);
304         }
305     };
306 };
307 
308 Template = new Class( new Template() );
309 
310 /**
311  * @static
312  * @constant
313  */
314 Template.RENDERED = "Template_RENDERED";
315 /**
316  * @static
317  * @constant
318  */
319 Template.ERROR = "Template_ERROR";
320 /**
321  * @static
322  * @constant
323  */
324 Template.ACTION_ERROR_PROPAGATE = "propagate";
325 /**
326  * @static
327  * @constant
328  */
329 Template.ACTION_ERROR_DISCARD = "discard";
330 /**
331  * @static
332  * @constant
333  */
334 Template.ACTION_ERROR_ABORT = "abort";
335 /**
336  * @static
337  * @constant
338  */
339 Template.ACTION_ERROR_DEFAULT = Template.ACTION_ERROR_DISCARD;
340 /**
341  * Namespace for exeptions messages.
342  * @static
343  * @constant
344  * @namespace
345  */
346 Template.Exception = {};
347 /**
348  * @static
349  * @constant
350  */
351 Template.Exception.CONFIG_INVALID = "Error - Template name and configuration are invalid.";
352 /**
353  * @static
354  * @constant
355  */
356 Template.Exception.NOT_IMPLEMENTED = "Method:render() - Not implemented!";
357 /**
358  * @static
359  * @constant
360  */
361 Template.Exception.TEMPLATEMANAGER_NULL = "TemplateManager is null";
362 /**
363  * @static
364  * @constant
365  */
366 Template.Exception.TEMPLATEMANAGER_NOT_CLASS_INSTANCE = "templateManager must be instance of TemplateManager class";
367 /**
368  * @static
369  * @constant
370  */
371 Template.Exception.FILE_DOES_NOT_EXIST = function(fileName){
372     return "Template: " + fileName + " doesn't exist";
373 };
374 /**
375  * @static
376  * @constant
377  */
378 Template.Exception.WRONG_RENDER_DATA = "Given data has to be an instance of JsonRpcAbstract";
379 /**
380  * Namespace for error objects;
381  * @static
382  * @constant
383  * @namespace
384  */
385 Template.Error = {};
386 /**
387  * @static
388  * @constant
389  */
390 Template.Error.ABORTED = new JsonRpcError(-2201, "Aborting because of template error");
391 /**
392  * @static
393  * @constant
394  */
395 Template.Error.PROPAGATED = new JsonRpcError(-2202, "Error occured, propagating error.");
396 
397 exports.Template = Template;