
Cookie = {
    set: function(name, value, days) {
        if (days) {
            var date = new Date();
            date.setTime(date.getTime() + (days * 24*60*60*1000));
            var expires = "; expires=" + date.toGMTString();
        }
        else var expires = "";
        document.cookie = name + "=" + value + expires + "; path=/";
    },
    
    read: function(name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for(var i=0; i < ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0)==' ') c = c.substring(1,c.length);
            if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
        }
        return null;
    },
    
    erase: function(name) {
        Cookie.set(name, "", -1);
    }
};

Util = {
    // attach event handler while properly considering (aka chaining) an existing one
    registerDocumentEventHandler: function(event, func) {
        var oldHandler = window.document[event];
        if (typeof window.document[event] != 'function') {
            window.document[event] = func;
        } else {
            // chain old with new func
            window.document[event] = function(e) {
                if (oldHandler) {
                    oldHandler(e);
                }
                func(e);
            }
        }
    },
	
	eventWrapper: function(func) {
		return function(e) {
	        var keyCode, event;
	        if (document.all) {
	            keyCode = window.event.keyCode;
	            event = window.event;
	        } else {
	            keyCode = (typeof(e.which) != 'undefined') ? e.which : 0;
	            event = e;
	        }
			if (event) {
				func(event, keyCode);
			}
		}
	},
	
	addStylesheet: function(href) {
        if (document.createStyleSheet) {
            document.createStyleSheet(href);
        } else {
            var link = document.createElement('link');
            link.rel = "stylesheet";
            link.type = "text/css";
			link.href = href;
            document.getElementsByTagName("head")[0].appendChild(link);
        }
	},
	
	createLink: function(text, func, props) {
        var link = document.createElement("a");
        link.href = "#";
        link.onclick = func;
        link.innerHTML = text;
		if (props) {
			for (var p in props) {
				if (props.hasOwnProperty(p)) {
					link[p] = props[p];
				}
			}
		}
		return link;
	}
};

TagCloud = function(taglist) {
	
	function parseTagList(taglist) {
        var tags = {};
        var tagArray = taglist.split(",");
        for (var t in tagArray) {
            if (tagArray.hasOwnProperty(t)) {
                var entry = tagArray[t].split("=");
                if (entry.length == 2) {
                    tags[entry[0]] = parseInt(entry[1]);
                }
            }
        }
        return tags;
	}
	
	return {
		tags: (taglist ? parseTagList(taglist) : {}),
		addedTags: [],
		frequencies: null,
		
		/**
		 * Parses a string in the form "foobar=2,bla=3", with entries
		 * being <tagid>=<count>.
		 */
		parseString: function(taglist) {
			this.tags = parseTagList(taglist);
			return this;
		},
		
		toString: function() {
			var list = null;
			for (var t in this.tags) {
				if (this.tags.hasOwnProperty(t)) {
	                list = (list === null ? "" : list + ",");
	                list += (t + "=" + this.tags[t]);
				}
			}
			return list;
		},
		
		add: function(tag) {
			this.addedTags[tag] = true;
			this.tags[tag] = (this.tags[tag] || 0) + 1;
		},
		
		each: function(func /*(tag, count)*/) {
			for (var t in this.tags) {
				if (this.tags.hasOwnProperty(t)) {
					func(t, this.tags[t]);
				}
			}
		},
		
        calculateFrequencies: function() {
	        var freqSet = {};
			var freqArray = [];
			
			this.each(function(tag, count) {
				if (!freqSet[count]) {
					freqArray.push(count);
				}
				freqSet[count] = true;
			});
			
			freqArray.sort(function compareNumbers(a, b) {
				if(a > b)
    				return 1;
				if(a < b)
	       			return -1;
				return 0;
			});
			
			return freqArray;
	    },
		
		calculateNtile: function(frequency, n) {
			if (this.frequencies === null) {
				this.frequencies = this.calculateFrequencies();
			}
	        var i = 0;
	        while (true) {
	            // if we reach the end of the array, return the maximum
	            // otherwise if we found the frequency or a higher value in the array
	            if ((i >= (this.frequencies.length - 1)) || (this.frequencies[i] >= frequency)) {
	                return Math.ceil( (i+1) / this.frequencies.length * n );
	            }
	            i++;
	        }
		}
        
	}
};

TagCloudBox = function(tagCloud, title, parent) {
	
    function createBox(tagCloudBox) {
        var box = document.createElement("div");
        box.id = "clickstreamcloud-box";
		box.style.display = "none";
		
        var div = document.createElement("div");
        
        var header = document.createElement("div");
        header.className = "header";
        div.appendChild(header);

        var titleDiv = document.createElement("div");
        titleDiv.innerHTML = title;
        titleDiv.className = "title";
        header.appendChild(titleDiv);
        
        header.appendChild(Util.createLink("x",
		    function() {
    			box.style.display = "none";
				tagCloudBox.onVisibilityChange();
			},
			{ "className": "close" }
		));
		
		var cloud = document.createElement("p");
		cloud.className = "cloud";
		tagCloud.each(function(tag, count) {
			var li = document.createElement("span");
			var dectil = tagCloud.calculateNtile(count, 10);
			var namespaceSplit = tag.split(":");
			var pathSplit = namespaceSplit[namespaceSplit.length-1].split("/");
			li.innerHTML = pathSplit[pathSplit.length-1] + "<span class='count tag" + dectil + "'>&nbsp;(" + count + ")</span>";
			li.className = "tag";
			if (tagCloud.addedTags[tag]) {
				li.className += " new";
			}
			li.className += " tag" + dectil;
			li.title = tag + " (" + count + ")";
			cloud.appendChild(li);
			// for proper wrapping in IE
			cloud.appendChild(document.createTextNode(" "));
		});
		div.appendChild(cloud);
		
        var linkContainer = document.createElement("div");
		linkContainer.className = "links";
        linkContainer.appendChild(Util.createLink("Clear tags",
		    function() {
	            cloud.innerHTML = "";
				tagCloudBox.onClearTags();
		    }
		));
		var toggleCountLink = Util.createLink("Display count",
            function() {
                if (cloud.className.match(/show-count/)) {
                    cloud.className = cloud.className.replace(/show-count/, "");
					toggleCountLink.innerHTML = "Display count";
                } else {
                    cloud.className += " show-count";
                    toggleCountLink.innerHTML = "Hide count";
                }
            }
        );
        linkContainer.appendChild(toggleCountLink);
		div.appendChild(linkContainer);

		box.appendChild(div);
				
        parent.appendChild(box);
		
		var border = RUZEE.ShadedBorder.create({ corner:10, border:2, shadow:21 });
		border.render(div);
		
		return box;
    }
	
	return {
		box: null,
		
		onClearTags: function() {},
		
		onVisibilityChange: function() {},
		
		isVisible: function() {
			return (this.box != null && this.box.style.display != "none");
		},
		
		toggle: function() {
			if (this.isVisible()) {
                this.hide();
			} else {
                this.show();
			}
		},
		
		show: function() {
			if (!this.box) {
                this.box = createBox(this);
			}
			this.box.style.display = "block";
			this.onVisibilityChange();
		},
		
		hide: function() {
            if (this.box) {
                this.box.style.display = "none";
            }
            this.onVisibilityChange();
		}
	};
	
};

ClickstreamCloud = {
	setup: function(pageTags, parent) {
//        var CLOUD_KEY = "tagcloud";
        var CLOUD_COOKIE = "clickstreamcloud";
        var SHOW_BOX_COOKIE = "show-clickstreamcloud";
    
//        TODO: get PersistJS to work on all browsers
//        var store = new Persist.Store("clickstreamcloud");
//        store.get(CLOUD_KEY, function(ok, value) {
//            value = ok ? value : null;
//            // convert to real string in case it is a "magic" globalstorage object
//            value = value === null ? "" : new String(value);
//            var tagCloud = new TagCloud(value);
            var tagCloud = new TagCloud(Cookie.read(CLOUD_COOKIE) || "");
			
            // store in globally accessible location
            window.clickstreamcloud = tagCloud;
			
			// add current page tags to cloud
	        for (var i in pageTags) {
				if (pageTags.hasOwnProperty(i)) {
					tagCloud.add(pageTags[i]);
				}
			}
			
			// persist new tag cloud
//            store.set(CLOUD_KEY, tagCloud.toString());
            Cookie.set(CLOUD_COOKIE, tagCloud.toString(), 365 /* days */);

            // setup GUI
            window.setTimeout(function() {
	            var box = new TagCloudBox(tagCloud, "Clickstream Cloud:", parent);
				
	            if (Cookie.read(SHOW_BOX_COOKIE) == "true") {
	                box.show();
	            }
	        
	            box.onVisibilityChange = function() {
	                Cookie.set(SHOW_BOX_COOKIE, box.isVisible() ? "true" : "false", 365 /* days */);
	            };
	            box.onClearTags = function() {
	//                store.remove(CLOUD_KEY);
	                Cookie.erase(CLOUD_COOKIE);
	            };
	        
	            Util.registerDocumentEventHandler("onkeydown", Util.eventWrapper(function(event, keyCode) {
	                if (event.ctrlKey && event.altKey && keyCode == "C".charCodeAt(0)) { // 84
	                    box.toggle();
	                }
	            }));
			}, 500);
//        });
	}
}; 

