protected virtual MethodDefinitionExpression CreateCreateClientMethod()
        {
            var client = Expression.Variable(FickleType.Define("PKWebServiceClient"), "client");
            var self = FickleExpression.Variable(currentType, "self");
            var options = FickleExpression.Parameter(FickleType.Define("NSDictionary"), "options");
            var url = Expression.Parameter(typeof(string), "urlIn");
            var parameters = new Expression[] { url, options };
            var operationQueue = FickleExpression.Call(options, "objectForKey", "OperationQueue");

            var variables = new [] { client };

            var body = FickleExpression.Block
            (
                variables,
                Expression.Assign(client, FickleExpression.StaticCall("PKWebServiceClient", "PKWebServiceClient", "clientWithURL", new
                {
                    url = FickleExpression.New("NSURL", "initWithString", url),
                    options = options,
                    operationQueue
                })),
                Expression.Return(Expression.Label(), client)
            );

            return new MethodDefinitionExpression("createClientWithURL", parameters.ToReadOnlyCollection(), FickleType.Define("PKWebServiceClient"), body, false, null);
        }
        protected virtual Expression CreateTryParseMethod()
        {
            var value = Expression.Parameter(typeof(string), "value");
            var methodName = currentTypeDefinition.Type.Name.Capitalize() + "TryParse";
            var result = Expression.Parameter(currentTypeDefinition.Type.MakeByRefType(), "result");

            var parameters = new Expression[]
            {
                value,
                result
            };

            var defaultBody = Expression.Return(Expression.Label(), Expression.Constant(false)).ToStatement();
            var cases = new List<SwitchCase>();

            foreach (var enumValue in ((FickleType)currentTypeDefinition.Type).ServiceEnum.Values)
            {
                cases.Add(Expression.SwitchCase(Expression.Assign(result, Expression.Convert(Expression.Constant((int)enumValue.Value), currentTypeDefinition.Type)).ToStatement(), Expression.Constant(enumValue.Name)));
            }

            var switchStatement = Expression.Switch(value, defaultBody, cases.ToArray());

            var body = FickleExpression.Block(switchStatement, Expression.Return(Expression.Label(), Expression.Constant(true)));

            return new MethodDefinitionExpression(methodName, parameters.ToReadOnlyCollection(), AccessModifiers.Static | AccessModifiers.ClasseslessFunction, typeof(bool), body, false, "__unused", null);
        }
        protected virtual Expression CreateToStringMethod()
        {
            var value = Expression.Parameter(currentTypeDefinition.Type, "value");
            var methodName = currentTypeDefinition.Type.Name.Capitalize() + "ToString";

            var parameters = new Expression[]
            {
                value
            };

            var array = FickleExpression.Variable("NSMutableArray", "array");
            var temp = FickleExpression.Variable(currentTypeDefinition.Type, "temp");

            var expressions = new List<Expression>
            {
                Expression.Assign(array, Expression.New(array.Type))
            };

            foreach (var enumValue in ((FickleType)currentTypeDefinition.Type).ServiceEnum.Values)
            {
                var currentEnumValue = Expression.Constant((int)enumValue.Value);

                expressions.Add
                (
                    Expression.IfThen
                    (
                        Expression.Equal(Expression.And(currentEnumValue, Expression.Convert(value, typeof(int))), Expression.Convert(currentEnumValue, typeof(int))),
                        FickleExpression.StatementisedGroupedExpression
                        (
                            GroupedExpressionsExpressionStyle.Wide,
                            FickleExpression.Call(array, typeof(void), "addObject", Expression.Constant(enumValue.Name)),
                            Expression.Assign(temp, Expression.Convert(Expression.Or(Expression.Convert(temp, typeof(int)), currentEnumValue), currentTypeDefinition.Type))
                        ).ToBlock()
                    )
                );
            }

            expressions.Add(Expression.IfThen(Expression.NotEqual(value, temp), FickleExpression.Return(FickleExpression.Call(Expression.Convert(value, typeof(object)), typeof(string), "stringValue", null)).ToStatementBlock()));
            expressions.Add(FickleExpression.Return(FickleExpression.Call(array, "componentsJoinedByString", Expression.Constant(","))));

            var defaultBody = FickleExpression.StatementisedGroupedExpression
            (
                GroupedExpressionsExpressionStyle.Wide,
                expressions.ToArray()
            );

            var cases = new List<SwitchCase>();

            foreach (var enumValue in ((FickleType)currentTypeDefinition.Type).ServiceEnum.Values)
            {
                cases.Add(Expression.SwitchCase(Expression.Return(Expression.Label(), Expression.Constant(enumValue.Name)).ToStatement(), Expression.Constant((int)enumValue.Value, currentTypeDefinition.Type)));
            }

            var switchStatement = Expression.Switch(value, defaultBody, cases.ToArray());

            var body = FickleExpression.Block(new [] { array, temp }, switchStatement);

            return new MethodDefinitionExpression(methodName, parameters.ToReadOnlyCollection(), AccessModifiers.Static | AccessModifiers.ClasseslessFunction, typeof(string), body, false, "__unused", null);
        }
        protected virtual Expression CreateConstructor()
        {
            var valParam = Expression.Parameter(typeof(int), "value");

            var parameters = new Expression[]
            {
                valParam
            };

            var valueMember = Expression.Variable(enumValueField.PropertyType, "this." + enumValueField.PropertyName);

            var body = FickleExpression.Block(Expression.Assign(valueMember, valParam).ToStatement());

            return new MethodDefinitionExpression(currentTypeDefinition.Type.Name, parameters.ToReadOnlyCollection(), null, body, false, null);
        }
        private Expression CreateParameterisedConstructor()
        {
            var valParam = Expression.Parameter(webServiceClientType, "client");

            var parameters = new Expression[]
            {
                valParam
            };

            var client = Expression.Variable(webServiceClientType, "webServiceClient");

            var body = FickleExpression.Block(Expression.Assign(client, valParam).ToStatement());

            return new MethodDefinitionExpression(currentTypeDefinitionExpression.Type.Name, parameters.ToReadOnlyCollection(), AccessModifiers.Public, null, body, false, null, null);
        }
        protected virtual MethodDefinitionExpression CreateCreateErrorResponseMethod()
        {
            var errorCode = Expression.Parameter(typeof(string), "errorCode");
            var message = Expression.Parameter(typeof(string), "errorMessage");
            var stackTrace = Expression.Parameter(typeof(string), "stackTrace");

            var parameters = new Expression[]
            {
                errorCode,
                message,
                stackTrace
            };

            var responseStatusType = FickleType.Define("ResponseStatus");

            var result = FickleExpression.Variable(currentType, "result");
            var responseStatus = FickleExpression.Variable(responseStatusType, "responseStatus");

            var newResult = Expression.Assign(result, Expression.New(currentType));
            var newResponseStatus = Expression.Assign(responseStatus, Expression.New(responseStatusType));

            var methodVariables = new List<ParameterExpression>
            {
                result,
                responseStatus
            };

            var methodStatements = new List<Expression>
            {
                newResponseStatus,
                FickleExpression.Call(responseStatus, "setErrorCode", errorCode),
                FickleExpression.Call(responseStatus, "setMessage", message),
                FickleExpression.Call(responseStatus, "setStackTrace", stackTrace),
                newResult,
                FickleExpression.Call(result, "setResponseStatus", responseStatus),
                Expression.Return(Expression.Label(), result)
            };

            var body = FickleExpression.Block(methodVariables.ToArray(), methodStatements.ToArray());

            return new MethodDefinitionExpression("createErrorResponse", parameters.ToReadOnlyCollection(), AccessModifiers.Public | AccessModifiers.Static, currentType, body, false, null);
        }
		MethodCallExpression ReplaceQueryableMethod (MethodCallExpression old)
		{
			Expression target = null;
			if (old.Object != null)
				target = Visit (old.Object);

			var method = ReplaceQueryableMethod (old.Method);
			var parameters = method.GetParameters ();
			var arguments = new Expression [old.Arguments.Count];

			for (int i = 0; i < arguments.Length; i++) {
				arguments [i] = UnquoteIfNeeded (
					Visit (old.Arguments [i]),
					parameters [i].ParameterType);
			}

			return new MethodCallExpression (target, method, arguments.ToReadOnlyCollection ());
		}
        private Expression CreateParameterisedConstructor()
        {
            var httpClientParam = Expression.Parameter(this.httpClientType, HttpClientFieldName);
            var httpStreamSerializerParam = Expression.Parameter(this.httpStreamSerializerType, HttpStreamSerializerFieldName);

            var parameters = new Expression[]
            {
                httpClientParam,
                httpStreamSerializerParam
            };

            var clientField = Expression.Variable(this.httpClientType, "this." + HttpClientFieldName);
            var serailizerField = Expression.Variable(this.httpStreamSerializerType, "this." + HttpStreamSerializerFieldName);

            var body = FickleExpression.Block(new Expression[]
            {
                Expression.Assign(clientField, httpClientParam).ToStatement(),
                Expression.Assign(serailizerField, httpStreamSerializerParam).ToStatement()

            } );

            return new MethodDefinitionExpression(this.currentTypeDefinitionExpression.Type.Name, parameters.ToReadOnlyCollection(), AccessModifiers.Public, null, body, false, null, null);
        }
        protected virtual MethodDefinitionExpression CreateCreateErrorResponseWithErrorCodeMethod()
        {
            var client = Expression.Parameter(FickleType.Define("PKWebServiceClient"), "client");
            var errorCode = Expression.Parameter(typeof(string), "createErrorResponseWithErrorCode");
            var message = Expression.Parameter(typeof(string), "andMessage");

            var parameters = new Expression[]
            {
                client,
                errorCode,
                message
            };

            var clientOptions = FickleExpression.Property(client, FickleType.Define("NSDictionary"), "options");
            var response = FickleExpression.Variable(FickleType.Define("id"), "response");
            var responseClass = FickleExpression.Call(clientOptions, "Class", "objectForKey", "$ResponseClass");
            var responseStatus = FickleExpression.Call(response, "ResponseStatus", "responseStatus", null);
            var newResponseStatus = FickleExpression.New("ResponseStatus", "init", null);

            var body = FickleExpression.Block
            (
                new [] { response },
                Expression.Assign(response, FickleExpression.Call(FickleExpression.Call(responseClass, response.Type, "alloc", null), response.Type, "init", null)),
                Expression.IfThen(Expression.IsTrue(Expression.Equal(responseStatus, Expression.Constant(null, responseStatus.Type))), FickleExpression.Block(FickleExpression.Call(response, "setResponseStatus", newResponseStatus))),
                FickleExpression.StatementisedGroupedExpression
                (
                    FickleExpression.Call(responseStatus, typeof(string), "setErrorCode", errorCode),
                    FickleExpression.Call(responseStatus, typeof(string), "setMessage", message)
                ),
                Expression.Return(Expression.Label(), response)
            );

            return new MethodDefinitionExpression("webServiceClient", parameters.ToReadOnlyCollection(), FickleType.Define("id"), body, false, null);
        }
        protected virtual MethodDefinitionExpression CreateParseResultMethod()
        {
            var client = Expression.Parameter(FickleType.Define("PKWebServiceClient"), "client");
            var data = Expression.Parameter(FickleType.Define("NSData"), "parseResult");
            var contentType = Expression.Parameter(typeof(string), "withContentType");
            var statusCode = Expression.Parameter(typeof(int), "andStatusCode");
            var response = FickleExpression.Variable("id", "response");
            var options = FickleExpression.Property(client, "NSDictionary", "options");

            var parameters = new Expression[]
            {
                client,
                data,
                contentType,
                statusCode
            };

            var bodyExpressions = new List<Expression>();
            var delegateType = new FickleDelegateType(FickleType.Define("id"), new FickleParameterInfo(client.Type, "client"), new FickleParameterInfo(FickleType.Define("NSData"), "data"));
            var block = Expression.Variable(delegateType, "block");

            bodyExpressions.Add(Expression.Assign(block, FickleExpression.Call(options, FickleType.Define("id"), "objectForKey", Expression.Constant("$ParseResultBlock"))));
            bodyExpressions.Add(Expression.Assign(response, FickleExpression.Call(block, "id", "Invoke", new { client, data })).ToStatement());

            var setResponseStatus = Expression.IfThen
            (
                Expression.Equal(FickleExpression.Call(response, "id", "responseStatus", null), Expression.Constant(null, FickleType.Define("id"))),
                FickleExpression.Call(response, "setResponseStatus", FickleExpression.New("ResponseStatus", "init", null)).ToStatementBlock()
            );

            var populateResponseStatus = FickleExpression.Call(FickleExpression.Call(response, "id", "responseStatus", null), "setHttpStatus", statusCode);

            bodyExpressions.Add(setResponseStatus);
            bodyExpressions.Add(populateResponseStatus);
            bodyExpressions.Add(FickleExpression.Return(response));

            var body = FickleExpression.Block
            (
                new[] { response, block },
                bodyExpressions.ToArray()
            );

            return new MethodDefinitionExpression
            (
                "webServiceClient",
                parameters.ToReadOnlyCollection(),
                FickleType.Define("id"),
                body,
                false,
                null
            );
        }
        protected virtual Expression CreateTryParseMethod()
        {
            var value = Expression.Parameter(typeof(string), "value");
            var methodName = currentTypeDefinition.Type.Name.Capitalize() + "TryParse";
            var result = Expression.Parameter(currentTypeDefinition.Type.MakeByRefType(), "result");
            var retval = Expression.Variable(currentTypeDefinition.Type, "retval");

            var parameters = new Expression[]
            {
                value,
                result
            };

            var parts = Expression.Variable(FickleType.Define("NSArray"), "parts");
            var splitCall = FickleExpression.Call(value, FickleType.Define("NSArray"), "componentsSeparatedByString", new { value = Expression.Constant(",") });
            var part = Expression.Variable(typeof(string), "part");
            var flagCases = new List<SwitchCase>();
            var number = Expression.Variable(FickleType.Define("NSNumber"), "number");

            foreach (var enumValue in ((FickleType)currentTypeDefinition.Type).ServiceEnum.Values)
            {
                flagCases.Add(Expression.SwitchCase(Expression.Assign(retval, Expression.Convert(Expression.Or(Expression.Convert(retval, typeof(int)), Expression.Constant((int)enumValue.Value)), currentTypeDefinition.Type)).ToStatement(), Expression.Constant(enumValue.Name)));
            }

            var foreachBody = FickleExpression.StatementisedGroupedExpression
            (
                Expression.Switch(part, FickleExpression.Return(Expression.Constant(false)).ToStatement(), flagCases.ToArray())
            ).ToBlock();

            var defaultBody = FickleExpression.StatementisedGroupedExpression
            (
                GroupedExpressionsExpressionStyle.Wide,
                Expression.Assign(number, FickleExpression.Call(Expression.New(FickleType.Define("NSNumberFormatter")), number.Type, "numberFromString", value)),
                Expression.IfThen
                (
                    Expression.NotEqual(number, Expression.Constant(null, number.Type)),
                    FickleExpression.StatementisedGroupedExpression
                    (
                        GroupedExpressionsExpressionStyle.Wide,
                        Expression.Assign(result, Expression.Convert(FickleExpression.Call(number, typeof(int), "intValue", null), currentTypeDefinition.Type)),
                        Expression.Return(Expression.Label(), Expression.Constant(true))
                    ).ToBlock()
                ),
                Expression.Assign(parts, splitCall),
                Expression.Assign(retval, Expression.Convert(Expression.Constant(0), currentTypeDefinition.Type)),
                FickleExpression.ForEach(part, parts, foreachBody),
                Expression.Assign(result, retval),
                Expression.Return(Expression.Label(), Expression.Constant(true))
            );

            var cases = new List<SwitchCase>();

            foreach (var enumValue in ((FickleType)currentTypeDefinition.Type).ServiceEnum.Values)
            {
                cases.Add(Expression.SwitchCase(Expression.Assign(result, Expression.Convert(Expression.Constant((int)enumValue.Value), currentTypeDefinition.Type)).ToStatement(), Expression.Constant(enumValue.Name)));
            }

            var switchStatement = Expression.Switch(value, defaultBody, cases.ToArray());

            var body = FickleExpression.Block(new[] { parts, number, retval }, switchStatement, Expression.Return(Expression.Label(), Expression.Constant(true)));

            return new MethodDefinitionExpression(methodName, parameters.ToReadOnlyCollection(), AccessModifiers.Static | AccessModifiers.ClasseslessFunction, typeof(bool), body, false, "__unused", null);
        }
		protected virtual FunctionResolveResult ResolveSqlFunction(SqlFunctionCallExpression functionExpression)
		{
			var function = functionExpression.Function;
			var arguments = functionExpression.Arguments;

			switch (function)
			{
			case SqlFunction.IsNull:
				return new FunctionResolveResult("", true, arguments)
				{
					functionSuffix = " IS NULL"
				};
			case SqlFunction.IsNotNull:
				return new FunctionResolveResult("", true, arguments)
				{
					functionSuffix = " IS NOT NULL"
				};
			case SqlFunction.In:
				return new FunctionResolveResult("IN", true, arguments);
			case SqlFunction.Exists:
				return new FunctionResolveResult("EXISTSOPERATOR", true, arguments)
				{
					functionPrefix = " EXISTS "
				};
			case SqlFunction.UserDefined:
				return new FunctionResolveResult(functionExpression.UserDefinedFunctionName, false, arguments);
			case SqlFunction.Coalesce:
				return new FunctionResolveResult("COALESCE", false, arguments);
			case SqlFunction.Like:
				return new FunctionResolveResult(this.sqlDialect.GetSyntaxSymbolString(SqlSyntaxSymbol.Like), true, arguments);
			case SqlFunction.CompareObject:
				var expressionType = (ExpressionType)((ConstantExpression)arguments[0].StripConstantWrappers()).Value;
				var args = new Expression[2];

				args[0] = arguments[1];
				args[1] = arguments[2];

				switch (expressionType)
				{
					case ExpressionType.LessThan:
						return new FunctionResolveResult("<", true, args.ToReadOnlyCollection());
					case ExpressionType.LessThanOrEqual:
						return new FunctionResolveResult("<=", true, args.ToReadOnlyCollection());
					case ExpressionType.GreaterThan:
						return new FunctionResolveResult(">", true, args.ToReadOnlyCollection());
					case ExpressionType.GreaterThanOrEqual:
						return new FunctionResolveResult(">=", true, args.ToReadOnlyCollection());
				}
				throw new InvalidOperationException();
			case SqlFunction.NotLike:
				return new FunctionResolveResult("NOT " + this.sqlDialect.GetSyntaxSymbolString(SqlSyntaxSymbol.Like), true, arguments);
			case SqlFunction.ServerNow:
				return new FunctionResolveResult("NOW", false, arguments);
			case SqlFunction.ServerUtcNow:
				return new FunctionResolveResult("UTCNOW", false, arguments);
			case SqlFunction.StartsWith:
			{
				var newArgument = new SqlFunctionCallExpression(typeof(string), SqlFunction.Concat, arguments[1], Expression.Constant("%"));
				var optimisedNewArgument = SqlRedundantFunctionCallRemover.Remove(newArgument);

				if (optimisedNewArgument != newArgument)
				{
					if (SqlExpressionFinder.FindExists(arguments[1], c => c.NodeType == (ExpressionType)SqlExpressionType.ConstantPlaceholder))
					{
						canReuse = false;
						this.parameterIndexToPlaceholderIndexes = null;
					}
				}

				var list = new List<Expression>
				{
					arguments[0],
					optimisedNewArgument
				};

				return new FunctionResolveResult(this.sqlDialect.GetSyntaxSymbolString(SqlSyntaxSymbol.Like), true, list.ToReadOnlyCollection());
			}
			case SqlFunction.ContainsString:
			{
				var newArgument = new SqlFunctionCallExpression(typeof(string), SqlFunction.Concat, arguments[1], Expression.Constant("%"));
				newArgument = new SqlFunctionCallExpression(typeof(string), SqlFunction.Concat, Expression.Constant("%"), newArgument);
				var optimisedNewArgument = SqlRedundantFunctionCallRemover.Remove(newArgument);

				if (optimisedNewArgument != newArgument)
				{
					if (SqlExpressionFinder.FindExists(arguments[1], c => c.NodeType == (ExpressionType)SqlExpressionType.ConstantPlaceholder))
					{
						canReuse = false;
						this.parameterIndexToPlaceholderIndexes = null;
					}
				}

				var list = new List<Expression>
				{
					arguments[0],
					optimisedNewArgument
				};

				return new FunctionResolveResult(this.sqlDialect.GetSyntaxSymbolString(SqlSyntaxSymbol.Like), true, list.ToReadOnlyCollection());
			}
			case SqlFunction.EndsWith:
			{
				var newArgument = new SqlFunctionCallExpression(typeof(string), SqlFunction.Concat, Expression.Constant("%"), arguments[1]);
				var optimisedNewArgument = SqlRedundantFunctionCallRemover.Remove(newArgument);

				if (optimisedNewArgument != newArgument)
				{
					if (SqlExpressionFinder.FindExists(arguments[1], c => c.NodeType == (ExpressionType)SqlExpressionType.ConstantPlaceholder))
					{
						canReuse = false;
						this.parameterIndexToPlaceholderIndexes = null;
					}
				}

				var list = new List<Expression>
				{
					arguments[0],
					optimisedNewArgument
				};

				return new FunctionResolveResult(this.sqlDialect.GetSyntaxSymbolString(SqlSyntaxSymbol.Like), true, list.ToReadOnlyCollection());
			}
			case SqlFunction.StringLength:
				return new FunctionResolveResult("LENGTH", false, arguments);
			default:
				return new FunctionResolveResult(function.ToString().ToUpper(), false, arguments);
			}
		}