﻿

(function ($) {

	var espcart = window.espcart = $.fn.espcart = function (options) {
		// make this object available inside all internal methods regardless of scope
		var $this = this;

		// extend defaults w/ passed in options
		var settings = $.fn.espcart.settings = $.extend({}, $.fn.espcart.config, options);

		var init = function () {

			// update count elements (even if no cart tokens found)
			var $counts = $(settings.countSelector);
			if ($counts.length > 0) {
				$counts.text(espcart.count);
				espcart.update.elements.count = $counts;
			}

			// kick out if no tokens
			if ($this.length < 1) {
				if (typeof console !== undefined) {
					console.log("espcart: no cart tokens found");
				}
				return this;
			}

			// store some settings for future use
			espcart.tokens.selector = $this.selector;
			espcart.update.deleteOnRemove = settings.deleteOnRemove;

			// transform tokens
			espcart.replaceTokens($this);

			

			// set selectall elements
			var $selectAllTokens = $(settings.selectAllSelector);
			if ($selectAllTokens.length > 0) {
				var tokenState = espcart.tokenState($this);
				espcart.selectAll($selectAllTokens, tokenState);
				espcart.update.elements.selectAll = $selectAllTokens;
			}

		};

		init();
		return this;

	};

	// default options, do not use
	$.fn.espcart.config = {
		countSelector: "span.count",
		deleteOnRemoveSelector: "div.Record",
		deleteOnRemove: false,
		selectAllSelector: "span.selectAll",
		tristateImgPath: "/espcart/layout/images/tristate/",
		tristateJustDual: false
	};
	
	// public config extended with options, set by constructor, ok to use
	$.fn.espcart.settings = {};

	$.fn.espcart.images = {
		add: cartConfig.addImage,
		remove: cartConfig.removeImage,
		blacklist: cartConfig.blacklistImage
	};

	$.fn.espcart.tooltips = {
		add: cartConfig.addTooltip,
		remove: cartConfig.removeTooltip,
		blacklist: cartConfig.blacklistTooltip
	};

	$.fn.espcart.text = {
		add: cartConfig.addText,
		remove: cartConfig.removeText,
		blacklist: cartConfig.blacklistText
	};

	$.fn.espcart.css = {
		add: 'add',
		remove: 'remove',
		blacklist: 'blacklist'
	};

	$.fn.espcart.tokens = {
		selector: "",
		state: {
			selected: "selected",
			unselected: "unselected",
			blacklisted: "blacklisted"
		},
		add: function (id) {
			return $("<a></a>")
                    .bind(espcart.update.event, espcart.update.handler)
                    .click(function (e) {
                    	e.preventDefault();
                    	var $that = $(this);
                    	espcart.add(id, function () {
                    		espcart.count = espcart.count + 1;
                    		$that.trigger(espcart.update.event, [espcart.count]);
                    		$that.replaceWith(espcart.tokens.remove(id));
                    	});
                    })
                    .attr('title', espcart.tooltips.add)
                    .removeClass().addClass(espcart.css.add)
                    .append($("<img/>").attr("src", espcart.images.add).attr("alt", espcart.text.add + " icon"))
                    .append($("<span></span>").text(espcart.text.add))
		},
		remove: function (id) {
			return $("<a></a>")
                        .bind(espcart.update.event, espcart.update.handler)
                        .click(function (e) {
                        	e.preventDefault();
                        	var $that = $(this);
                        	espcart.remove(id, function () {
                        		espcart.count = espcart.count - 1;
                        		$that.trigger(espcart.update.event, [espcart.count, espcart.update.elements.toDelete($that)]);
                        		$that.replaceWith(espcart.tokens.add(id));
                        	});
                        })
                        .attr('title', espcart.tooltips.remove)
                        .removeClass().addClass(espcart.css.remove)
                        .append($("<img/>").attr("src", espcart.images.remove).attr('alt', espcart.text.remove + ' icon'))
                        .append($("<span></span>").text(espcart.text.remove))
		},
		blacklist: function () {
			return $("<a></a>")
                        .click(function (e) {
                        	e.preventDefault();
                        })
                        .attr('title', espcart.tooltips.blacklist)
                        .removeClass().addClass(espcart.css.blacklist)
                        .append($("<img/>").attr("src", espcart.images.blacklist).attr('alt', espcart.text.blacklist + ' icon'))
                        .append($("<span></span>").text(espcart.text.blacklist))
		}
	};

	$.fn.espcart.url = cartConfig.updateCartLocation;

	$.fn.espcart.count = cartConfig.cartItemCount;

	$.fn.espcart.update = {
		event: "update",
		deleteOnRemove: false,
		elements: {
			toDelete: function ($that) {
				return $that.closest("div.Record"); // todo: set from plugin settings
			},
			count: $(),
			selectAll: $()
		},
		handler: function (e, count, $delete) {
			// update count html
			espcart.update.elements.count.each(function () {
				$(this).text(count);
			});
			// delete element/s from DOM
			if (espcart.update.deleteOnRemove === true && $delete !== undefined) {
				$delete.remove();
			}
			// update selectall
			espcart.selectAllState.set("intermediate");
			$.fn.tristate.set(espcart.update.elements.selectAll, espcart.selectAllState.get());
		}
	};


	$.fn.espcart.inCart = function (id) {
		return $.inArray(id, WebPubCartContents) > -1 ? true : false;
	}

	$.fn.espcart.replaceTokens = function ($els) {

		$els.each(function () {
			var $this = $(this);
			var id = espcart.trimId($this.attr("id"));
			$this.data("id", id);

			// check for blacklist status
			if (espcart.isFilterOn() === true & $.trim($this.text()) !== "") {
				if (espcart.isBlacklisted($this.text()) === true) {
					// not to be added to cart, mark as blacklisted 
					$this.empty().append(espcart.tokens.blacklist()).css("visibility", "visible");
					$this.data("state", espcart.tokens.state.blacklisted);
					return true;
				}
			}
			// check for cart status 
			if (espcart.inCart(id)) {
				// already in cart, mark with remove status 
				$this.empty().append(espcart.tokens.remove(id)).css("visibility", "visible");
				$this.data("state", espcart.tokens.state.selected);
				return true;
			}
			// not in cart, mark with add status 
			$this.empty().append(espcart.tokens.add(id)).css("visibility", "visible");
			$this.data("state", espcart.tokens.state.unselected);

		});
	};

	$.fn.espcart.addMany = function (ids, callback) {
		$.ajax({
			type: "POST",
			contentType: "application/json; charset=utf-8",
			timeout: 10000,
			url: espcart.url + "/AddMany",
			data: JSON.stringify({ 'ids': ids }),
			error: function (xhr, statusText, error) {
				if (typeof console !== "undefined") {
					console.log(xhr);
				}
			},
			success: function (results, statusText, xhr) {
				callback();
			},
			dataFilter: function (data) {
				var msg;
				if (typeof (JSON) !== 'undefined' && typeof (JSON.parse) === 'function') {
					msg = JSON.parse(data);
				}
				else {
					msg = eval('(' + data + ')');
				}

				if (msg.hasOwnProperty('d')) {
					return msg.d;
				}
				else {
					return msg;
				}
			}
		});
	};

	$.fn.espcart.removeMany = function (ids, callback) {
		$.ajax({
			type: "POST",
			contentType: "application/json; charset=utf-8",
			timeout: 10000,
			url: espcart.url + "/RemoveMany",
			data: JSON.stringify({ 'ids': ids }),
			error: function (xhr, statusText, error) {
				if (typeof console !== "undefined") {
					console.log(xhr);
				}
			},
			success: function (results, statusText, xhr) {
				callback();
			},
			dataFilter: function (data) {
				var msg;
				if (typeof (JSON) !== 'undefined' && typeof (JSON.parse) === 'function') {
					msg = JSON.parse(data);
				}
				else {
					msg = eval('(' + data + ')');
				}

				if (msg.hasOwnProperty('d')) {
					return msg.d;
				}
				else {
					return msg;
				}
			}
		});
	};

	$.fn.espcart.isFilterOn = function () {
		return WebPubCartFilterFields === undefined || WebPubCartFilterFields === null || WebPubCartFilterFields.length < 1 ? false : true;
	};

	$.fn.espcart.trimId = function (tokenId) {
		return tokenId.substring("WebPubCartToken_".length, tokenId.length);
	};

	$.fn.espcart.isBlacklisted = function (text) {
		// filters is array like [field1=value1, field2=value2]
		var filters = text.split(" | ");
		// create pair objects of filter values
		var pairs = [];
		for (var i = 0; i < filters.length; i++) {
			var split = filters[i].split("=");
			var pair = { key: $.trim(split[0]), value: $.trim(split[1]) };
			pairs.push(pair);
		}
		// check filter values against blacklist 
		var blacklist = WebPubCartFilterFields;
		for (var i = 0; i < pairs.length; i++) {
			var keyIndex = $.inArray(pairs[i].key, blacklist.keys);
			if (keyIndex > -1) {
				// key found in blacklist fields, attempt value match
				if ($.inArray(pairs[i].value, blacklist.filters[keyIndex].values) > -1) {
					// match found, this record is blacklisted 
					return true;
				}
			}
		}
		return false;
	};

	$.fn.espcart.add = function (id, callback) {
		$.ajax({
			type: "POST",
			contentType: "application/json; charset=utf-8",
			timeout: 10000,
			url: espcart.url + "/Add",
			data: "{'id': '" + id + "'}",
			error: function (xhr, statusText, error) {
				if (typeof console !== "undefined") {
					console.log(xhr);
				}
			},
			success: function (results, statusText, xhr) {
				callback();
			},
			dataFilter: function (data) {
				var msg;
				if (typeof (JSON) !== 'undefined' && typeof (JSON.parse) === 'function') {
					msg = JSON.parse(data);
				}
				else {
					msg = eval('(' + data + ')');
				}

				if (msg.hasOwnProperty('d')) {
					return msg.d;
				}
				else {
					return msg;
				}
			}
		});
	};

	$.fn.espcart.remove = function (id, callback) {
		$.ajax({
			type: "POST",
			contentType: "application/json; charset=utf-8",
			timeout: 10000,
			url: espcart.url + "/Remove",
			data: "{'id': '" + id + "'}",
			error: function (xhr, statusText, error) {
				if (typeof console !== "undefined") {
					console.log(xhr);
				}
			},
			success: function (results, statusText, xhr) {
				callback();
			},
			dataFilter: function (data) {
				var msg;
				if (typeof (JSON) !== 'undefined' && typeof (JSON.parse) === 'function') {
					msg = JSON.parse(data);
				}
				else {
					msg = eval('(' + data + ')');
				}

				if (msg.hasOwnProperty('d')) {
					return msg.d;
				}
				else {
					return msg;
				}
			}
		});
	};

	$.fn.espcart.tokenState = function ($cartTokens) {

		var count = {
			selected: 0,
			unselected: 0,
			blacklisted: 0,
			total: 0
		};

		count.total = $cartTokens.length;
		if (count.total < 1) return null;

		$cartTokens.each(function (i, el) {

			var state = $(el).data("state");

			switch (state) {
				case espcart.tokens.state.selected:
					count.selected = count.selected + 1;
					break;
				case espcart.tokens.state.unselected:
					count.unselected = count.unselected + 1;
					break;
				case espcart.tokens.state.blacklisted:
					count.blacklisted = count.blacklisted + 1;
					break;
				default:
					throw new Error("unknown token state: " + state);

			}

		});

		return count;
	};

	$.fn.espcart.selectAll = function ($selectAllTokens, cartTokenState) {

		var settings = espcart.settings;
		
		var state = espcart.selectAllState.test(cartTokenState);
		espcart.selectAllState.set(state);
		
		var addSelector = espcart.css.add != "" ? "." + espcart.css.add : "";
		var removeSelector = espcart.css.remove != "" ? "a." + espcart.css.remove : "";
		var blacklistSelector = espcart.css.blacklist != "" ? "a." + espcart.css.blacklist : "";

		if (state === null) {
			$selectAllTokens.each(function (i, el) {
				$(el).tristate({
					imgPath: settings.tristateImgPath,
					initialState: "unchecked"
				})
					.attr("disabled", "disabled")
					.addClass("disabled");
			});
		}
		else {
			$selectAllTokens.each(function (i, el) {
				$(el)
					.tristate({
						imgPath: settings.tristateImgPath,
						initialState: espcart.selectAllState.get()
					})
					.click(function () {
						switch (espcart.selectAllState.get()) {
						
							case "checked":
								// unselect selected tokens
								var $els = $(espcart.tokens.selector).find(removeSelector);
								var ids = [];
								$els.each(function (i, token) {
									var $token = $(token);
									ids.push($token.parent(espcart.tokens.selector).data("id"));
								});
								espcart.removeMany(ids, function () {
									$els.each(function (i, token) {
										espcart.count = espcart.count - 1;
										$(token)
                        					.trigger(espcart.update.event, [espcart.count, espcart.update.elements.toDelete($(token))])
                        					.replaceWith(espcart.tokens.add(id));
									});
									$.fn.tristate.set(espcart.update.elements.selectAll, "unchecked");
									espcart.selectAllState.set("unchecked");
								});
								break;

							case "intermediate":
								espcart.selectAllState.set("unchecked");
								break;

							case "unchecked":
								// select unselected tokens
								var $els = $(espcart.tokens.selector).find(addSelector);
								var ids = [];
								$els.each(function (i, token) {
									var $token = $(token);
									ids.push($token.parent(espcart.tokens.selector).data("id"));
								});
								espcart.addMany(ids, function () {
									$els.each(function (i, token) {
										espcart.count = espcart.count + 1;
										$(token)
								    		.trigger(espcart.update.event, [espcart.count])
								    		.replaceWith(espcart.tokens.remove(id));
									});
									$.fn.tristate.set(espcart.update.elements.selectAll, "checked");
									espcart.selectAllState.set("checked");
								});
								break;

							default:
								throw new Error("espcart: unknown select all state");
						}
					});
			});
		}

	};

	$.fn.espcart.selectAllState = {
			_state: "unchecked",
			get: function() { 
				if ($.fn.espcart.selectAllState._state === "intermediate" && espcart.settings.tristateJustDual === true) {
					// tristate is turned off
					return "unchecked";
				}
				return $.fn.espcart.selectAllState._state;
			},
			set: function (state) {
				$.fn.espcart.selectAllState._state = state;
			},
			test: function (tokenState) {
				var count = tokenState;
				if (count.total === count.blacklisted) {
					return null;
				}
				if (count.total === count.blacklisted + count.unselected) {
					return "unchecked";
				}
				if (count.total === count.blacklisted + count.selected) {
					return "checked";
				}
				if (espcart.settings.tristateJustDual === true) {
					// tristate is turned off, two states only, no intermediate state
					return "unchecked";	
				}
				return "intermediate";
			}
	};


})(jQuery);


/***********************************************************************
 * Copyright (c) 2010 Bit Thicket Software
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

 /*
	Modified March 2011 by Peter Tyrrell
	- intermediate may only be a starting state
	- tristate returns 'this' for chaining
	- set() static method
	- imagePath property
 */

(function($) {
    $.fn.tristate = function(settings) {
        var config = {
            initialState: 'intermediate',
            imgPath: 'images/',
            after: null
        };

        if (settings) $.extend(config, settings);

		$.fn.tristate.imagePath = config.imgPath;

        var getNextState = function(state) {
            switch (state) {
            case 'intermediate':
                return 'unchecked';
            case 'unchecked':
                return 'checked';
            case 'checked':
				return 'unchecked';
                //return 'intermediate';
            }
        }

        this.each(function() {
            var html = '<img src="' + config.imgPath + config.initialState + '.gif' + '"/>' +
                '<input type="hidden" value="' + config.initialState + '" />';
            $(this).html(html);

            $(this).unbind('click');
            $(this).click(function() {
                var nextState = getNextState($('input', this).val());
                $('img', this).attr('src', config.imgPath + nextState + '.gif');
                $('input', this).val(nextState);
            });
            $('img', this).hover(function() {   /* in */
                var src = $(this).attr('src').replace(/\.gif$/i, '_highlighted.gif');
                $(this).attr('src', src);
            }, function() {                     /* out */
                var src = $(this).attr('src').replace(/_highlighted/, '');
                $(this).attr('src', src);
            });

            if (settings.after)
                settings.after(this);
        });

		return this;
    };

	$.fn.tristate.imagePath = "";

	$.fn.tristate.set = function($this, state) {
		$('img', $this).attr('src', $.fn.tristate.imagePath + state + '.gif');
        $('input', $this).val(state);
	};
})(jQuery);




