private void AddSupportedPortDetails(ClassFileGenerator cfg, string implementedPort, bool isImplemented = true)
        {
            var type = implementedPort.Split()[0];
            var name = implementedPort.Split()[1];

            if (type.StartsWith("IEvent") && !type.StartsWith("IEventB"))
            {
                if (isImplemented)
                {
                    cfg.AddField("EventConnector",
                                 $"{name}Connector",
                                 accessLevel: "private",
                                 defaultValue: $"new EventConnector() {{ InstanceName = \"{name}Connector\" }}",
                                 region: "Input instances");

                    List <string> methodBody = new List <string>();
                    methodBody.Add($"({name}Connector as IEvent).Execute();");

                    cfg.AddMethod("IEvent.Execute", region: $"{type} implementation", methodBody: methodBody);
                }
                else
                {
                    cfg.AddField("EventConnector",
                                 $"{name}Connector",
                                 accessLevel: "private",
                                 defaultValue: $"new EventConnector() {{ InstanceName = \"{name}Connector\" }}",
                                 region: "Output instances");
                }
            }
            else if (type.StartsWith("IDataFlow"))
            {
                if (type.StartsWith("IDataFlowB"))
                {
                }
                else
                {
                    var internalDataType = type.Replace("IDataFlow<", "");
                    internalDataType = internalDataType.Substring(0, internalDataType.Length - 1);

                    if (isImplemented)
                    {
                        cfg.AddField($"DataFlowConnector<{internalDataType}>", $"{name}Connector",
                                     accessLevel: "private",
                                     defaultValue: $"new DataFlowConnector<{internalDataType}>() {{ InstanceName = \"{name}Connector\" }}",
                                     region: "Input instances");

                        string setterBody = $"{{({name}Connector as IDataFlow<{internalDataType}>).Data = value;}}";

                        cfg.AddProperty(internalDataType, $"{type}.Data", region: $"{type} implementation", setterBody: setterBody);
                    }
                    else
                    {
                        cfg.AddField($"Apply<{internalDataType}, {internalDataType}>", $"{name}Connector",
                                     accessLevel: "private",
                                     defaultValue: $"new Apply<{internalDataType}, {internalDataType}>() {{ InstanceName = \"{name}Connector\", Lambda = input => input }}",
                                     region: "Output instances");
                    }
                }
            }
            else if (type.StartsWith("IUI"))
            {
                cfg.AddMethod("IUI.GetWPFElement", returnType: "UIElement", region: $"{type} implementation");
            }
        }
        private void Create()
        {
            try
            {
                var cfg = new ClassFileGenerator()
                {
                    Namespace             = $"{NamespacePrefix}{Enum.GetName(typeof(Enums.ALALayer), Layer)}",
                    ClassName             = ClassName,
                    ImplementedInterfaces = ImplementedPorts.Select(s => s.Split().First()).ToList(), // Just get interface types
                    IsInterface           = Layer == Enums.ALALayer.ProgrammingParadigms
                };

                if (Layer != Enums.ALALayer.ProgrammingParadigms)
                {
                    cfg.Regions.Add("Public fields and properties");
                    cfg.Regions.Add("Private fields");
                    cfg.Regions.Add("Ports");
                    cfg.AddProperty("string", "InstanceName", accessLevel: "public", defaultValue: "\"Default\"", region: "Public fields and properties", isAutoProperty: true);
                }
                else
                {
                    cfg.Regions.Add("Properties");
                    cfg.Regions.Add("Methods");
                }

                // Add usings
                cfg.Usings.Add("System.Windows");

                if (Layer == Enums.ALALayer.ProgrammingParadigms)
                {
                    cfg.Usings.Add($"{NamespacePrefix}Libraries");
                }
                else if (Layer == Enums.ALALayer.DomainAbstractions)
                {
                    cfg.Usings.Add($"{NamespacePrefix}Libraries");
                    cfg.Usings.Add($"{NamespacePrefix}ProgrammingParadigms");
                }
                else if (Layer == Enums.ALALayer.Application)
                {
                    cfg.Usings.Add($"{NamespacePrefix}Libraries");
                    cfg.Usings.Add($"{NamespacePrefix}ProgrammingParadigms");
                    cfg.Usings.Add($"{NamespacePrefix}DomainAbstractions");
                }

                List <string> description = new List <string> {
                    ""
                };
                int portCounter = 1;

                if (!(Layer == Enums.ALALayer.ProgrammingParadigms))
                {
                    if (Layer == Enums.ALALayer.Application)
                    {
                        cfg.Regions.Add("Input instances");
                        cfg.Regions.Add("Output instances");
                    }
                    ;

                    description.Add("Ports:");

                    // Create implementation stubs
                    foreach (var implementedPort in ImplementedPorts)
                    {
                        var type = implementedPort.Split()[0];
                        cfg.Regions.Add($"{type} implementation");
                        AddSupportedPortDetails(cfg, implementedPort, isImplemented: true);

                        description.Add($"{portCounter}. {implementedPort.Replace("<", "&lt;").Replace(">", "&gt;")}:");
                        portCounter++;
                    }

                    foreach (var providedPort in ProvidedPorts)
                    {
                        var split = providedPort.Split();
                        if (split.Length < 2)
                        {
                            continue;
                        }

                        var type = split[0];
                        var name = split[1];

                        if (type.StartsWith("List<"))
                        {
                            cfg.AddField(type, name, accessLevel: "private", region: "Ports", defaultValue: $"new {type}()");
                        }
                        else
                        {
                            cfg.AddField(type, name, accessLevel: "private", region: "Ports");
                        }

                        description.Add($"{portCounter}. {providedPort.Replace("<", "&lt;").Replace(">", "&gt;")}:");
                        portCounter++;

                        AddSupportedPortDetails(cfg, providedPort, isImplemented: false);
                    }
                }

                cfg.Description = description;

                if (Layer == Enums.ALALayer.Application)
                {
                    // Add landmarks for wiring code insertion
                    List <string> constructorBody = new List <string>();
                    constructorBody.Add($"// BEGIN AUTO-GENERATED INSTANTIATIONS FOR {ClassName}.xmind");
                    constructorBody.Add($"// END AUTO-GENERATED INSTANTIATIONS FOR {ClassName}.xmind");
                    constructorBody.Add($"");

                    constructorBody.Add($"// BEGIN AUTO-GENERATED WIRING FOR {ClassName}.xmind");
                    constructorBody.Add($"// END AUTO-GENERATED WIRING FOR {ClassName}.xmind");
                    constructorBody.Add($"");

                    constructorBody.Add($"// BEGIN MANUAL INSTANTIATIONS FOR {ClassName}.xmind");
                    constructorBody.Add($"// END MANUAL INSTANTIATIONS FOR {ClassName}.xmind");
                    constructorBody.Add($"");

                    constructorBody.Add($"// BEGIN MANUAL WIRING FOR {ClassName}.xmind");
                    constructorBody.Add($"// END MANUAL WIRING FOR {ClassName}.xmind");

                    cfg.ConstructorBody = constructorBody;

                    // Add PostWiringInitialize
                    List <string> postWiringInitializeBody = new List <string>();
                    postWiringInitializeBody.Add("// Mapping to virtual ports");
                    // postWiringInitializeBody.Add("// Utilities.ConnectToVirtualPort(outputInstance, \"portOnOutputInstance\", portInStoryAbstraction);");
                    // postWiringInitializeBody.Add("");

                    foreach (var providedPort in ProvidedPorts)
                    {
                        var type = providedPort.Split()[0];
                        var name = providedPort.Split()[1];

                        // Connector should be an Apply<type, type>
                        if (type.StartsWith("IDataFlow") && !type.StartsWith("IDataFlowB"))
                        {
                            // postWiringInitializeBody.Add($"Utilities.ConnectToVirtualPort({name}Connector, \"output\", {name});");
                            postWiringInitializeBody.Add($"if ({name} != null) {name}Connector.WireTo({name}, \"output\");");
                        }
                        else if (type.StartsWith("IEvent") && !type.StartsWith("IEventB"))
                        {
                            // postWiringInitializeBody.Add($"Utilities.ConnectToVirtualPort({name}Connector, \"complete\", {name});");
                            postWiringInitializeBody.Add($"if ({name} != null) {name}Connector.WireTo({name}, \"complete\");");
                        }
                    }
                    postWiringInitializeBody.Add("");

                    postWiringInitializeBody.Add("// IDataFlowB and IEventB event handlers");
                    // postWiringInitializeBody.Add("// if (inputDataFlowBPort != null)");
                    // postWiringInitializeBody.Add("// {");
                    // postWiringInitializeBody.Add("//     inputDataFlowBPort.DataChanged += () => (inputInstance as IDataFlow<T>).Data = inputDataFlowBPort.Data;");
                    // postWiringInitializeBody.Add("// }");
                    foreach (var providedPort in ProvidedPorts)
                    {
                        var type = providedPort.Split()[0];
                        var name = providedPort.Split()[1];

                        // Connector should be an Apply<type, type>
                        if (type.StartsWith("IDataFlowB"))
                        {
                            postWiringInitializeBody.Add($"if ({name} != null)");
                            postWiringInitializeBody.Add($"{{");
                            postWiringInitializeBody.Add($"    {name}.DataChanged += () => ({name}Connector as IDataFlow<T>).Data = {name}.Data;");
                            postWiringInitializeBody.Add($"}}");
                            postWiringInitializeBody.Add("");
                        }
                        else if (type.StartsWith("IEventB"))
                        {
                            postWiringInitializeBody.Add($"if ({name} != null)");
                            postWiringInitializeBody.Add($"{{");
                            postWiringInitializeBody.Add($"    {name}.EventHappened += () => ({name}Connector as IEvent).Execute();");
                            postWiringInitializeBody.Add($"}}");
                            postWiringInitializeBody.Add("");
                        }
                    }

                    postWiringInitializeBody.Add("// Send out initial values");
                    postWiringInitializeBody.Add("// (instanceNeedingInitialValue as IDataFlow<T>).Data = defaultValue;");

                    cfg.Regions.Add("PostWiringInitialize");
                    cfg.AddMethod("PostWiringInitialize", accessLevel: "private", methodBody: postWiringInitializeBody, region: "PostWiringInitialize");
                }

                var classFileTemplateContents = cfg.BuildFile();

                if (WriteFile && Directory.Exists(Path.GetDirectoryName(FilePath)))
                {
                    var classNameWithoutTypes = GetClassNameWithoutTypes(ClassName);

                    File.WriteAllText(Path.Combine(FilePath, $"{classNameWithoutTypes}.cs"), classFileTemplateContents);

                    if (Layer == Enums.ALALayer.Application && File.Exists(Path.Combine(FilePath, $"baseStoryAbstraction.xmind")))
                    {
                        // Create xmind diagram
                        File.Copy(Path.Combine(FilePath, $"baseStoryAbstraction.xmind"), Path.Combine(FilePath, $"{classNameWithoutTypes}.xmind"));
                    }
                }

                if (fileContentsOutput != null)
                {
                    fileContentsOutput.Data = classFileTemplateContents;
                }
            }
            catch (Exception e)
            {
            }
        }