private void ProcessNode(Class targetClass, Variable parent, string targetList, XmlNode xmlNode)
        {
            if (xmlNode == null) return;
            if (standalone == false) // generate GUID for each xmlnode
                if (nodeMap.ContainsKey(xmlNode) == false) nodeMap[xmlNode] = Guid.NewGuid().ToString();
            //Console.WriteLine("Processing: {0}", xmlNode.Name);

            Variable obj = parent;
            string list = null;
            if (xmlNode.Name == "ZApplication")
            {
                if (fullBuild) ParseAttributes(ns.mainClass, parent, xmlNode);
            }
            else
            {
                // Check if this node is a List property of the parent
                //FieldInfo fi = parent.type.GetField(xmlNode.Name, BindingFlags.FlattenHierarchy | BindingFlags.Public  | BindingFlags.NonPublic | BindingFlags.Instance);
                FieldInfo fi = CodeGenerator.GetField(parent.type, xmlNode.Name);
                //if (pi != null) Console.WriteLine(" Parent property found: {0}", pi.PropertyType.Name);
                if (fi != null && typeof(IList).IsAssignableFrom(fi.FieldType))
                {
                    //Console.WriteLine("List found: {0}", xmlNode.Name);
                    list = fi.Name;
                }
                // Check if this node is an event of the parent
                else if (fi != null && typeof(Delegate).IsAssignableFrom(fi.FieldType))
                {
                    Type type = fi.FieldType;
                    string currentGuid = "";
                    if (standalone == false) nodeMap.TryGetValue(xmlNode, out currentGuid);                    
                    
                    string methodName = targetClass.GetNextMethodName();
                    //bool isStatic = targetClass.baseClass.StartsWith("Prototype");
                    string header = GetMethodHeader(methodName, type, false);
                    Method met = new Method(header);
                    targetClass.methods.Add(met);
                    //if (isStatic)
                    //{
                        //Automatically cast the caller to the type of the Model class
                        //met.AddLine(String.Format("{0} model = caller as {0};", targetClass.name));
                    //}
                    met.AddLine(xmlNode.InnerText);
                    // BIND THE CALLBACK
                    if (targetClass.type == typeof(Model))
                        targetClass.init.AddLine(String.Format("{0} += {1};", fi.Name, methodName)); // init method points to BindCallbacks()
                    
                    if (fullBuild)
                    {
                        // Add the generated method as an event handler                       
                        if (targetClass.type == typeof(ZApplication))
                            ns.mainClass.init.AddLine(String.Format("{0}.{1} += {2};", parent.name, fi.Name, methodName));
                        if (standalone == false) // Create a ZEvent (always in CustomGame)
                        {
                            string varName = ns.mainClass.GetNextObjectName();
                            ns.mainClass.init.AddLine("");
                            ns.mainClass.init.AddLine(String.Format("var {0} = new ZEvent({1}, \"{2}\");", varName, parent.name, fi.Name));
                            // assign a GUID to the ZEvent
                            ns.mainClass.init.AddLine(String.Format("{0}.GUID = \"{1}\";", varName, currentGuid));
                            // store the text of the method (for editing purposes)
                            string escaped = xmlNode.InnerText.Replace("\"", "\"\"");  // escape inner strings " -> ""
                            ns.mainClass.init.AddLine(String.Format("{0}.Text = @\"{1}\";", varName, escaped));
                        }
                    }
                    else
                    {
                        if (targetClass.type != typeof(Model))
                        {
                            string exprName = ns.mainClass.GetNextObjectName();
                            ns.mainClass.restore.AddLine("");
                            ns.mainClass.restore.AddLine(String.Format("ZEvent {0} = oldApp.FindEvent(\"{1}\");", exprName, currentGuid));
                            ns.mainClass.restore.AddLine(String.Format("CodeGenerator.RestoreEvent({0}, {1}, \"{2}\");", exprName, targetClass.variable, methodName));
                        }
                    }
                    return; //return here, so no TreeNode will be created for the CodeLike component
                }
                // Check if this node is a CodeLike property of the parent
                else if (fi != null && typeof(CodeLike).IsAssignableFrom(fi.FieldType))
                {
                    Type type = fi.FieldType;
                    if (type == typeof(CustomCodeDefinition)) // handle custom code definitions
                    {
                        targetClass.definitions.Add(xmlNode.InnerText);
                    }                        
                    else if (type == typeof(VirtualMethod))
                    {
                        string methodName = targetClass.GetNextMethodName();                           
                        object[] attributes = fi.GetCustomAttributes(typeof(MethodSignature), false);
                        if (attributes.Length == 1 && attributes[0] is MethodSignature)
                        {                          
                            MethodSignature ms = attributes[0] as MethodSignature;
                            Method met = new Method(ms.Signature);
                            targetClass.methods.Add(met);
                            met.AddLine(xmlNode.InnerText);
                        }
                        else
                        {
                            Console.WriteLine("Missing MethodSignature attribute on VirtualMethod: {0}.{0}", parent.name, xmlNode.Name);
                            return;
                        }   
                    }
//                     if (standalone == false && fullBuild == true) // assign the GUIDs to the CodeLike components
//                     {                        
//                         ns.mainClass.init.AddLine(String.Format("{0}.{1}.GUID = \"{2}\";", parent.name, fi.Name, currentGuid));
// 
//                     }
                    // if not shader
                    if (standalone == false && fullBuild == true) // no need for the code text in a standalone build
                    {
                        string escaped = xmlNode.InnerText.Replace("\"", "\"\"");  // escape inner strings " -> ""
                        ns.mainClass.init.AddLine(String.Format("{0}.{1}.Text = @\"{2}\";", parent.name, fi.Name, escaped));
                    }
                    //Console.WriteLine("Code Text:\n{0}", code.Text);                    
                    return; //return here, so no TreeNode will be created for the CodeLike component
                }
                else
                {
                    obj = InitComponent(ns.mainClass, xmlNode.Name, xmlNode, parent, targetList);
                    if (obj == null)
                    {
                        Console.WriteLine("SKIPPING subtree - Cannot find type: {0}", xmlNode.Name);
                        return;
                    }
                    if (xmlNode.Name == "Model")
                    {
                        string modelName = obj.name + "Model";
                        Class model = new Class(typeof(Model), modelName, "Model", obj.name, false);
                        //String.Format("Prototype<{0}>", modelName)
                        
                        model.constructor = new Method("public " + modelName + "(ZComponent parent): base(parent)");
                        var staticApp = new StaticVariable(typeof(ZApplication), "CustomGame", "App", false);
                        model.memberVars.Add(staticApp);
                        ns.mainClass.staticRef.AddLine(String.Format("{0}.App = this;", modelName));

                        //model.constructor.AddLine("InitializeComponents();");
                        model.init = new Method("public override void BindCallbacks()");
                        //model.init.AddLine("CreateNamedComponents();");
                        //model.createNamed = new Method("public void CreateNamedComponents()");
                        ns.helperClasses.Add(model);
                        targetClass = model;
                    }
                }
            }
            foreach (XmlNode childNode in xmlNode.ChildNodes)
            {
                if (childNode.NodeType == XmlNodeType.Element)
                {
                    ProcessNode(targetClass, obj, list, childNode);
                }
            }            
        }
 private void ParseAttributes(Class targetClass, Variable obj, XmlNode xmlNode)
 {
     if (xmlNode.Attributes != null)
     {
         foreach (XmlAttribute attribute in xmlNode.Attributes)
         {
             //if (attribute.Name == "Name") continue;
             if (xmlNode.Name == "GameObject" && attribute.Name == "Model") continue;
             string val = attribute.Value;
             FieldInfo fi = obj.type.GetField(attribute.Name, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
             if (fi != null)
             {
                 Type type = fi.FieldType;
                 if (xmlNode.Name == "ZApplication" && specialVars.Contains(attribute.Name))
                     SetAttribute(targetClass.constructor, type, val, obj.name, attribute.Name);
                 else    
                     SetAttribute(targetClass.init, type, val, obj.name, attribute.Name);
             }                    
             else
             {
                 // Also try a Property with a public setter
                 PropertyInfo pi = obj.type.GetProperty(attribute.Name, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
                 if (pi != null && pi.GetSetMethod() != null)
                 {                            
                     SetAttribute(targetClass.init, pi.PropertyType, val, obj.name, attribute.Name);
                 }
                 else
                 {
                     // These components might have custom fields (those will be resolved after compilation)
                     if (xmlNode.Name == "ZApplication" || xmlNode.Name == "Model" || xmlNode.Name == "GameObject")
                     {
                         unresolved.Add(new UnresolvedField
                         {
                             targetClass = targetClass,
                             objName = obj.name,
                             objTypeName = obj.typeName,
                             fieldName = attribute.Name,
                             value = val
                         });
                     }
                     else
                         Console.WriteLine(" Field not found: {0} - {1}", attribute.Name, val);
                 }                        
             }
         }
     }
 }
        private Variable InitComponent(Class targetClass, string typeName, XmlNode xmlNode, Variable parent, string targetList)
        {
            var type = types.Find(it => it.Name == typeName);
            Variable obj = null;
            string model = null;
            if (typeName == "GameObject")
            {
                XmlAttribute attribute = xmlNode.Attributes["Model"];
                if (attribute != null)
                {
                    model = attribute.Value;
                    typeName = attribute.Value + "Model";
                    type = typeof(Model);
                }
                else
                {
                    Console.WriteLine("Cannot instantiate GameObject without a Model!");
                    return null;
                }
            }

            if (type != null)
            {
                if (fullBuild) targetClass.init.AddLine("");
                XmlAttribute attribute = xmlNode.Attributes["Name"];
                if (attribute == null)
                {
                    string objName = targetClass.GetNextObjectName();
                    obj = new Variable(type, typeName, objName, false);
                    if (typeName == "Model")
                    {
                        Console.WriteLine("Cannot process Model without a name!");
                        return null;
                    }
                    if (fullBuild)
                    {
                        if (model != null) //GameObject without a name, it has to be CLONED
                        {
                            targetClass.init.AddLine(String.Format("var {0} = ({1}) {2}.Clone();", objName, typeName, model));
                        }
                        else
                            targetClass.init.AddLine(String.Format("var {0} = new {1}({2});", objName, typeName, parent.name));
                    }                    
                }
                else
                {
                    string objName = attribute.Value;
                    if (typeName == "Model") typeName = objName + "Model";
                    obj = new Variable(type, typeName, objName, false);
                    targetClass.memberVars.Add(obj);
                    if (fullBuild)
                    {
                        if (model != null) //GameObject with a name, it has to be CLONED
                        {
                            targetClass.init.AddLine(String.Format("{0} = ({1}) {2}.Clone();", objName, typeName, model));
                        }
                        else
                        {                              
                            targetClass.createNamed.AddLine(String.Format("{0} = new {1}({2});", objName, typeName, parent.name));
                        }
                    }
                    else if (xmlNode.Name == "Model") 
                    {
                        targetClass.restore.AddLine("");
                        targetClass.restore.AddLine(String.Format("{0} = new {1}({2});", objName, typeName, parent.name));
                        //targetClass.restore.AddLine(String.Format("{0} = {1}.CreatePrototype();", objName, typeName));
                        string currentGuid = "";
                        nodeMap.TryGetValue(xmlNode, out currentGuid);
                        targetClass.restore.AddLine(String.Format("CodeGenerator.Restore({0}, oldApp.FindPrototype(\"{1}\"));", objName, currentGuid));
                        // Re-create all GameObjects in the scene by cloning the Model prototypes
                        targetClass.restore.AddLine(String.Format("foreach (Model gameObj in oldApp.FindGameObjects(\"{0}\"))", currentGuid));
                        targetClass.restore.AddLine("{");
                        //targetClass.restore.AddLine("Console.WriteLine(\"GO found: {0} - {1}\", gameObj.GetType().Name, gameObj.Name);");
                        targetClass.restore.AddLine(String.Format("    var temp = {0}.Clone() as Model;", objName));
                        targetClass.restore.AddLine(String.Format("    CodeGenerator.Restore(temp, gameObj);"));
                        targetClass.restore.AddLine(String.Format("    if (oldApp.SelectedObject == gameObj) this.SelectedObject = temp;"));
                        targetClass.restore.AddLine("}");
                    }                    
                }

                if (fullBuild)
                {
                    ParseAttributes(targetClass, obj, xmlNode);
                    //targetClass.init.AddLine(String.Format("AddComponent({0});", obj.name));
                    if (standalone == false) // assign GUIDs to Model components
                    {
                        if (xmlNode.Name == "Model")
                        {
                            string currentGuid = "";
                            nodeMap.TryGetValue(xmlNode, out currentGuid);
                            targetClass.createNamed.AddLine(String.Format("{0}.GUID = \"{1}\";", obj.name, currentGuid));
                        }
                    }                    
                    if (parent != null)
                    {
                        // We always need an Owner
                        //targetClass.init.AddLine(String.Format("{0}.Owner = {1};", obj.name, parent.name));

                        if (targetList != null) // components in member lists are not considered children!
                        {
                            //Console.WriteLine("Adding to list: {0}", parent_list.GetType().Name);
                            //targetClass.init.AddLine(String.Format("{0}.OwnerList = (IList) {1}.{2};", obj.name, parent.name, targetList));
                            //targetClass.init.AddLine(String.Format("{0}.{1}.Add({2});", parent.name, targetList, obj.name));
                            targetClass.init.AddLine(String.Format("{0}.SetOwner({1}, (IList) {1}.{2});", obj.name, parent.name, targetList));
                        }
                        else
                        {                            
                            //targetClass.init.AddLine(String.Format("{0}.Children.Add({1});", parent.name, obj.name));
                            targetClass.init.AddLine(String.Format("{0}.SetOwner({1}, null);", obj.name, parent.name));
                        }
                    }
                }               
            }
            return obj;
        }
        public string GenerateCodeFromXml(XmlDocument xml, bool standalone, bool fullBuild, Dictionary<XmlNode, string> nodeMap)
        {
            XmlNode rootElement = xml.DocumentElement;
            
            if (standalone && fullBuild == false) fullBuild = true; // no incremental build for standalone
            this.standalone = standalone;
            this.fullBuild = fullBuild;

            if (standalone == false) // no need for XmlNode->GUID mapping at standalone builds
            {
                if (nodeMap == null)
                    this.nodeMap = new Dictionary<XmlNode, string>();
                else
                    this.nodeMap = nodeMap;
            }

            cu = new CompileUnit();
            cu.AddUsing("using System;");
            cu.AddUsing("using System.Collections;");
            cu.AddUsing("using System.Collections.Generic;");
            cu.AddUsing("using System.Text;");
            cu.AddUsing("using System.Drawing;");
            cu.AddUsing("using OpenTK;");
            cu.AddUsing("using OpenTK.Graphics;");
            cu.AddUsing("using OpenTK.Graphics.OpenGL;");
            cu.AddUsing("using ZGE.Components;");
            cu.AddUsing("using Gwen.Control;");
            //if (standalone == false)
            //    cu.AddUsing("using System.ComponentModel");

            ns = new Namespace("ZGE");
            cu.namespaces.Add(ns);
            Class main = new Class(typeof(ZApplication), "CustomGame", "ZApplication", "this", true);
            ns.mainClass = main;
            main.constructor = new Method("public CustomGame()");
            main.staticRef = new Method("public override void SetStaticReferences()");
            if (fullBuild)
            {
                //main.constructor.AddLine("if (createAll) InitializeComponents();");
                main.init = new Method("public override void InitializeComponents()");
                main.init.AddLine("CreateNamedComponents();");
                main.createNamed = new Method("public override void CreateNamedComponents()");                
            }
            else
            {                
                main.restore = new Method("public void RestoreComponents(ZApplication oldApp)");
                main.restore.AddLine("CodeGenerator.Restore(this, oldApp);");                
            }
            

            types = Factory.GetTypesFromNamespace(Assembly.GetAssembly(typeof(ZApplication)), "ZGE.Components");
            types.AddRange(Factory.GetTypesFromNamespace(Assembly.GetAssembly(typeof(ZApplication)), "Gwen.Control"));
            Variable dummy = new Variable(typeof(ZApplication), "CustomGame", "this", false);
            if (rootElement != null)
                ProcessNode(main, dummy, null, rootElement);

            if (standalone)
            {
                Method mm = new Method("[STAThread]\npublic static void Main()");
                main.methods.Add(mm);
                mm.AddLine("ZApplication app = new CustomGame();");
                mm.AddLine("using (Standalone game = new Standalone(app))");
                mm.AddLine("{");
                mm.AddLine("    game.Run(app.UpdateFrequency);");
                mm.AddLine("}");
            }            

            string code = cu.GetFullCode();
            // Save the file for debugging
            using (StreamWriter writer = new StreamWriter("DynamicGame.cs", false))
            {
                writer.Write(code);
            }
            return code;
        }