private void SetAttribute(Method targetMethod, Type type, string val, string objName, string fieldName)
 {
     if (type == typeof(string))
         targetMethod.AddLine(String.Format("{0}.{1} = \"{2}\";", objName, fieldName, val));
     else if (type == typeof(bool))
         targetMethod.AddLine(String.Format("{0}.{1} = {2};", objName, fieldName, val.ToLowerInvariant()));
     else if (type.IsPrimitive)  // a cast might be necessary (e.g. float)                        
         targetMethod.AddLine(String.Format("{0}.{1} = ({2}){3};", objName, fieldName, GetPlainTypeName(type), val));
     else if (type.IsEnum)
         targetMethod.AddLine(String.Format("{0}.{1} = {2}.{3};", objName, fieldName, type.Name, val));
     else if (type.IsSubclassOf(typeof(ZComponent))) // simple assignment to a named component
         targetMethod.AddLine(String.Format("{0}.{1} = {2};", objName, fieldName, val));
     else if (type == typeof(Vector3) || type == typeof(Vector2)) // cast all constuctor parameters to float
     {
         string commaList = string.Join(", ", val.Split(' ').Select(it => "(float)" + it).ToArray());
         targetMethod.AddLine(String.Format("{0}.{1} = new {2}({3});", objName, fieldName, type.Name, commaList));
     }
     else if (type == typeof(Color))  // make a Color4 instead with float parameters
     {
         string commaList = string.Join(", ", val.Split(' ').Select(it => "(float)" + it).ToArray());
         targetMethod.AddLine(String.Format("{0}.{1} = new {2}({3});", objName, fieldName, "Color4", commaList));
     }
     else
     {
         string commaList = string.Join(", ", val.Split(' '));
         targetMethod.AddLine(String.Format("{0}.{1} = new {2}({3});", objName, fieldName, type.Name, commaList));
     }
 }
        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);
                }
            }            
        }
        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;
        }