namespace Community.CsharpSqlite
{
	public partial class Sqlite3
	{
		/*
		** 2008 August 16
		**
		** The author disclaims copyright to this source code.  In place of
		** a legal notice, here is a blessing:
		**
		**    May you do good and not evil.
		**    May you find forgiveness for yourself and forgive others.
		**    May you share freely, never taking more than you give.
		**
		*************************************************************************
		** This file contains routines used for walking the parser tree for
		** an SQL statement.
		*************************************************************************
		**  Included in SQLite3 port to C#-SQLite;  2008 Noah B Hart
		**  C#-SQLite is an independent reimplementation of the SQLite software library
		**
		**  SQLITE_SOURCE_ID: 2010-08-23 18:52:01 42537b60566f288167f1b5864a5435986838e3a3
		**
		*************************************************************************
		*/
		//#include "sqliteInt.h"
		//#include <stdlib.h>
		//#include <string.h>

		/*
		** Walk an expression tree.  Invoke the callback once for each node
		** of the expression, while decending.  (In other words, the callback
		** is invoked before visiting children.)
		**
		** The return value from the callback should be one of the WRC_*
		** constants to specify how to proceed with the walk.
		**
		**    WRC_Continue      Continue descending down the tree.
		**
		**    WRC_Prune         Do not descend into child nodes.  But allow
		**                      the walk to continue with sibling nodes.
		**
		**    WRC_Abort         Do no more callbacks.  Unwind the stack and
		**                      return the top-level walk call.
		**
		** The return value from this routine is WRC_Abort to abandon the tree walk
		** and WRC_Continue to continue.
		*/

		private static int sqlite3WalkExpr(Walker pWalker, ref Expr pExpr)
		{
			int rc;
			if (pExpr == null)
				return WRC_Continue;
			testcase(ExprHasProperty(pExpr, EP_TokenOnly));
			testcase(ExprHasProperty(pExpr, EP_Reduced));
			rc = pWalker.xExprCallback(pWalker, ref pExpr);
			if (rc == WRC_Continue
			&& !ExprHasAnyProperty(pExpr, EP_TokenOnly))
			{
				if (sqlite3WalkExpr(pWalker, ref pExpr.pLeft) != 0)
					return WRC_Abort;
				if (sqlite3WalkExpr(pWalker, ref pExpr.pRight) != 0)
					return WRC_Abort;
				if (ExprHasProperty(pExpr, EP_xIsSelect))
				{
					if (sqlite3WalkSelect(pWalker, pExpr.x.pSelect) != 0)
						return WRC_Abort;
				}
				else
				{
					if (sqlite3WalkExprList(pWalker, pExpr.x.pList) != 0)
						return WRC_Abort;
				}
			}
			return rc & WRC_Abort;
		}

		/*
		** Call sqlite3WalkExpr() for every expression in list p or until
		** an abort request is seen.
		*/

		private static int sqlite3WalkExprList(Walker pWalker, ExprList p)
		{
			int i;
			ExprList_item pItem;
			if (p != null)
			{
				for (i = p.nExpr; i > 0; i--)
				{//, pItem++){
					pItem = p.a[p.nExpr - i];
					if (sqlite3WalkExpr(pWalker, ref pItem.pExpr) != 0)
						return WRC_Abort;
				}
			}
			return WRC_Continue;
		}

		/*
		** Walk all expressions associated with SELECT statement p.  Do
		** not invoke the SELECT callback on p, but do (of course) invoke
		** any expr callbacks and SELECT callbacks that come from subqueries.
		** Return WRC_Abort or WRC_Continue.
		*/

		private static int sqlite3WalkSelectExpr(Walker pWalker, Select p)
		{
			if (sqlite3WalkExprList(pWalker, p.pEList) != 0)
				return WRC_Abort;
			if (sqlite3WalkExpr(pWalker, ref p.pWhere) != 0)
				return WRC_Abort;
			if (sqlite3WalkExprList(pWalker, p.pGroupBy) != 0)
				return WRC_Abort;
			if (sqlite3WalkExpr(pWalker, ref p.pHaving) != 0)
				return WRC_Abort;
			if (sqlite3WalkExprList(pWalker, p.pOrderBy) != 0)
				return WRC_Abort;
			if (sqlite3WalkExpr(pWalker, ref p.pLimit) != 0)
				return WRC_Abort;
			if (sqlite3WalkExpr(pWalker, ref p.pOffset) != 0)
				return WRC_Abort;
			return WRC_Continue;
		}

		/*
		** Walk the parse trees associated with all subqueries in the
		** FROM clause of SELECT statement p.  Do not invoke the select
		** callback on p, but do invoke it on each FROM clause subquery
		** and on any subqueries further down in the tree.  Return
		** WRC_Abort or WRC_Continue;
		*/

		private static int sqlite3WalkSelectFrom(Walker pWalker, Select p)
		{
			SrcList pSrc;
			int i;
			SrcList_item pItem;

			pSrc = p.pSrc;
			if (ALWAYS(pSrc))
			{
				for (i = pSrc.nSrc; i > 0; i--)// pItem++ )
				{
					pItem = pSrc.a[pSrc.nSrc - i];
					if (sqlite3WalkSelect(pWalker, pItem.pSelect) != 0)
					{
						return WRC_Abort;
					}
				}
			}
			return WRC_Continue;
		}

		/*
		** Call sqlite3WalkExpr() for every expression in Select statement p.
		** Invoke sqlite3WalkSelect() for subqueries in the FROM clause and
		** on the compound select chain, p.pPrior.
		**
		** Return WRC_Continue under normal conditions.  Return WRC_Abort if
		** there is an abort request.
		**
		** If the Walker does not have an xSelectCallback() then this routine
		** is a no-op returning WRC_Continue.
		*/

		private static int sqlite3WalkSelect(Walker pWalker, Select p)
		{
			int rc;
			if (p == null || pWalker.xSelectCallback == null)
				return WRC_Continue;
			rc = WRC_Continue;
			while (p != null)
			{
				rc = pWalker.xSelectCallback(pWalker, p);
				if (rc != 0)
					break;
				if (sqlite3WalkSelectExpr(pWalker, p) != 0)
					return WRC_Abort;
				if (sqlite3WalkSelectFrom(pWalker, p) != 0)
					return WRC_Abort;
				p = p.pPrior;
			}
			return rc & WRC_Abort;
		}
	}
}