void FocusController::findHorizontallyFocusableNodeInRect(FocusDirection direction, Node* start, KeyboardEvent* event, const IntRect* rect, Node** candidateNode, IntRect& candidateNodeRect)
{
#if PLATFORM(WKC)
    CRASH_IF_STACK_OVERFLOW(WKC_STACK_MARGIN_DEFAULT);
#endif
//    ASSERT(direction == FocusDirectionLeft || direction == FocusDirectionRight);
    if (!start)
        return ;

    Node* node = start;
    HTMLFrameOwnerElement* owner;
    Document* document;
    IntRect nodeRect;

    while (node) {
        if (!isNodeInSpecificRect(node, rect)) {
            node = getClosestNode(node, direction);
            continue;
        }
        owner = 0;
        if (node->isFrameOwnerElement()) {
            owner = static_cast<HTMLFrameOwnerElement*>(node);
            if (!owner->contentFrame()) {
                *candidateNode = 0;
                return;
            }
            document = owner->contentFrame()->document();
            findHorizontallyFocusableNodeInRect(direction, document, event, rect, candidateNode, candidateNodeRect);
        } else if (isScrollableContainerNode(node) && !node->renderer()->isTextArea()) {
            findHorizontallyFocusableNodeInRect(direction, node->firstChild(), event, rect, candidateNode, candidateNodeRect);
        } else {
            if (node->isFocusable() && !node->isFrameOwnerElement()) {
                nodeRect = node->renderer()->absoluteBoundingBoxRect();
                FrameView* frameView = node->document()->view();
                if (!frameView) {
                    *candidateNode = 0;
                    return;
                }                
                nodeRect = frameView->contentsToWindow(nodeRect);
                nodeRect.intersect(*rect);
                if (!nodeRect.isEmpty()) {
                    if (candidateNodeRect.isEmpty()) {
                        *candidateNode = node;
                        candidateNodeRect = nodeRect;
                    }
                    if (direction == FocusDirectionRight && candidateNodeRect.x() > nodeRect.x()) {
                        *candidateNode = node;
                        candidateNodeRect = nodeRect;
                    } else if (direction == FocusDirectionLeft && candidateNodeRect.x() < nodeRect.x()) {
                        *candidateNode = node;
                        candidateNodeRect = nodeRect;
                    }
                }
            }
        }
        node = getClosestNode(node, direction);
    }
}
void CharacterUpdaterPlayer::goToUsingPath(const CCVector3 &target)
{
    const CCPathFinderNetwork::PathNode *targetNode = pathFinderNetwork->findClosestNode( player, &target, false );
    if( targetNode == NULL )
    {
        DELETE_POINTER( path );
        goTo( target );
        return;
    }

    if( path == NULL )
    {
        findNewAnchor = true;
        path = new CCPathFinderNetwork::Path();
    }
    getClosestNode();

    pathAnchorNode = anchorNode;
    if( pathAnchorNode != NULL )
    {
        pathFinderNetwork->findPath( *path, pathAnchorNode, targetNode );
    }

    if( path->endDirection == 0 )
    {
        // See if we can head straight to our target
        CCObjectCollideable *hitObject = CCMovementOctreeCollisionCheck( player, *player->positionPtr, target );
        if( hitObject == NULL )
        {
            DELETE_POINTER( path );
        }
    }

    // Check if we can head straight to our first path
    else
    {
        const int pathDirection = path->directions[0];
        if( pathAnchorNode != NULL && pathDirection < pathAnchorNode->numberOfConnections )
        {
            const CCPathFinderNetwork::PathNode::PathConnection *usingConnection = &pathAnchorNode->connections[pathDirection];
            const CCVector3 *pathTarget = &usingConnection->node->point;
            CCObjectCollideable *hitObject = CCMovementOctreeCollisionCheck( player, *player->positionPtr, *pathTarget );
            currentPath = hitObject == NULL ? 0 : -1;
        }
        else
        {
            currentPath = 0;
        }
    }

    goTo( target );
}
void CharacterUpdaterAI::setWaypointCycle(WaypointCycleType inCycleType)
{
	waypointCycle = inCycleType;
	
    if( enabled )
    {
        if( waypointCycle == cycle_random )
        {
            waypointCurrent = rand() % waypointTotal;
            goTo( waypoints[waypointCurrent] );
        }
        else if( waypointCycle == cycle_aiNodes )
        {
            getClosestNode();
            pickRandomNode();
        }
    }
}
Node* FocusController::findVerticallyFocusableNodeInRect(FocusDirection direction, Node* start, KeyboardEvent* event, const IntRect* rect)
{
#if PLATFORM(WKC)
    CRASH_IF_STACK_OVERFLOW(WKC_STACK_MARGIN_DEFAULT);
#endif
    ASSERT(direction == FocusDirectionUp || direction == FocusDirectionDown);
    if (!start)
        return 0;

    Node* node = start;
    HTMLFrameOwnerElement* owner;
    Document* document;

    while (node) {
        if (!isNodeInSpecificRect(node, rect)) {
            node = getClosestNode(node, direction);
            continue;
        }

        owner = 0;
        if (node->isFrameOwnerElement()) {
            owner = static_cast<HTMLFrameOwnerElement*>(node);
            if (!owner->contentFrame()) {
                node = 0;
                break;
            }
            document = owner->contentFrame()->document();
            if (direction == FocusDirectionUp) {
                node = findVerticallyFocusableNodeInRect(direction, document->lastChild(), event, rect);
            } else {
                node = findVerticallyFocusableNodeInRect(direction, document->firstChild(), event, rect);
            }
            if (node)
                break;
            node = getClosestNode(owner, direction);
            continue;
        } else if (isScrollableContainerNode(node) && !node->renderer()->isTextArea()) {
            Node* childNode = 0;
            if (direction == FocusDirectionUp) {
                childNode = findVerticallyFocusableNodeInRect(direction, node->lastChild(), event, rect);
            } else {
                ASSERT(direction == FocusDirectionDown);
                childNode = findVerticallyFocusableNodeInRect(direction, node->firstChild(), event, rect);
            }
            if (!childNode) {
                node = getClosestNode(node, direction, true);
                if (!node)
                    break;
            } else {
                node = childNode;
                break;
            }
        }

        if (node->isFocusable() && !node->isFrameOwnerElement()) {
            break;
        }
        if (owner) {
            node = owner;
        }
        node = getClosestNode(node, direction);
    }
    return node;
}
void CharacterUpdaterAI::movePlayer(const float delta)
{
	if( wait > 0.0f )
	{
		player->movementDirection.z = 0.0f;
		wait -= delta;
		
		if( wait <= 0.0f )
		{
			goTo( targetConnection->node->point );
		}
	}
	else if( moving )
	{	
		if( path != NULL )
		{
			super::movePlayer( delta );
		}
		else
		{
            const float distance = CCVector3DistanceCheck2D( player->getPosition(), positionTarget, false );
            if( distance > 5.0f )
            {
                movePlayerRotation( positionTarget, delta );
            }
            else
			{	
				if( waypointCycle == cycle_aiNodes && enabled && followingEnemy == false )
				{
                    if( pathAnchorNode == NULL || targetConnection == NULL )
                    {
                        getClosestNode();
                        pickRandomNode();
                    }
					else if( targetConnection->distance > 10.0f ||
                       distance < 0.1f )
					{
						pathAnchorNode = targetConnection->node;
						anchorNode = pathAnchorNode;
						
						if( nodesPerMovementCycle++ > 10 )
						{
							int shouldWait = rand() % 5;
							if( shouldWait == 0 )
							{
								wait = (float)( rand() % 15 ) + 5.0f;
							}
							else
							{
								movementMagnitude = ( ( rand() % 5 ) * 0.1f ) + 0.3f;
							}
							nodesPerMovementCycle = 0;
						}
						
						// Pick a path from that node
						int randomType = rand() % 5;
						if( randomType > 1 )
						{
							int closestConnection = 0;
							float closestAngle = MAXFLOAT;
							for( int i=0; i<pathAnchorNode->numberOfConnections; ++i )
							{
								const float angleDistance = CCDistanceBetweenAngles( player->rotation.y, pathAnchorNode->connections[i].angle );
								if( angleDistance < closestAngle )
								{
									closestConnection = i;
									closestAngle = angleDistance;
								}
							}
							
							if( pathAnchorNode->numberOfConnections > 0 )
							{
								targetConnection = &pathAnchorNode->connections[closestConnection];
								goTo( targetConnection->node->point );
							}
							else
							{
								
							}
						}
						else
						{
							pickRandomNode();
						}
					}
				}
				else
				{
                    if( landPlayerOnTarget( distance, delta ) )
                    {        
                        if( enabled && followingEnemy == false )
                        {
                            if( waypointCycle == cycle_off )
                            {
                                if( waypointTotal > 0 )
                                {
                                    waypointTotal--;
                                    if( waypointTotal > 0 )
                                    {
                                        for( int i=0; i<waypointTotal; ++i )
                                        {
                                            waypoints[i] = waypoints[i+1];
                                        }
                                        goToUsingPath( waypoints[0] );
                                    }	
                                }
                            }
                            else
                            {
                                nextWaypoint();
                            }
                        }
                    }
				}
			}
		}
	}
}