/**
 *	This method processes key down events
 */
LineEditor::ProcessState LineEditor::processKeyEvent(
	KeyEvent event, std::string& resultString )
{
	#define EMPTY_STR(str) \
		(str.empty() || str.find_first_not_of(32) == std::string::npos)

	const KeyEvent::Key eventKey = event.key();

	bool isResultSet = false;
	bool isHandled = false;

	if (event.isKeyDown())
	{
		char keyChar = event.character();

		isHandled = this->processAdvanceEditKeys( event );
		if (!isHandled)
		{
			isHandled = true;
			switch (eventKey)
			{
			case KeyEvent::KEY_RETURN:
			case KeyEvent::KEY_JOY8:	// 'A' key
				if (!event.isAltDown())
				{
					resultString = editString_;
					isResultSet = true;
					editString_ = "";
					cx_ = 0;
					lastChar_ = 0;
				}
				else
				{
					isHandled = false;
				}
				break;

			case KeyEvent::KEY_DELETE:
				if ( cx_ < (int)editString_.length( ) )
					deleteChar( cx_ );
				break;

			case KeyEvent::KEY_BACKSPACE:
			case KeyEvent::KEY_JOY14:	// left trigger
				if ( cx_ )
				{
					cx_--;
					deleteChar( cx_ );
				}
				break;

			case KeyEvent::KEY_INSERT:
				inOverwriteMode_ = !inOverwriteMode_;
				break;

			case KeyEvent::KEY_LEFTARROW:
			case KeyEvent::KEY_JOY2:	// dpad left
				if ( cx_ > 0 )
					cx_--;
				break;

			case KeyEvent::KEY_RIGHTARROW:
			case KeyEvent::KEY_JOY3:	// dpad right
				if ( cx_ < (int)editString_.length() )
					cx_++;
				break;

			case KeyEvent::KEY_UPARROW:
			case KeyEvent::KEY_JOY0:	// dpad up
				if (history_.size() > 0) 
				{
					if (historyShown_ == -1)
					{
						history_.insert( history_.begin(), editString_ );
						historyShown_ = 1;
					}
					else 
					{
						if (!EMPTY_STR(editString_))
						{
							history_[historyShown_] = editString_;
						}
						++historyShown_;
					}
					showHistory();
				}
				break;

			case KeyEvent::KEY_DOWNARROW:
			case KeyEvent::KEY_JOY1:	// dpad down
				if (history_.size() > 0) 
				{
					if (historyShown_ == -1)
					{
						history_.insert( history_.begin(), editString_ );
						historyShown_ = history_.size() - 1;
					}
					else 
					{
						if (!EMPTY_STR(editString_))
						{
							history_[historyShown_] = editString_;
						}
						--historyShown_;
					}
					showHistory();
				}
				break;

			case KeyEvent::KEY_HOME:
				cx_ = 0;
				break;

			case KeyEvent::KEY_END:
				cx_ = editString_.length();
				break;

			// joystick space
			case KeyEvent::KEY_JOY15:
				keyChar = ' ';
				isHandled = false;
				break;

			default:
				isHandled = false;
				break;
			}
		}

		if (!isHandled && keyChar != 0)
		{
			isHandled = true;

			cx_ += this->insertChar( cx_, keyChar );

			lastChar_ = 0;
		}
		else if (event.isCtrlDown())
		{
			if (event.isKeyDown() && eventKey == KeyEvent::KEY_U)
			{
				int assignmentLocation = editString_.find_last_of( "=" );

				if (assignmentLocation > 0)
				{
					editString_ = editString_.substr( 0, assignmentLocation + 1 );
					cx_ = min( cx_, (int)editString_.length() );

					isHandled = true;
				}
			}
		}

		// if key is relevant (i.e. was handled) and 
		// it isn't the RETURN key, insert it into 
		// list of currently pressed-down keys
		if (isHandled && !isResultSet && this->keyRepeat_.first.key() != eventKey )
		{
			this->keyRepeat_.first  = event;
			this->keyRepeat_.second = this->time_ + KEY_REPEAT_START_SEC;
		}
		if( this->keyRepeat_.first.modifiers() != event.modifiers() )
		{
			this->keyRepeat_.first = KeyEvent( keyRepeat_.first.type(), 
				keyRepeat_.first.key(), event.modifiers() );
		}
	}
	else
	{
		// this is a key-up event. 
		// Stop key from repeating
		if (eventKey == this->keyRepeat_.first.key() ||
			event.isCtrlDown() || event.isAltDown() )
		{
			this->keyRepeat_.first = KeyEvent();
			this->keyRepeat_.second = FLT_MAX;
			this->time_ = 0;
		}
		else if( this->keyRepeat_.first.modifiers() != event.modifiers() )
		{
			this->keyRepeat_.first = KeyEvent( keyRepeat_.first.type(), 
				keyRepeat_.first.key(), event.modifiers() );
		}
	}

	// these are key up and key downs
	if (!isHandled) switch (eventKey)
	{
		// any joystick button or quantized direction 
		// change and we go and update our joystick state
		case KeyEvent::KEY_JOYALPUSH:
		case KeyEvent::KEY_JOYARPUSH:
		case KeyEvent::KEY_JOYALUP:
		case KeyEvent::KEY_JOYALDOWN:
		case KeyEvent::KEY_JOYALLEFT:
		case KeyEvent::KEY_JOYALRIGHT:
		case KeyEvent::KEY_JOYARUP:
		case KeyEvent::KEY_JOYARDOWN:
		case KeyEvent::KEY_JOYARLEFT:
		case KeyEvent::KEY_JOYARRIGHT:
			this->processJoystickStates(
				InputDevices::joystick().stickDirection( 1 ),
				InputDevices::joystick().stickDirection( 0 ),
				InputDevices::isKeyDown( KeyEvent::KEY_JOYARPUSH ),
				InputDevices::isKeyDown( KeyEvent::KEY_JOYALPUSH ) );
			isHandled = true;
			break;
	}

	// end of line, request processing
	if (isResultSet)
	{
		if (!EMPTY_STR(resultString))
		{
			if (history_.size() > 0 && historyShown_ != -1)
			{
				history_[ 0 ] = resultString;
			}
			else
			{
				history_.insert( history_.begin(), resultString );
			}
		}
		else
		{
			if (history_.size() > 0 && EMPTY_STR(history_[ 0 ]))
			{
				history_.erase(history_.begin());
			}
		}
		// clamp history 
		if (history_.size() > MAX_HISTORY_ENTRIES)
		{
			history_.erase( history_.end()-1 );
		}
		historyShown_ = -1;
		return RESULT_SET;
	}

	if (isHandled)
	{
		return PROCESSED;
	}

	return NOT_HANDLED;
}