text: /*******************************************************************************
   * @license
   * Copyright (c) 2012 IBM Corporation and others.
   * All rights reserved. This program and the accompanying materials are made
   * available under the terms of the Eclipse Public License v1.0
   * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
   * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
   *
   * Contributors:
   *     Kris De Volder (VMWare) - initial API and implementation
   *******************************************************************************/
  
  /*global define Range*/
  /*jslint browser:true*/
  
  define(['i18n!orion/widgets/nls/messages', 'gcli/index', 'gcli/types', 'gcli/types/basic', 'gcli/ui/field', 'gcli/argument', 'gcli/util', 'gcli/ui/menu'],
  	function(messages, mGCLI, mTypes, mBasicTypes, mField, mArgument, mUtil, mMenu) {
  
  	function CustomType(typeSpec) {}
  	CustomType.prototype = Object.create(mBasicTypes.DeferredType.prototype);
  
  	var orion = {};
  	orion.console = {};
  	orion.console.CompletionStatus = {
  		MATCH: 0,
  		PARTIAL: 1,
  		ERROR: 2
  	};
  
  	/**
  	 * Constructs a new console.
  	 * 
  	 * @param parent the parent element for the console, it can be either a DOM element or an ID for a DOM element.
  	 * 
  	 * @class A Console is a user interface that accepts input command lines and displays output.
  	 * @name orion.console.Console
  	 */
  	orion.console.Console = (function() {
  		function Console(input, output) {
  			this._init(input, output);
  		}
  		Console.prototype = /** @lends orion.console.Console.prototype */{			
  			/** @private */
  			_init: function(input, output) {
  				if (!input) { throw messages["no input"]; }
  				if (!output) { throw messages["no output"]; }
  
  				if (!Range.prototype.createContextualFragment) {
  					var label = document.createElement("label"); //$NON-NLS-0$
  					label.innerText = messages["Sorry, the Console is not supported on your browser."];
  					output.appendChild(label);
  					return;
  				}
  
  				var outputDiv = document.createElement("div"); //$NON-NLS-0$
  				outputDiv.id = "gcli-display"; //$NON-NLS-0$
  				outputDiv.style.height = "100%"; //$NON-NLS-0$
  				outputDiv.style.width = "100%"; //$NON-NLS-0$
  				output.appendChild(outputDiv);
  
  				var inputDiv = document.createElement("div"); //$NON-NLS-0$
  				inputDiv.id = "gcli-input-area"; //$NON-NLS-0$
  				inputDiv.style.height = "100%"; //$NON-NLS-0$
  				inputDiv.style.width = "100%"; //$NON-NLS-0$
  				input.appendChild(inputDiv);
  
  				var inputText = document.createElement("input"); //$NON-NLS-0$
  				inputText.id = "gcli-input"; //$NON-NLS-0$
  				inputText.className = "inputText"; //$NON-NLS-0$
  				inputText.style.paddingLeft = "1em"; //$NON-NLS-0$
  				inputText.style.width = "100%"; //$NON-NLS-0$
  				inputDiv.appendChild(inputText);
  
  				var rowCompleteDiv = document.createElement("div"); //$NON-NLS-0$
  				rowCompleteDiv.id = "gcli-row-complete"; //$NON-NLS-0$
  				rowCompleteDiv.style.position = "absolute"; //$NON-NLS-0$
  				rowCompleteDiv.style.top = "2px"; //$NON-NLS-0$
  				rowCompleteDiv.style.zIndex = "-1000"; //$NON-NLS-0$
  				inputDiv.appendChild(rowCompleteDiv);
  
  				mGCLI.createView();
  
  				function CustomField(type, options) {
  					mField.Field.call(this, type, options);
  					this.onInputChange = this.onInputChange.bind(this);
  					this.arg = new mArgument.Argument();
  					this.element = mUtil.dom.createElement(this.document, 'div'); //$NON-NLS-0$
  					this.element.className = "orion";
  					this.menu = new mMenu.Menu({ document: this.document, field: true });
  					this.element.appendChild(this.menu.element);
  					this.fieldChanged = mUtil.createEvent('DirectoryField.fieldChanged'); //$NON-NLS-0$
  					this.menu.onItemClick = this.onItemClick.bind(this);
  				}
  
  				CustomField.prototype = Object.create(mField.Field.prototype);
  				CustomField.prototype.destroy = function() {
  					mField.Field.prototype.destroy.call(this);
  					this.menu.destroy();
  					delete this.element;
  					delete this.menu;
  					delete this.document;
  					delete this.onInputChange;
  				};
  				CustomField.prototype.setConversion = function(conversion) {
  					this.arg = conversion.arg;
  					this.setMessage(conversion.message);
  					var items = [];
  					var predictions = conversion.getPredictions();
  					predictions.forEach(function(item) {
  						if (!item.hidden) {
  							items.push({
  								name: item.name,
  								complete: item.name,
  								description: item.description || ''
  							});
  						}
  					}, this);
  					this.menu.show(items);
  
  					if (conversion.then) {
  						/*
  						 * We only got a 'provisional' conversion. When caches are filled
  						 * we'll get a callback and should try again.
  						 */
  						var that = this;
  						conversion.then(function () {
  							if (that.element) { //if there's no UI yet => ignore.
  								that.setConversion(that.getConversion());
  							}
  						});
  					}
  				};
  				CustomField.prototype.onItemClick = function(ev) {
  					var itemText = ev.currentTarget.querySelector(".gcli-menu-name").innerHTML; //$NON-NLS-0$
  					this.arg = this.arg.beget(itemText);
  					var conversion = this.type.parse(this.arg);
  					this.fieldChanged({ conversion: conversion });
  					this.setMessage(conversion.message);
  				};
  				CustomField.claim = function(type) {
  					return type instanceof CustomType ? mField.Field.MATCH + 1 : mField.Field.NO_MATCH;
  				};
  
  				mField.addField(CustomField);
  			},
  			addCommand: function(command) {
  				if (!command.exec) {
  					command.exec = command.callback;
  				}
  				if (!command.params) {
  					command.params = command.parameters;
  				}
  				mGCLI.addCommand(command);
  			},
  			addField: function(field) {
  				// TODO
  			},
  			addType: function(type) {
  				function NewType(typeSpec) {}
  
  				NewType.prototype = Object.create(CustomType.prototype);
  				NewType.prototype.name = type.name;
  				NewType.prototype.parse = function (arg) {
  					var completion = type.parse(arg.toString().trim());
  					var status = mTypes.Status.VALID;
  					if (completion.status) {
  						switch (completion.status) {
  							case orion.console.CompletionStatus.ERROR:
  								status = mTypes.Status.ERROR;
  								break;
  							case orion.console.CompletionStatus.PARTIAL:
  								status = mTypes.Status.INCOMPLETE;
  								break;
  						}
  					}							
  					return new mTypes.Conversion(completion.value, arg, status, completion.message, completion.predictions);
  				};
  				if (type.stringify) {
  					NewType.prototype.stringify = function (arg) {
  						return type.stringify(arg);
  					};
  				}
  				if (type.increment) {
  					NewType.prototype.increment = function (arg) {
  						return type.increment(arg);
  					};
  				}
  				if (type.decrement) {
  					NewType.prototype.decrement = function (arg) {
  						return type.decrement(arg);
  					};
  				}
  				mTypes.registerType(NewType);
  			}
  		};
  		return Console;
  	}());
  
  	return orion.console;
  });
  