/*
 * 	 imList - A JQuery Plugin
 * 	 @author Les Green
 * 	 Copyright (C) 2008 Intriguing Minds, Inc.
 *   Version 1.0
 *  	 
 *   Change Log: Date: Feb 10, 2009
 *   1. added ol/ul	
 *   2. added confirm delete popup
 *   3. added stripe_class option. can set both odd and even: stripe_class: {odd: "odd", even: "even"}
 *   4. Added Ajax error popup
 *   5. added addClass to <li> using opts.display.li_class
 * 
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.

 *   Demo and Documentation can be found at:   
 *   http://www.grasshopperpebbles.com
 *   
 */


;(function($) {
	$.fn.extend({
        imList: function(options) { 
        	opts = $.extend({}, $.listDisplay.defaults, options);
			return this.each(function() {
				new $.listDisplay(this, opts);
			});
			//console.log($this.attr('id'));
        }
    });	
	
$.listDisplay = function(obj, opts) {
	var links = new Array();
	var dbParams = new Array();
	var tableRow = new Array();
	var list = '';
	var $this = $(obj);
		
	if (opts.db_map != '') {
		var d = getDataString();
		doAjax('GET', opts.data_url, d, '', doCreate);
	}
	function getDataString() {
		var str = '';
		$.each(opts.data, function(i, itm) {
			str += itm.name + "=" + itm.value + "&";							
		});
		//remove last "&"
		//str = str.substr(0, (str.length-1));
		str = str.substr(0, (str.length-1));
		return str;
	};
		
	function doAjax(t, u, d, fnBefore, fnSuccess) {
		$.ajax({
			type: t,
			url: u,
			data: d,
			error: showError,
			dataType: 'json',
			beforeSend: fnBefore, //function(){$("#loading").show("fast");}, //show loading just when link is clicked
			//complete: function(){ $("#loading").hide("fast");}, //stop showing loading when the process is complete
			success: fnSuccess//{ //so, if data is retrieved, store it in html
	 	}); //close $.ajax(
	};

	function showError(XMLHttpRequest, textStatus, errorThrown) {
		alert(textStatus);
		console.log(textStatus);
	};
	
	function getParams(row, params) {
		var str = '';	
		$.each(params, function(i, itm) {
			if (itm.fromDB) {
				str += itm.name + "=" + row[itm.value] + "&";		
			} else {
				str += itm.name + "=" + itm.value + "&";
			}
		});
		//remove last '&';
		str = str.substr(0, (str.length-1));
		return str;
	};
	
	function doCreate(data) {
		list = (opts.display.type == 'self') ? '' : document.createElement(opts.display.type);
		//list = document.createElement(opts.display.type);
		if (opts.display.type != 'self') {
			if (opts.display.name != '') {
				$(list).attr("name", opts.display.name);
			}
			if (opts.display.id != '') {
				$(list).attr("id", opts.display.id);
			}
			if (opts.display.class != '') {
				$(list).addClass(opts.display.class);
			}
		}
		switch (opts.display.type) {
			case "table": createTable(data); break;
			case "ul": createList(data); break;
			case "ol": createList(data); break;
			case "select": createSelect(data); break;
			case "div": createDiv(data); break;
			case "self": createDiv(data); break;
		}
	};
	
	function createTable(data) {
		$(list).attr({width: opts.width, border : "0"});
		if (opts.header_cols) {
			var tr = createHeader('tr', 'th');
			$(list).append(tr);
		}
		$.each(data, function(i, itm) {
			var tr = document.createElement('tr');
			$.each(opts.db_map, function(j, map) {
				var td = document.createElement('td');
				//var fld = ((map.url) || (map.func)) ? getLink(itm, map) : getDbField(itm, map.name);
				var fld = doFormat(data, itm, map);
				$(td).append(fld);
				$(tr).append(td);
				$(list).append(tr);
			});
		});
		
		$this.append($(list));
		if (opts.stripe_class) {
			if (opts.stripe_class.odd) {
				$('tr:odd', $(list)).addClass(opts.stripe_class.odd);
				//$(list + ' tbody tr:not([th]):odd').addClass(opts.stripe_class);
			}
			if (opts.stripe_class.even) {
				$('tr:even', $(list)).addClass(opts.stripe_class.even);
				//$(list + ' tbody tr:not([th]):odd').addClass(opts.stripe_class);
			}
		}
	};
	
	function createList(data) {
		if (opts.header_cols) {
			var h = createHeader('', 'h3');	
			$this.append($(h));
		}
		//var ul = document.createElement(opts.display_list);
		//console.log(data);
		$.each(data, function(i, itm) {
			$.each(opts.db_map, function(j, map) {
				var li = document.createElement('li');	
				//var fld = ((map.url) || (map.func)) ? getLink(itm, map) : getDbField(itm, map.name);
				var fld = doFormat(data, itm, map);
				if (opts.display.li_class) {
					$(li).addClass(opts.display.li_class);
				}
				$(li).append(fld);
				$(list).append(li);
			});
		});
		if (opts.footer) {
			$.each(opts.footer, function(j, map) {
				//$.each(data, function(i, itm) {						 
					var li = document.createElement('li');	
					//var fld = ((map.url) || (map.func)) ? getLink('', map) : getDbField('', map.name);
					var fld = doFormat(data, itm, map);
					$(li).append(fld);
					$(list).append(li);
				//});
			});
		}
		$this.append($(list));
	};
	
	function createSelect(data) {
		if (opts.display.multiple) {
			$(list).attr("multiple", "multiple");	
		}
		$.each(data, function(i, itm) {
			$(list).append('<option value="'+itm[opts.db_map.value]+'">'+itm[opts.db_map.label]+'</option>');
		});
		$this.append($(list));
	};
	
	function createDiv(data) {
		if (opts.header_cols) {
			var h = createHeader('', 'h3');	
			$this.append($(h));
		}
		
		$.each(data, function(i, itm) {
			//must have a class if opt.display.type = 'self'
			if (opts.display.type == 'self') {
				//in this case $(list) is parent container: list = this
				// this div will be the conainter for each row of data
				list = document.createElement('div');
				$(list).addClass(opts.display.class);
			}				  
			$.each(opts.db_map, function(j, map) {
				var fld = doFormat(data, itm, map);	
				if (map.class) {
					$(list).append($('<div></div>')
						.addClass(map.class)
						.append(fld));
				} else {
					$(list).append(fld);	
				}
				if (opts.display.type == 'self') {
					$this.append($(list));
				}
				if (map.afterLoad) {
					afterLoad(itm, map.afterLoad);
				}
			});
		});
		if (opts.display.type != 'self') {
			$this.append($(list));
		}
	};
	
	function afterLoad(row, map) {
		var fn = eval(map.name);
		if (map.params) {
			var pVal = '';
			$.each(map.params, function(i, prm) {
				if (prm.fromDB) {
					pVal += row[prm.param] + ", ";	
				} else {
					pVal += prm.param + ", ";
				}
			});
			pVal = pVal.substr(0, pVal.length-2);
			fn (pVal);
		} else {
			fn ();
		}
	};
	
	function createHeader(cntnr, element) {
		var c, h;
		if (cntnr != '') {
			c = document.createElement(cntnr);
		}
		$.each(opts.header_cols, function(i, itm) {
			h = document.createElement(element);
			$(h).append(itm.caption);
			if (element == 'th') {				
				if (itm.width) {
					$(h).attr("width", itm.width);
				}
				if (opts.header_cols.length == 1) {
					$(h).attr("colspan", opts.data_map.length);	
				}
				if (itm.align) {
					$(h).css("text-align", itm.align);	
				}
			}
			if (opts.header_class != '') {
				$(h).addClass(opts.header_class);	
			}
			if (cntnr != '') {
				$(c).append(h);
			}
		});
		if (cntnr == '') {
			return h;
		} else {
			return c;
		}
	};

	function doFormat(data, row, map) {
		var v;
		switch (map.type) {
			case "db": v = getDbField(row, map); break;
			case "text": v = map.value; break;
			case "regex": v = getRegex(data, row, map.value); break;
		}
		v = ((map.url) || (map.func)) ? getLink(row, map, v) : v;
		return v;
	};
	
	function getDbField(row, map) {
		var sep = (map.separator) ? map.separator : '';
		var ln = sep.length;
		var cols = map.value;
		var c = cols.split(", ");
		var v = '';
		if (c.length == 1) {
			v = row[cols];	
		} else {
			$.each(c, function(i, itm) {
				v += row[itm] + sep;			   
			});
		}
		if (map.separator) v = v.substr(0, (v.length-ln));
		return v;
	};
	
	function getRegex(data, row, v) {
		var r, l;
		var b = "before";
		var f = "flds";
		var bt = "between";
		var a = "after";
		var a_str = [];
		a_str[b] = '';
		a_str[f] = [];
		a_str[bt] = [];
		a_str[a] = '';
		var patt = new RegExp("<imList>(.*?)<\/imList>", "g");
		//get everything before <im>
		var be = new RegExp("(.*?)<im>", "i");
		//a_str[a_str.length] = b.exec(v)[1];
		a_str[b] = be.exec(v)[1];
		
		//get fields
		var db = new RegExp("<im>(.*?)<\/im>", "g");
		var flds = v.match(db);
		$.each(flds, function(i, itm) {
			a_str[f][i]	= row[db.exec(itm)[1]];
			db = new RegExp("<im>(.*?)<\/im>", "g");
		});
		
		//get everything between fields
		if (flds.length > 1) {
			var btw = new RegExp("<\/im>(.*?)<im>", "g");
			
			var bw = v.match(btw);
			$.each(bw, function(i, itm) {
				var js = btw.exec(itm)[1];
				if (patt.test(js)) {
					a_str[bt][i] = callImFunc(data, js);
				} else {
					a_str[bt][i] = js;	
				}
				btw = new RegExp("<\/im>(.*?)<im>", "g");
			});
		}

		//get everthing after
		var aft = new RegExp("</\im>(.*?)", "g");
		var li;
		var ma = v.match(aft);
		var ln = ma.length;
		for (var i = 0; i < ln; i++) {
			aft.test(v);
			if (i == (ln-1)) {
				li = aft.lastIndex;
			}
		}
		a_str[a] = v.substr(li, v.length);
		if (patt.test(a_str[a])) {
			a_str[a] = getImFuncRegex(row, a_str[a]);
		}
		//return result
		r = a_str[b];
		$.each(a_str[f], function(i, itm) {
			r += itm;
			//if (itm != '') {
			if (a_str[bt][i]) {
				r += a_str[bt][i];	
			}
			//}
		});
		r += a_str[a];
		return r;
	};
	
	function getImFuncRegex(data, v) {
		var r, l;
		var b = "before";
		var a = "after";
		var a_str = [];
		a_str[b] = '';
		a_str[a] = '';
		//var patt = new RegExp("<imList>(.*?)<\/imList>", "g");
		//get everything before <im>
		var be = new RegExp("(.*?)<imList>", "i");
		//a_str[a_str.length] = b.exec(v)[1];
		a_str[b] = be.exec(v)[1];
				
		//get fields
		var j = new RegExp("<imList>(.*?)<\/imList>", "g");
		//var js = v.match(j);
		var js = j.exec(v)[1];

		js = callImFunc(data, js);
		//get everthing after
		var aft = new RegExp("</\imList>(.*?)", "g");
		var li;
		var ma = v.match(aft);
		var ln = ma.length;
		for (var i = 0; i < ln; i++) {
			aft.test(v);
			if (i == (ln-1)) {
				li = aft.lastIndex;
			}
		}
		a_str[a] = v.substr(li, v.length);
		
		//return result
		r = a_str[b] + js + a_str[a];
		return r;
	};
	
	function callImFunc(data, js) {
		//console.log(js);
		var j = js.parseJSON();
		return doMultValues(data, j);
	}
	
	function doMultValues(data, itm) {
		//formatting is used to create multiple values on a page that are numbered sequentially. cbh_1, cbh_2, etc.
		var ln = data[itm.name].length;
		var d = '';
		var affix = itm.format[0].value;
		for (var j=0;j<ln;j++) {
			var fieldVal = data[itm.name][j][itm.db_field];
			if (itm.format) {
				switch (itm.format[0].name) {
					case "prefix": fieldVal = affix + fieldVal; break;
					case "suffix": fieldVal = fieldVal + affix; break;
				}
			}
			d += fieldVal;
		}
		ln = affix.length;
		d = d.substr(0, d.length-ln);
		return d;
	};
	
	function getLink(row, map, v) {
		var url = '';
		var prms = '';
		if (map.url) {
			//if (map.url == "#") {
				//console.log(row);
			//	url = row.fromDB;	
			//} else {
				url = map.url;
			//}
		}
		if (map.params) {
			prms = getParams(row, map.params);
			url += '?' + prms;
		}
		var a = document.createElement('a');
		//var v = (map.format) ? doFormat(itm, map.format) : getDbField(itm, map.name);
		if (map.func) {
			$(a)
		 		.attr("href", "#")
				.click(function() {
					var f = eval(map.func);
					//doDeleteRow
					f(this, map.url, prms);
					return false;
				});
		} else {
			$(a).attr("href", url);
		}
	 	$(a).append(v);
		return a;
	};
	
	function showPagination() {
		var pageInfo = document.getElementById('cartCaption');
		//clearDiv(pageInfo);
		var p = document.createElement('p');
		$(p).append(document.createTextNode('Page:  '));
		//var pgTxt = document.createTextNode('Page:  ');
		//p.appendChild(pgTxt);
		for (var i=1; i<=$this.numPages; i++) {
			$(p)
				.append(getPageLink(i))
				.append(document.createTextNode(' | '));
			//var a = getPageLink(i);
			//p.appendChild(a);
			//var sep = document.createTextNode(' | ');
			//p.appendChild(sep);	
		}
		//var a = this.getPageLink('View All');
		//p.appendChild(a);
		//pageInfo.appendChild(p);
		$('#'+settings.navContainer).append($p);
	};

	function doDeleteRow(el, url, params) {
		//var cell = $(el).parent("td");
		//var row = $(cell).parent("tr")
		//console.log(row[0].sectionRowIndex);
		tableRow[tableRow.length] = $(el).parent().parent();
		//tableRow[tableRow.length] = row;
		var c = confirm("Delete Row?");
		if (c) {
			doAjax('POST', url, params, '', doDelete);
		}
	};
	
	function deleteChecked(url, params) {
		var ch_val = new Array();
		$("input:checked", $this).each(function(i) {
			ch_val[ch_val.length] = this.val();								   
			tableRow[tableRow.length] = this.parent().parent();								   
		});
		if(ch_val.length>0) {
			var v = ch_val.toString();
			var p = (url.match("/?/")) ? "&tRows=" : "?tRows=";
			params += p + v;
			doAjax('POST', url, params, '', doDelete);
    	}
		/*var inputs = table.getElementsByTagName('input');
		var nL = inputs.length;
		if (nL != 0) {
			for (i = 0; i < inputs.length; i++) {
    			if (inputs[i].type == 'checkbox') {
					if (inputs[i].checked == true) {
						chbxVal[chbxVal.length] = inputs[i].value;
						//aRowIndex.push(inputs[i].parentNode.parentNode.rowIndex);
						aRowIndex[aRowIndex.length] = inputs[i].parentNode.parentNode.rowIndex;
						//alert(aRowIndex[0]);
					}
				}
			}
		}
		if(chbxVal.length>0) {
			var sVal = chbxVal.toString();
			var params = (sURL.match("/?/")) ? "&tRows=" : "?tRows=";
			imAjx.doGet(sURL + params + sVal, doDelete);
			//doDelete("deleted");
    	} else { 
        	alert("No records selected.");
    	}*/
	};
	
	function doDelete(result) {
		if (result.label == "Record Deleted") {
			$.each(tableRow, function(i, itm) {
				console.log(i);
				//$(table + 'tr:eq('+i+')').remove();
				$(itm).remove();
			});
			/*var nL = aRowIndex.length;
			for (i=0;i<nL;i++) {
				table.deleteRow(aRowIndex[i]-i);
			}*/
		}
		tableRow = [];
	};
};
	
$.listDisplay.defaults = {
		/*header_cols: [{"caption": "Name", "width" : "80%"}, {"name": "Date Added", "width" : "20%"}],
		header_class: '',
		data_url: '../includes/controllers/dbActionController.php',
		data: '',
		db_map: '[{"name": "event_name", "url": "whatever.php", "params" :
				  												[{"name": "action", "value": "doGetJson"}, 
																 {"name": "event_id", "value": "event_id", "fromDB": "true"}]},
				  {"name": "add_date"}]'*/
	//display: {"name": '', "id": '', "type": 'table', "class": '', "nav": ''},	
	display: {"name": '', "id": '', "type": 'gallery', "class": '', "nav": ''},	
	header_cols: '',
	header_class: '',
	width: '100%',
	stripe_class: '',
	data_url: '',
	data: '',
	db_map: '',
	footer: ''
};
// The following block implements the string.parseJSON method
(function (s) {
  // This prototype has been released into the Public Domain, 2007-03-20
  // Original Authorship: Douglas Crockford
  // Originating Website: http://www.JSON.org
  // Originating URL    : http://www.JSON.org/JSON.js

  // Augment String.prototype. We do this in an immediate anonymous function to
  // avoid defining global variables.

  // m is a table of character substitutions.

  var m = {
    '\b': '\\b',
    '\t': '\\t',
    '\n': '\\n',
    '\f': '\\f',
    '\r': '\\r',
    '"' : '\\"',
    '\\': '\\\\'
  };

  s.parseJSON = function (filter) {

    // Parsing happens in three stages. In the first stage, we run the text against
    // a regular expression which looks for non-JSON characters. We are especially
    // concerned with '()' and 'new' because they can cause invocation, and '='
    // because it can cause mutation. But just to be safe, we will reject all
    // unexpected characters.
	//console.log(this);
    try {
      if (/("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.
        test(this)) {
			
          // In the second stage we use the eval function to compile the text into a
          // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
          // in JavaScript: it can begin a block or an object literal. We wrap the text
          // in parens to eliminate the ambiguity.

          var j = eval('(' + this + ')');

          // In the optional third stage, we recursively walk the new structure, passing
          // each name/value pair to a filter function for possible transformation.

          if (typeof filter === 'function') {

            function walk(k, v) {
              if (v && typeof v === 'object') {
                for (var i in v) {
                  if (v.hasOwnProperty(i)) {
                    v[i] = walk(i, v[i]);
                  }
                }
              }
              return filter(k, v);
            }

            j = walk('', j);
          }
          return j;
        }
      } catch (e) {

      // Fall through if the regexp test fails.

      }
      throw new SyntaxError("parseJSON");
    };
  }
) (String.prototype);

})(jQuery);		   
