std::vector<Pnt3f> OctreeAStarAlgorithm::search(OctreePtr Tree,
                                                const Pnt3f& Start,
                                                const Pnt3f& Goal,
                                                PathCostHeuristicFunc CostHeuristicFunc)
{
    _Tree = Tree; 
    _StartNode = _Tree->getNodeThatContains(Start);
    _GoalNode = _Tree->getNodeThatContains(Goal);
    _CostHeuristicFunc = CostHeuristicFunc;

    if(!_StartNode ||
       !_GoalNode)
    {
        return _SolutionPath;
    }

    //clear lists
    _SolutionPath.clear();
    _OpenNodes.clear();
    _ClosedNodes.clear();

    //initialize start node
    ASNodePtr startNode = ASNodePtr(new ASNode);
    startNode->_OctreeNode = _StartNode;
    startNode->_CostFromStart = 0;
    Pnt3f Center;
    _StartNode->getVolume().getCenter(Center);
    startNode->_CostToGoal = _CostHeuristicFunc(_Tree, _StartNode, Center);
    startNode->_Parent.reset();
    _OpenNodes.push_back(startNode);

    while(!_OpenNodes.empty())
    {
        ASNodePtr Node = _OpenNodes.front();
        _OpenNodes.erase(_OpenNodes.begin());

        if(Node->_OctreeNode == _GoalNode)
        {
            constructPath(Node);
            return _SolutionPath;//success
        }
        else
        {
            for(Int8 i = 0; i < Node->_OctreeNode->getNeighbors().size(); ++i)
            {
                if(!Node->_OctreeNode->getNeighbor(i)->getContainsObstacles())
                {//Node->_OctreeNode->getNeighbor(i)->children.size() == 0
                    Node->_OctreeNode->getNeighbor(i)->getVolume().getCenter(Center);
                    Real32 NewCost = Node->_CostFromStart + _CostHeuristicFunc(_Tree, _StartNode, Center);
                    Int32 locInOpen = inOpen(Node->_OctreeNode->getNeighbor(i));
                    Int32 locInClosed = inClosed(Node->_OctreeNode->getNeighbor(i));
                    if((locInOpen >= 0 && _OpenNodes[locInOpen]->_CostFromStart <= NewCost) || (locInClosed >= 0 && _ClosedNodes[locInClosed]->_CostFromStart <= NewCost))
                    {
                        continue;
                    }
                    else
                    {
                        //initialize a new node
                        ASNodePtr NewNode = ASNodePtr(new ASNode());
                        NewNode->_OctreeNode = Node->_OctreeNode->getNeighbor(i);
                        NewNode->_OctreeNode->getVolume().getCenter(Center);
                        NewNode->_CostFromStart = _CostHeuristicFunc(_Tree, _StartNode, Center);
                        NewNode->_CostToGoal = _CostHeuristicFunc(_Tree, _GoalNode, Center);
                        NewNode->_Parent = Node;

                        if(locInClosed >= 0)
                        {
                            _ClosedNodes.erase(_ClosedNodes.begin() + locInClosed);
                        }
                        /*if(locInOpen >= 0)
                         * {
                            _OpenNodes.erase(_OpenNodes.begin() + locInOpen);
                        }else{
                            pushOnOpen(NewNode);
                        }*/
                        if(locInOpen >= 0)
                        {
                            _OpenNodes.erase(_OpenNodes.begin() + locInOpen);
                        }
                        pushOnOpen(NewNode);

                    }//endif
                }//endif...
            }//end for loop...dont with Node
        }//endif

        _ClosedNodes.push_back(Node);
    }//end while loop

    return _SolutionPath;
}
void AStar::createPath(Vec3f startPos, Vec3f endPos, levelGraph *level)
{
	//no need to process this situation
	if(startPos == endPos)
	{
		return;
	}

	/*startPos[0] = (startPos[0] - level->levelMask->startingOffset[0]) / level->levelMask->scaleX;
	startPos[1]	= 0.0f;
	startPos[2]	= (startPos[2] - level->levelMask->startingOffset[2]) / level->levelMask->scaleZ; 

	endPos[0] = (endPos[0] - level->levelMask->startingOffset[0]) / level->levelMask->scaleX;
	endPos[1] = 0.0f;
	endPos[2] = (endPos[2] - level->levelMask->startingOffset[2]) / level->levelMask->scaleZ; 
*/
	start = findNodeInGraph(startPos, level);
	goal = findNodeInGraph(endPos, level);

	//if goal is in collision zone, return so game does not freeze
	if(goal->neighbor[0] == NULL &&
		goal->neighbor[1] == NULL &&
		goal->neighbor[2] == NULL &&
		goal->neighbor[3] == NULL)
	{
		//cout << "ERROR, goal is in collision zone" << endl;
		return;
	}

	open.push_back(start);

	//while lowest ranked node's postion in the open list is not equal to the goal's position
	//if it is equal we are done finding our path
	while(open.front()->pos != goal->pos)
	{
		current = open.front();

		//cout<< current->pos << endl; //##############################################################################################################

		removeFromOpen(open.front());
		//open.clear();

		//put node in closed so we dont reprocess a node that we already processed
		closed.push_back(current);

		//process current's neighbors to look for the right path
		for(int i = 0; i < 4; i++)
		{
			if(current->neighbor[i] != NULL)
			{
				//float cost = g(current) + movementCost(current->neighbor[i]);
				
				////if neighbor in open and cost less than g(neighbor)
				//if(inOpen(current->neighbor[i]) && cost < g(current->neighbor[i]))
				////if(inOpen(current->neighbor[i]) && h(current) < h(current->neighbor[i]))
				//{
				//	//remove neighbor from open, because new path is better
				//	removeFromOpen(current->neighbor[i]);

				//	cout << "GGGGG" << endl;
				//}

				////if neighbor in closed and cost less than g(neighbor)
				//else if(inClosed(current->neighbor[i]) && cost < g(current->neighbor[i]))
				////else if(inClosed(current->neighbor[i]) && h(current) < h(current->neighbor[i]))
				//{
				//	removeFromClosed(current->neighbor[i]);

				//	cout << "AAAA" << endl;
				//}

				//if neighbor not in closed and neighbor not in open
				if((!inOpen(current->neighbor[i])) && (!inClosed(current->neighbor[i])))
				{
					open.push_back(current->neighbor[i]);
					current->neighbor[i]->rank = g(current->neighbor[i]) + h(current->neighbor[i]);
					current->neighbor[i]->parent = current;
				}
			}	
		}

//*******************SORT*********************************************//
		//bubble sort
		
		int check = open.size();

		//ERROR check
		if(check > 1)
		{
			//sort open list from lowest rank to highest
			for(unsigned int counter = 0; counter < check; counter++)
			{
				list<node*>::iterator k = open.end();
				k--;

				list<node*>::iterator m = open.end();
				m--;
				m--;
		
				unsigned int countEnd = check - 1;
				while(countEnd > counter)
				{
					if((*k)->rank < ((*m)->rank))
					{
						node *temp;
						temp = new node();

						temp = (*k);

						(*k) = (*m);
						(*m) = temp;

						temp = NULL;
						delete temp;

					}
					if(countEnd-1 != counter)
					{
						k--;
						m--;
					}
					countEnd--;
				}

			}

			//optimizes pathfinding by shinking open list to fewer nodes to sort
			if(open.size() > 20)
			{
				unsigned int openSize = check / 2; 
				list<node*>::iterator k = open.end();
				k--;

				//remove some of the highest ranked nodes to make open list process faster
				for(unsigned int counter = 0; counter < openSize; counter++)
				{
					//put node in closed so we dont reprocess a node that we already processed
					closed.push_back((*k));

					removeFromOpen((*k));

					k = open.end();
					k--;
				}
			}
		}
		else
		{
			//cout << "ERROR, open list in AStarPathFinding.h contains zero elements, NPC start point is in collision zone. " << endl;
			
			//clear the open and closed lists so they are ready for the next iteration
			open.clear();
			closed.clear();

			if(!firstTime)
			{
				//clear the path list from the previous determined path
				path.clear();
			}

			return;
		}
//*************************************************************************************************/

	}

	//reconstruct path from goal to start by following parent pointers
	getPath( startPos,  endPos, level->levelMask);

	//clear the open and closed lists so they are ready for the next iteration
	open.clear();
	closed.clear();
}