var Grouper = {
	generic:function( items, target, name, group, one, action, keep ){
		var last = null, letter, obj,
			grp = target = DOM.$(target);

		if( !keep )
			DOM.empty( target );
		action = action || 'append';
		if( action == 'prepend' ) items.reverse();

		for( var i = 0; i < items.length; i++ ){
			obj = items[i];
			if( name && group ){
				if( obj.numberOrdering && obj.numberOrdering < maxNumberOrdering )
					letter = obj.numberOrdering + '';
				else if( obj.numberOrdering === maxNumberOrdering && obj.nameOrdering )
					letter = obj.nameOrdering;
				else
					letter = name(obj);

				if( /^\d/.test(letter) )
					letter = '#';
				else
					letter = letter.charAt(0).toUpperCase();

				if( last !== letter ){
					grp = group( target, letter, action, keep );
					last = letter;
				}
			}
			var elem = one(obj, i, letter);
			if( elem )
				DOM[action]( grp, elem );
		}
		var d = target.style.display;
		target.style.display = 'none';
		target.style.display = d;
	},
	genericGroup:function( target, letter, action, keep ){
		var id = 'group-' + letter,
			h2 =  keep && DOM.$(id),
			group;

		if( !h2 ){
			h2 = DOM[action]( target, 'h2' );
			h2.id = id;
			DOM.text( h2, letter );
		}else{
			group = h2.nextSibling;
			while( group && group.nodeName != 'UL' )
				group = group.nextSibling;
		}
		if( !group ){
			group = DOM[action]( target, 'ul' );
			if( action == 'prepend' )
				DOM.prepend( target, h2 );
		}
		return group;
	},
	simpleGroup:function( target ){
		return DOM.append( target, 'ul' );
	},
	noGroup:function( target ){
		return target;
	},
	// generic:function( items, target, name, group, one, action, keep ){
	page:function( items, id, handler, getName, action, keep, reviewHandler, messageHandler, descriptionHandler, group ){
		Grouper.generic( items, id, getName, group || Grouper.genericGroup, function( itm, i ){
			var li = DOM.create('li'),
				anchor = DOM.append( li, 'a' );
			anchor.href = '#';
			anchor.setAttribute("onclick", handler + "('" + itm.id + "')");
			DOM.text( anchor, getName(itm, i) );

			// Appending a span to the li to wrap the buttons
			var buttonsWrap = DOM.append(li, '<span class="buttonsWrapper"></span>');

			// Appending the Map link at the end
			if( Cache('macworld') ){
				var click = function(){
					Cookie.set('mapFloor', (this.parentNode.index+1).toString() );
				};
				var map = DOM.append( buttonsWrap, '<a href="#" class="map">'+Lex.get('to_map')+'</a>');
				map.addEventListener('click', function(){
					theFloorGlobal = itm.id == 200000 ? "1": "2";
					Cookie.set('mapFloor', theFloorGlobal );
					loadMacWorld();
				}, false );
			}

			if(itm.anyReview)
				DOM.append( buttonsWrap, '<a href="#" class="rlink" onclick="' + reviewHandler + '(' + itm.id + ')">'+ Lex.get('to_rev') + '</a>');

			if(itm.anyMessageUntil != null){
				var now = new Date;

				if(itm.anyMessageUntil > now)
					// It has non expired messages
					DOM.append( buttonsWrap, '<a href="#" class="mlink" onclick="' + messageHandler + '(' + itm.id + ')">'+ Lex.get('to_msg') + '</a>');
			}

			if(itm.anyDescription)
				DOM.append( buttonsWrap, '<a href="#" class="rlink" onclick="' + descriptionHandler + '(' + itm.id + ')">'+ Lex.get('to_desc') + '</a>');

			return li;
		}, action, keep);
	},
	store:function( items, id, action, keep, group, name, address ){
		Grouper.generic( items, id, name, group || Grouper.noGroup, function( store, i ){
			var li = DOM.create('li'),
				anchor = DOM.append( li, 'a' );
			anchor.href = '#';
			anchor.setAttribute("onclick", "loadStorePage('" + store.id + "')");

			var number = DOM.append( anchor, 'span' );
			number.className = 'number';
			DOM.text( number, store.number + ' ' );
			DOM.text( anchor, store.name.truncate(storeNameTruncation) );

			var secondary = DOM.append( anchor, 'span' ), subtitle;
			secondary.className = 'secondary';
			if( address ){
				secondary.className += ' smaller';
				subtitle = makeCityStateCountry(store.street.city, store.zip).truncate(50);
			}else//keywords
				subtitle = List.map( store.keywords, 'name' ).join(', ').truncate(15);

			DOM.text( secondary, subtitle );
			return li;
		}, action, keep );
	},
	undefinedStore:function( stores, list, action, keep ){
		Grouper.store( stores, list, action, keep, Grouper.genericGroup, getStoreName, true );	
	},
	street:function( streets, list, action, keep ){
		Grouper.page( streets, list, 'loadStoresPage', function( street ){
			return street.name;
		}, action, keep, "loadReviewsPageByStreet",  "loadMessagesPageByStreet", "loadDescriptionsPageByStreet");	
	},
	messages:function( items, id ){
			var	messageUl = DOM.append(id,'ul');

			var template =
						'<li class="part">' +
							'<ul id="descriptions">' +
								'<li>' +
									'<h4>' +
										'<span><a href="#" onclick="loadStorePage({6})">Message at {5}</a></span>' +
										'<p><span class="date">{0} <span class="author">{1}</span></span></p>' +
									'</h4>' +
									'<p>{2}</p>' +
								'</li>' +
							'</ul>' +
						'</li>';

			var storeAnchor = DOM.append( messageUl, 'a' );

			messageUl.innerHTML = HtmlUtil.convertNewLines(List.map( items, function( m, i ){
				return template.format( m.tstamp.format(Lex.get('date_format')),
										FormatUtil.parseUserName(m),
										m.message,
										'Reply',
										m.id,
										m.store.name,
										m.store.id );

			}).join('') || '<li><h4><em>'+ Lex.get('no_mess') + '</em></h4></li>');

			id.id = "store";
	},
	reviews:function( items, id ){
		var	reviewUl = DOM.append(id,'ul');

		var template =
					'<li class="part">' +
						'<ul id="descriptions">' +
							'<li>' +
								'<h4>' +
									'<span><a href="#" onclick="loadStorePage({5})">Review of {4}</a></span>' +
									'<p><span class="date">{0} <span class="author"> {1}</span></span></p>' +
								'</h4>' +
								'<p>{2}<br />{3}</p>' +
							'</li>' +
						'</ul>' +
					'</li>';

		reviewUl.innerHTML = HtmlUtil.convertNewLines(List.map( items, function( c, i ){
			return template.format( c.tstamp.format(Lex.get('date_format')),
									FormatUtil.parseUserName(c),
									c.title,
									c.comment,
									c.store.name,
									c.store.id );

		}).join('') || '<li><h4><em>'+ Lex.get('no_rev') + '</em></h4></li>');

		id.id = "store";
	},
	descriptions:function( items, id ){
		var	descriptionUl = DOM.append(id,'ul');

		var template =
					'<li class="part">' +
						'<ul id="descriptions">' +
							'<li>' +
								'<h4>' +
									'<span><a href="#" onclick="loadStorePage({4})">Description of {3}</a></span>' +
									'<p><span class="date">{0} <span class="author"> {1}</span></span></p>' +
								'</h4>' +
								'<p>{2}</p>' +
							'</li>' +
						'</ul>' +
					'</li>';

		descriptionUl.innerHTML = HtmlUtil.convertNewLines(List.map( items, function( d, i ){
			return template.format( d.tstamp.format(Lex.get('date_format')),
									FormatUtil.parseUserName(d),
									d.description,
									d.store.name,
									d.store.id );

		}).join('') || '<li><h4><em>'+ Lex.get('no_desc') + '</em></h4></li>');

		id.id = "store";
	},
	letters:function( target, handler ){
		Grouper.generic( new Array(27), target, null, null, function( k, i ){
			var letter = String.fromCharCode( i ? i + 64 : 35 ),
				li = DOM.create('li'),
				anchor = DOM.append( li, 'a' );

			anchor.href = '#';
			anchor.setAttribute("onclick", handler + "('" + letter + "')");
			DOM.text( anchor, letter );
			return li;
		});
		return target;
	},
	range:function( target, start, step, handler ){
		Grouper.generic( new Array(26), target, null, null, function( k, i ){
			var value = start + step * i,
				li = DOM.create('li'),
				anchor = DOM.append( li, 'a' );

			anchor.href = '#';
			anchor.setAttribute("onclick", handler + "('" + value + "')");
			DOM.text( anchor, value );
			return li;
		});
		return target;
	}
};