/**
    Javascript Repeater
    http://jsrepeater.devprog.com/
    Version 1.1
    
    Copyright (c) 2008 MT Global Consulting srl 
    This code is licensed under the MIT Licence
    http://www.opensource.org/licenses/mit-license.php
    
    usage: $('#myDiv').fillTemplate(data);
    Please see the site for details on template formatting
    
**/

(function($) {
    $.fn.fillTemplate = function(obj, _debug){        
        if ($.fn.fillTemplate.rptInstance == null) { 
            $.fn.fillTemplate.rptInstance = new $.fn.fillTemplate.jsRepeater(); 
        }
        
		var _result;
        this.each(function() {
            if ((this.id == null) || (this.id == undefined)){
                this.innerHTML = "Error: id attribute required";
            } else {
				$.fn.fillTemplate.rptInstance.templaters[this.id] = new $.fn.fillTemplate.templater();
                var node = this.cloneNode(true);
                $.fn.fillTemplate.rptInstance.templaters[this.id].initialise(this.cloneNode(true));
                if (obj) {
                    $(this).replaceWith($.fn.fillTemplate.rptInstance.templaters[this.id].parse(obj, null, _debug));
				} else {
					$(this).replaceWith('');
				};
				
				_result = $.fn.fillTemplate.rptInstance.templaters[this.id];
            }
 
        });
		
		return _result;
    };
    
    $.fn.fillTemplate.rptInstance = null;
    
    $.fn.fillTemplate.jsRepeater = function(){
        this.templaters = {}; 
    };
    
    $.fn.fillTemplate.templater = function(){
        this.templaters = {}; this.Context = null; this.template = "";
        this.isRoot = true; this.mirrorID = null;
    };
        
    var templater = $.fn.fillTemplate.templater;
    
    templater.prototype.initialise = function(rootNode){
        if ((rootNode.getAttribute) && (rootNode.getAttribute("context"))){
			this.Context = rootNode.getAttributeNode("context").nodeValue;
        }
		if ((rootNode.getAttribute) && (rootNode.getAttribute("filter"))){
			this.Filter = $.parseJSON(rootNode.getAttributeNode("filter").nodeValue);
        }
		if ((rootNode.getAttribute) && (rootNode.getAttribute("top"))){
			this.Top = $.parseJSON(rootNode.getAttributeNode("top").nodeValue);
        }
		if ((rootNode.getAttribute) && (rootNode.getAttribute("edit"))){
			this.Edit = $.parseJSON(rootNode.getAttributeNode("edit").nodeValue);
        }
        for (var i=0; i<rootNode.childNodes.length; i++){
            this.extractSubTemplates(rootNode, rootNode.childNodes[i]);
        }
        
        this.template = $.mtgcOuterHTML(rootNode);
    };
    templater.prototype.initialiseMirror = function(rootNode){
        var tempNode = document.createElement("div");
        tempNode.appendChild(rootNode.cloneNode(false));
        var Marker = document.createTextNode("STATIC");
        tempNode.childNodes[0].appendChild(Marker);
        this.template = tempNode.innerHTML;
    };
    templater.prototype.parseOrdering = function(template, ordinal, total){
        template = template.replace(/%{([^}]*)}/g,
            function(match, group1){
                var first = null; 
                var alternates = null;
                var last = null;
                
                if (group1.indexOf("|") > -1){
                    var ary = group1.split("|");
                    first = ary[0];
                    alternates = ary[1];
                    if (ary.length > 2) { last = ary[2]; }
                } else {
                    alternates = group1;
                }
                alternates = alternates.split(":");
                
                if ((ordinal == 0) && (first != null)) { return first; }
                if ((ordinal == total - 1) && (last != null)) { return last; }
                return alternates[ordinal % alternates.length];
            });
            return template;
    };
    templater.prototype.parseRecursionOrdering = function(template, data, recursionCount, ob){
        template = template.replace(/!%{([^}]*)}/g,
            function(match, group1){
                var first = null; 
                var alternates = null;
                var last = null;
                
                if (group1.indexOf("|") > -1){
                    var ary = group1.split("|");
                    first = ary[0];
                    alternates = ary[1];
                    if (ary.length > 2) { last = ary[2]; }
                } else {
                    alternates = group1;
                }
                alternates = alternates.split(":");
                
                if ((recursionCount == 0) && (first != null)) { return first; }
                //if ((ordinal == total - 1) && (last != null)) { return last; }
                return alternates[recursionCount % alternates.length];
            });
            return template;
    };
    templater.prototype.parseNumbering = function(template, ordinal, total){    
        template = template.replace(/#{([^}]*)}/g,
            function(match, group1){
                return ordinal + 1;
            });
            return template;
    };
    templater.prototype.parseRecursive = function(template, data, recursionCount, ob){

    template = template.replace(/!{([^}]*)}/g,
        function(match, group1){
            if (group1 > recursionCount){
                if (ob.Context == null) { return ""; }
                var contextData = data[ob.Context];
                if ((contextData == null) || (contextData == undefined)) { return ""; }
                return ob.parse(data, recursionCount + 1);
            } else { return ""; }
        });
        return template;
    };
    templater.prototype.parse = function(data, recursionCount, _debug){
        if (_debug) debugger;
        var result = ""; 
        var self = this;
		if (this.mirrorID){
            result += this.template.replace(/(STATIC)/g,                
                    function(match, group1) {    
                        return document.getElementById(self.mirrorID).innerHTML;    
                             
                    } ); 
            return result;
        }
        if ((recursionCount == null) || (recursionCount == undefined)) { recursionCount = 0; }
        var contextData = null;
        if (this.Context) { contextData = data[this.Context]; } else { contextData = data; }
        if ((contextData == null) || (contextData == undefined)) {   contextData = {}; }
        if (contextData instanceof Array) { 
			var count = 0;
			for(var i = 0; i < contextData.length; i++){
                var obj = contextData[i];
                if (obj) {				
				    if(this.filter(obj, this.Filter)){
					    if ((this.Top == null) || (this.Top == undefined) || (count < this.Top)) {
						    result += this.template.replace(/\#\{([^}]*)\}/g,                
		                        function(match, group1) { 
								    var outer = group1.split(":");
		                            var val = outer[0];
		                            var f = null;
		                            if (outer.length > 1) { f = outer[1]; }
		                            var ary = val.split(".");
		                            var newObj = obj;
    		                        
		                            for(var j=0; j<ary.length; j++){
		                                newObj = newObj[ary[j]];
    		                            
		                                if (newObj == undefined) { 
		                                    if (f != null) { return eval(f + '(newObj);'); }
		                                    else { return newObj; }   
		                                }
		                            }  
		                            if (f != null) { return eval(f + '(newObj);'); }
		                            else { return newObj; }               
		                        } ); 
		                     var self = this;   
						    result = this.parseNumbering(result, i, contextData.length);
						    result = this.parseRecursionOrdering(result, contextData[i], recursionCount, this);
						    result = this.parseOrdering(result, i, contextData.length);
    						
						    result = this.parseRecursive(result, contextData[i], recursionCount, this);
    		                    	                
		                    result = result.replace(/\~\{([^}]*)\}/g,            
		                            function(match, group1) {    
									    return self.templaters[group1].parse(contextData[i]);       
								    } );  
    						
						    count += 1;
					    }
				    };
				};
            }
        } else {
            var obj = contextData; 
			if(this.filter(obj, this.Filter)){
	            result += this.template.replace(/\#\{([^}]*)\}/g,                
	                    function(match, group1) { 
	                        var outer = group1.split(":");
	                        var val = outer[0];
	                        var f = null;
	                        if (outer.length > 1) { f = outer[1]; }
	                             
	                        ary = val.split(".");
	                        var newObj = obj;
	                        
	                        for(var j=0; j<ary.length; j++){
	                            newObj = newObj[ary[j]];
	                            
	                            if (newObj == undefined) { 
	                                if (f != null) { return eval(f + '(newObj);'); }
	                                else { return newObj; }
	                             }
	                        }  
	                        if (f != null) { return eval(f + '(newObj);'); }
	                                else { return newObj; }         
	                    } );
	              var self = this;      
	                    result = this.parseNumbering(result, i, contextData.length);
	                    result = this.parseRecursionOrdering(result, contextData, recursionCount, this);
	                    result = this.parseOrdering(result, 0, 1);
	                    
	                    result = this.parseRecursive(result, contextData, recursionCount, this);
	                    
	            
	            result = result.replace(/\~\{([^}]*)\}/g,            
	            function(match, group1) {      
	                        return self.templaters[group1].parse(contextData);       
	                    } );
			};
        }  
        result = result.replace(/jQuery[0-9]{13}=\".+?\"/g, '');
        return result; 
    };
    templater.prototype.extractSubTemplates = function(sourceTree, node){
        var plucked = null;
        var markerID = null;
        var markerNode = null;
        var Subtemplater = null;
        if ((node.getAttribute) && (node.getAttribute("template"))){
            plucked = node;
            markerID = this.newGuid();
            markerNode = document.createTextNode("~{" + markerID + "}");
            sourceTree.replaceChild(markerNode, node);
            Subtemplater = new $.fn.fillTemplate.templater();
            Subtemplater.isRoot = false;
            Subtemplater.mirrorID = node.getAttributeNode("ID").nodeValue;
            this.templaters[markerID] = Subtemplater;
            Subtemplater.initialiseMirror(plucked);
            return;
        }
        if ((node.getAttribute) && (node.getAttribute("context"))){

        plucked = node;
        markerID = this.newGuid();
        markerNode = document.createTextNode("~{" + markerID + "}");

        sourceTree.replaceChild(markerNode, node);
        
        Subtemplater = new $.fn.fillTemplate.templater();
        Subtemplater.isRoot = false;
        this.templaters[markerID] = Subtemplater;
        Subtemplater.initialise(plucked);
        }
        else {
            for (var i=0; i<node.childNodes.length; i++){
                this.extractSubTemplates(node, node.childNodes[i]);
            }
        }
    };
    templater.prototype.S4 = function(){
        return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
    };  
    templater.prototype.newGuid = function(){
        return (this.S4()+this.S4()+"-"+this.S4()+"-"+this.S4()+"-"+this.S4()+"-"+this.S4()+this.S4()+this.S4()).toUpperCase();
    };
	templater.prototype.filter = function(_obj, _filter){
		var filterOK = true;
		if (_filter){
			$.each(_filter, function(key, value){
				var _OBJvalues = getValue(_obj, key);
				_OBJvalues = _OBJvalues.split('||');
				
				if ((_OBJvalues) && (filterOK)){
					if (value instanceof Array) {
						var _filterAND = true;
						if ((_OBJvalues.length == 1) && (_OBJvalues[0] == '')) {
							_filterAND = false;
						} else {
							for(var j=0; j<value.length; j++){
								var _filterOR = false;
								for(var k=0; k<_OBJvalues.length; k++){
									if (_OBJvalues[k]==value[j]) _filterOR = true;
								};
								if (!_filterOR) _filterAND = _filterOR;
							};
						};
						filterOK = _filterAND;
					} else {
						var _filterOR = false;
						for(var k=0; k<_OBJvalues.length; k++){
							if(_OBJvalues[k]==value) _filterOR = true;
						};
						filterOK = _filterOR;
					};
				};
			});
		};
		
		return filterOK;
	};
	templater.prototype.edit = function(obj){
		var _value = obj.value;
		if (this.Edit){
			$.each(this.Edit, function(key, value){
				if (obj[key]){
					if (value instanceof Array) {
						
					} else {
						
					};
				};
			});
		};
		
		return _value;
	};
})(jQuery);

function getValue(_obj, _key){
	var resValue = '';
	var _ary = _key.split(".");
	var _newkey = '';
	for(var i=1; i<_ary.length; i++){
		_newkey += _ary[i] + '.';
	};
	if(_newkey!='') _newkey = String(_newkey).substring(0,String(_newkey).length-1);
	var newObj = _obj;
	for(var j=0; j<_ary.length; j++){
		if (newObj instanceof Array) {
			for(var i=0; i<newObj.length; i++){
				if(i>0) {
					resValue += '||' + getValue(newObj[i], _newkey);
				} else {
					resValue += getValue(newObj[i], _newkey);
				};
			};
			return resValue;
		} else {
			newObj = newObj[_ary[j]];
		};
	} ;
	
	return resValue + newObj;
};