OPENNLP-480 Added first draft of simple web demo.
diff --git a/tagging-server/src/main/resources/htmls/annotation-editor.js b/tagging-server/src/main/resources/htmls/annotation-editor.js
new file mode 100644
index 0000000..6a811a9
--- /dev/null
+++ b/tagging-server/src/main/resources/htmls/annotation-editor.js
@@ -0,0 +1,94 @@
+//   Licensed to the Apache Software Foundation (ASF) under one or more
+//   contributor license agreements.  See the NOTICE file distributed with
+//   this work for additional information regarding copyright ownership.
+//   The ASF licenses this file to You under the Apache License, Version 2.0
+//   (the "License"); you may not use this file except in compliance with
+//   the License.  You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+
+function Annotation(type, id, begin, end) {
+  this.type = type;
+  this.id = id;
+  this.begin = begin;
+  this.end = end;
+};
+
+Annotation.prototype.length = function() {
+  return this.end - this.begin;
+};
+
+function AnnotationEditor(parentElement, tokens, annotations) {
+  this.parentElement = parentElement;
+  this.annotations = new Array();
+  this.tokens = tokens;
+  
+  // Render tokens
+  for (var i = 0, token; token = this.tokens[i++];) {
+    this.parentElement.append("<span class=token id=token" + 
+        (i - 1) + ">" + token + "</span>");
+  }
+  
+  // Insert annotation after annotation 
+  for (var i = 0, annotation; annotation = annotations[i++];) {
+    this.addAnnotation(annotation);
+  }
+};
+
+// Annotation Model:
+// - All annotation indexes are token indexes
+// - Annotations can contain other annotations.
+// - Annotations which cross each other or intersect with each other are not allowed
+//   for example A <START_1> B <START_2> C <END_1> D E <END_2>.
+
+AnnotationEditor.prototype.addAnnotation = function(annotation) {
+  
+  // TODO: Do crossing annotation detection and fail if they do! (return false or fail harder!)
+  
+  // Note:
+  // If an annotation span with the same bounds already exist the new annotation
+  // span is placed inside the existing one
+  $(".token").slice(annotation.begin, annotation.end).wrapAll("<span class=" + annotation.type +
+      " id=" + annotation.type + annotation.id + ">");
+  
+  this.annotations.push(annotation);
+};
+
+AnnotationEditor.prototype.removeAnnotation = function(annotationId) {
+  $("#" + annotationId).unwrap();
+};
+
+
+// Selection handling and navigation depends highly
+// on the annotation task. There is no default way of
+// doing it which fits all tasks.
+// Therefore we should implement a few default tools which
+// can be registered if required.
+
+// Registers a previous and forward key shortcuts to navigate based on span types.
+// Multiple span types can be passed in and optionally a function to choose a
+// span to select in case it is ambiguous.
+AnnotationEditor.prototype.setNavigationBySpanTypeKeys = function(spanType, previousKey, nextKey) {
+};
+
+// Registers a previous and forward key shortcuts to navigate with the help of a span locator function.
+AnnotationEditor.prototype.setNavigationByFunctionKeys = function(previousKey, nextKey, spanLocator){
+};
+
+
+// If a user clicks with a mouse on something he expects a reaction
+// It should be possible to register a function which helps dealing with
+// such a selection in a default way
+
+// e.g. user wants to select a few tokens
+// e.g. user wants to select a named entity annotation
+// He likely wants to do both in the same AnnotationEditor instance.
+// Span type priority could help with this (also for navigation)
+
diff --git a/tagging-server/src/main/resources/htmls/index.html b/tagging-server/src/main/resources/htmls/index.html
new file mode 100644
index 0000000..e239ed3
--- /dev/null
+++ b/tagging-server/src/main/resources/htmls/index.html
@@ -0,0 +1,65 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one
+   or more contributor license agreements.  See the NOTICE file
+   distributed with this work for additional information
+   regarding copyright ownership.  The ASF licenses this file
+   to you under the Apache License, Version 2.0 (the
+   "License"); you may not use this file except in compliance
+   with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing,
+   software distributed under the License is distributed on an
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+   KIND, either express or implied.  See the License for the
+   specific language governing permissions and limitations
+   under the License.    
+-->
+
+<html>
+<head>
+<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.js"></script>
+<script type="text/javascript" src="annotation-editor.js"></script>
+<script type="text/javascript" src="opennlp-demo.js"></script>
+<style>
+  .token {PADDING-LEFT: 3px; PADDING-RIGHT: 3px;}
+  .person {color:brown;}
+  .location {color: green;}
+  
+  #opennlp-demo {
+  	min-height: 12.1em;
+  }
+  
+  #opennlp-demo-language {
+  	position: relative;
+  	top: 0;
+  }
+  
+  #opennlp-demo-input {
+  	width: 49.999%;
+  	height: 100px;
+  	float: left;
+  	position: relative;
+  	resize: none;
+  }
+  
+  #opennlp-demo-result {
+  	width: 49.999%;
+  	height: 100px;
+	left: 50%;
+	position: relative;
+  	background: whiteSmoke;
+  }
+</style>
+  
+<script type="text/javascript">                                         
+	$(document).ready(function() {
+		$("div#opennlp-demo").opennlpDemo('namefinder');
+	});
+</script>
+</head>
+<body>
+	<div id="opennlp-demo"></div>
+</body>
+</html>
diff --git a/tagging-server/src/main/resources/htmls/opennlp-demo.js b/tagging-server/src/main/resources/htmls/opennlp-demo.js
new file mode 100644
index 0000000..545b9a6
--- /dev/null
+++ b/tagging-server/src/main/resources/htmls/opennlp-demo.js
@@ -0,0 +1,108 @@
+//   Licensed to the Apache Software Foundation (ASF) under one or more
+//   contributor license agreements.  See the NOTICE file distributed with
+//   this work for additional information regarding copyright ownership.
+//   The ASF licenses this file to You under the Apache License, Version 2.0
+//   (the "License"); you may not use this file except in compliance with
+//   the License.  You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+(function( $ ){
+	
+	function insertDemoElements( element ) {
+		element.append('<select id="opennlp-demo-language"></select>');
+		element.append('<div id="input-output">');
+    	element.append('<textarea id="opennlp-demo-input"></textarea>');
+    	element.append('<div id="opennlp-demo-result"></div>');
+		element.append('</div>');    	
+    	element.append('<button id="opennlp-demo-process">Process</button>');
+	};
+	
+	function detectLanguage( componentName ) {
+		
+		// TODO:
+		// Query name finder tagging service for supported languages
+		// Try to auto detect language in the background (every time input changed)
+		
+		// For now lets hard code English
+		$('select#opennlp-demo-language').append('<option value="en">English</option>');
+	};
+	
+  var methods = {
+    
+    namefinder : function( options ) { 
+    	insertDemoElements(this);
+    	
+    	// Can we get the method name here? 
+    	detectLanguage('namefinder')
+    	
+    	$('button#opennlp-demo-process').click(function() {
+    		
+    		//$.ajax({url:"/rest/namefinder/_findRawText",type:"GET",data: "Test text",dataType:"json",contentType:"application/json"})
+    		
+    		var inputText = $('textarea#opennlp-demo-input').val();
+    		
+    		// Call the name finder service to detect names
+			$.ajax({
+				  type: 'POST',
+				  url: "http://localhost:8080/rest/namefinder/_findRawText",
+				  data: inputText,
+				  dataType: "json",
+				  contentType: "application/json; charset=UTF-8",
+				  success: function (data) {
+					
+				    $("div#opennlp-demo-result").empty();
+					
+				    // Extract tokens and names from the array array
+					var tokens = [];
+					var annotations = [];
+
+					for (si = 0; si < data.document.length; si++) {
+						for (ni = 0; ni < data.names[si].length; ni++) {
+							var ann = data.names[si][ni];
+							
+							// alert(data.names[si][ni]);
+							
+							annotations.push(new Annotation("person", 0, tokens.length + ann.start, 
+									tokens.length + ann.end));
+						}
+						
+						for (ti = 0; ti < data.document[si].length; ti++) {
+							// TODO: its end and begin index, need to do substring on input text!
+							
+							tokens.push(inputText.substring(data.document[si][ti].start, data.document[si][ti].end));
+						}
+					}
+				    
+				    // Display results in annotation editor!
+    				new AnnotationEditor($("div#opennlp-demo-result"),
+							tokens, annotations);
+    			  },
+    			  error: function (jqXHR, textStatus, errorThrown) {
+    			  	alert("Failed to call name finder service for some reason!");
+    			  }
+				});
+    	});
+    }
+  };
+
+  $.fn.opennlpDemo = function( method ) {
+    
+    // Method calling logic
+    if ( methods[method] ) {
+      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
+    } else if ( typeof method === 'object' || ! method ) {
+      return methods.init.apply( this, arguments );
+    } else {
+      $.error( 'Method ' +  method + ' does not exist on jQuery.opennlpDemo' );
+    }    
+  
+  };
+
+})( jQuery );