private Dictionary <string, CodePropertyReferenceExpression> CreatePropertiesForResources(IEnumerable <Resource> resources)
 {
     return(resources.ToDictionary(resource => resource.Key, resource =>
     {
         DataTemplateResource dataTemplateResource = resource as DataTemplateResource;
         Tuple <CodeMemberField, CodeMemberProperty> result;
         if (dataTemplateResource != null)                 // in case of data templates
         {
             const string type = "Storm.Mvvm.DataTemplate";
             result = CodeGeneratorHelper.GenerateProxyProperty(resource.PropertyName, type, fieldReference => new List <CodeStatement>
             {
                 // _field = new DataTemplate();
                 new CodeAssignStatement(fieldReference, new CodeObjectCreateExpression(CodeGeneratorHelper.GetTypeReferenceFromName(type))),
                 // _field.ViewId = Resource.Id.***
                 new CodeAssignStatement(new CodePropertyReferenceExpression(fieldReference, "ViewId"), CodeGeneratorHelper.GetAndroidResourceReference(ResourcePart.Layout, dataTemplateResource.ViewId)),
                 // _field.LayoutInflater = LayoutInflater;
                 new CodeAssignStatement(new CodePropertyReferenceExpression(fieldReference, "LayoutInflater"), GetLayoutInflaterReference()),
                 // _field.ViewHolderType = typeof(viewholder class)
                 new CodeAssignStatement(new CodePropertyReferenceExpression(fieldReference, "ViewHolderType"), new CodeTypeOfExpression(string.Format("{0}.{1}", Configuration.GeneratedNamespace, dataTemplateResource.ViewHolderClassName))),
             });
         }
         else
         {
             // create a proxy property to handle the resource
             string type = resource.Type;
             Dictionary <string, string> assignments = resource.Properties;
             result = CodeGeneratorHelper.GenerateProxyProperty(resource.PropertyName, type, fieldReference => CodeGeneratorHelper.GenerateStatementsCreateAndAssign(fieldReference, type, assignments));
         }
         Fields.Add(result.Item1);
         Properties.Add(result.Item2);
         return CodeGeneratorHelper.GetPropertyReference(result.Item2);
     }));
 }
        public void Preprocess(List <XmlAttribute> expressionAttributes, List <Resource> resources, List <IdViewObject> viewElements)
        {
            // Create all properties for viewElements
            foreach (IdViewObject viewElement in viewElements)
            {
                Tuple <CodeMemberField, CodeMemberProperty> result = CodeGeneratorHelper.GenerateProxyProperty(viewElement.Id, viewElement.TypeName, new CodeMethodInvokeExpression(GetFindViewByIdReference(viewElement.TypeName), CodeGeneratorHelper.GetAndroidResourceReference(ResourcePart.Id, viewElement.Id)));
                Fields.Add(result.Item1);
                Properties.Add(result.Item2);
            }

            // Generate property for ILocalizationService LocalizationService
            CodePropertyReferenceExpression localizationServiceReference = CreateLocalizationServiceProperty();

            // Eval all expressions
            List <ExpressionContainer> expressions = (from attribute in expressionAttributes
                                                      let expressionResult = EvaluateExpression(attribute.Value)
                                                                             where expressionResult != null
                                                                             select new ExpressionContainer
            {
                Expression = expressionResult,
                TargetObject = attribute.AttachedId,
                TargetField = attribute.LocalName,
                IsTargetingResource = false,
            }).ToList();

            // Affect a property name to all resources and check if some has expression as attribute value
            foreach (Resource res in resources)
            {
                res.PropertyName = NameGeneratorHelper.GetResourceName();
                foreach (KeyValuePair <string, string> propertyItem in res.Properties.Where(propertyItem => ParsingHelper.IsExpressionValue(propertyItem.Value)).ToList())
                {
                    res.Properties.Remove(propertyItem.Key);

                    Expression expr = EvaluateExpression(propertyItem.Value);
                    if (expr != null)
                    {
                        if (CheckCorrectExpressionInResource(expr))
                        {
                            Log.LogError("Expression {0} is invalid in a resource context (you cannot use binding)", propertyItem.Value);
                        }
                        else
                        {
                            expressions.Add(new ExpressionContainer
                            {
                                Expression          = expr,
                                TargetObject        = res.PropertyName,
                                TargetField         = propertyItem.Key,
                                IsTargetingResource = true,
                            });
                        }
                    }
                }
            }

            // Check if all resources are declared and filter those we need
            Dictionary <string, Resource> neededResource = new Dictionary <string, Resource>();
            List <string> resourceKeys = expressions.SelectMany(x => GetUsedResources(x.Expression)).Distinct().ToList();

            foreach (string key in resourceKeys)
            {
                Resource res = resources.FirstOrDefault(x => key.Equals(x.Key, StringComparison.InvariantCultureIgnoreCase));
                if (res == null)
                {
                    Log.LogError("Resource with key {0} does not exists", key);
                }
                else
                {
                    neededResource.Add(key, res);
                }
            }


            // Go through all binding expression and find those where we need to declare implicit resources
            // Will also remove all Template & TemplateSelector fields in BindingExpression
            // to only have a fully prepared adapter
            foreach (Expression bindingExpression in expressions.SelectMany(expression => GetBindingExpressions(expression.Expression)).ToList())
            {
                if (bindingExpression.Has(BindingExpression.TEMPLATE))
                {
                    // create a template selector
                    string templateSelectorKey          = NameGeneratorHelper.GetResourceKey();
                    string templateSelectorPropertyName = NameGeneratorHelper.GetResourceName();
                    neededResource.Add(templateSelectorKey, new Resource(templateSelectorKey)
                    {
                        PropertyName    = templateSelectorPropertyName,
                        ResourceElement = null,
                        Type            = Configuration.DefaultTemplateSelector
                    });
                    expressions.Add(new ExpressionContainer
                    {
                        Expression          = bindingExpression[BindingExpression.TEMPLATE],
                        TargetField         = Configuration.DefaultTemplateSelectorField,
                        TargetObject        = templateSelectorPropertyName,
                        IsTargetingResource = true,
                    });
                    bindingExpression.Remove(BindingExpression.TEMPLATE);

                    ResourceExpression templateSelectorResourceExpression = new ResourceExpression();
                    templateSelectorResourceExpression.Add(ResourceExpression.KEY, new TextExpression
                    {
                        Value = templateSelectorKey
                    });
                    bindingExpression.Add(BindingExpression.TEMPLATE_SELECTOR, templateSelectorResourceExpression);
                }

                if (bindingExpression.Has(BindingExpression.TEMPLATE_SELECTOR))
                {
                    // create an adapter
                    string adapterKey  = NameGeneratorHelper.GetResourceKey();
                    string adapterName = NameGeneratorHelper.GetResourceName();
                    neededResource.Add(adapterKey, new Resource(adapterKey)
                    {
                        PropertyName    = adapterName,
                        ResourceElement = null,
                        Type            = Configuration.DefaultAdapter
                    });
                    expressions.Add(new ExpressionContainer
                    {
                        Expression          = bindingExpression[BindingExpression.TEMPLATE_SELECTOR],
                        TargetField         = Configuration.DefaultAdapterField,
                        TargetObject        = adapterName,
                        IsTargetingResource = true,
                    });
                    bindingExpression.Remove(BindingExpression.TEMPLATE_SELECTOR);
                    ResourceExpression adapterResourceExpression = new ResourceExpression();
                    adapterResourceExpression.Add(ResourceExpression.KEY, new TextExpression
                    {
                        Value = adapterKey
                    });
                    bindingExpression.Add(BindingExpression.ADAPTER, adapterResourceExpression);
                }
            }

            // In order to check if all adapter are not used more than once since we need them to be unique target
            Dictionary <string, bool> usedAdapter = new Dictionary <string, bool>();

            foreach (ExpressionContainer expression in expressions.Where(x => x.Expression.IsOfType(ExpressionType.Binding)).ToList())
            {
                Expression bindingExpression = expression.Expression;
                if (bindingExpression.Has(BindingExpression.ADAPTER))
                {
                    // expression in Adapter could only be Resource (since it's an android platform specific things, a binding expression would not have any sense)
                    Expression resourceExpression = bindingExpression[BindingExpression.ADAPTER];
                    string     adapterKey         = resourceExpression.GetValue(ResourceExpression.KEY);
                    Resource   adapterResource    = neededResource[adapterKey];

                    if (usedAdapter.ContainsKey(adapterKey))
                    {
                        Log.LogError("The adapter with key {0} is used more than once which could lead to issue, you need one adapter per use !", adapterKey);
                    }
                    else
                    {
                        usedAdapter.Add(adapterKey, true);
                    }

                    // remove the adapter property
                    bindingExpression.Remove(BindingExpression.ADAPTER);

                    // store old target info
                    string oldTargetField  = expression.TargetField;
                    string oldTargetObject = expression.TargetObject;
                    bool   oldTargetType   = expression.IsTargetingResource;

                    // retarget the binding expression to be targeted to Adapter.Collection
                    expression.TargetField         = "Collection";
                    expression.TargetObject        = adapterResource.PropertyName;
                    expression.IsTargetingResource = false;                     //TODO : false for debug mode only, need to see what we can do about that ?

                    // add a new expression to target the old object/field couple and affect the adapter with the resource expression
                    expressions.Add(new ExpressionContainer
                    {
                        IsTargetingResource = oldTargetType,
                        TargetField         = oldTargetField,
                        TargetObject        = oldTargetObject,
                        Expression          = resourceExpression,
                    });
                }
            }

            // Create all properties for resources
            Dictionary <string, CodePropertyReferenceExpression> resourceReferences = CreatePropertiesForResources(neededResource.Values);

            // Generate all properties to handle CommandParameter and retarget all expressions if needed
            GenerateCommandParameterProperties(expressions);

            // Create a setup resources method to initalize resources with all {Resource ...} and {Translation ...} expressions
            List <ExpressionContainer> translationExpressions        = expressions.Where(x => x.Expression.IsOfType(ExpressionType.Translation)).ToList();
            List <ExpressionContainer> expressionsTargetingResources = expressions.Where(x => x.IsTargetingResource && x.Expression.IsOfType(ExpressionType.Resource)).ToList();
            List <ExpressionContainer> resourceExpressions           = expressions.Where(x => !x.IsTargetingResource && x.Expression.IsOfType(ExpressionType.Resource)).ToList();
            List <ExpressionContainer> bindingExpressions            = expressions.Where(x => !x.IsTargetingResource && x.Expression.IsOfType(ExpressionType.Binding)).ToList();

            CodeMethodReferenceExpression assignTranslationMethodReference = CreateAssignTranslationMethod(translationExpressions, localizationServiceReference);
            CodeMethodReferenceExpression setupResourcesReference          = CreateSetupResourcesMethod(expressionsTargetingResources, resourceReferences);
            CodeMethodReferenceExpression setupResourceForViewElement      = CreateSetupResourceForViewElementMethod(resourceExpressions, resourceReferences);

            CreateBindingOverrideMethod(bindingExpressions, localizationServiceReference, resourceReferences, assignTranslationMethodReference, setupResourcesReference, setupResourceForViewElement);
        }