// ToDo: Add tables datasource support, currently supports only queires
    public CodeGenerationSection GenerateListForm(StoreForm form, StoreCodeGeneratorContext ctx)
    {
        var result = new CodeGenerationSection()
        {
            FileName = form.Name + ".cs"
        };
        var sb         = new StringBuilder();
        var schema     = ctx.Schemas[form.Schema];
        var dataSource = form.Datasource.Replace(ObjectBuilderConstants.DS_QUERY_START, "");
        var query      = ctx.Queries[dataSource];
        var usingList  = new List <string>();

        usingList.Add(schema.Namespace);
        usingList.Add(query.Namespace);
        usingList = usingList.Distinct().ToList();

        sb.AppendLine(@$ "using Platz.SqlForms;");

        foreach (var u in usingList)
        {
            sb.AppendLine(@$ "using {u};");
        }

        sb.AppendLine();
        sb.AppendLine(@$ "namespace {form.Namespace};");

        sb.Append(@$ "
        private StoreCodeGeneratorContext GetCodeGenerationContext()
        {
            var ctx = new StoreCodeGeneratorContext();

            // ToDo: we implement code generation of the fly - all changes made but not save should be reflected
            // ToDo: schemas should be taken from current model changes, for now we take originals
            ctx.Schemas = Model.Schemas.ToDictionary(m => m.Schema.Name, m => m.Schema);
            ctx.Queries = Model.Queries.ToDictionary(m => m.Query.Name, m => m.Query);

            // forms on the fly generation reflecting not saved changes
            ctx.Forms = new Dictionary <string, StoreForm>();
            ValidationResult.Clear();

            foreach (var formDetails in Model.Forms)
            {
                StoreForm storeForm = formDetails.Form;
                var       formModel = (formDetails)?.Model;

                if (formModel != null)
                {
                    var formsValidations = _formBuilderController.Validate(formModel);
                    formModel.Validated = !formsValidations.Any(v => v.Type == ValidationResultTypes.Error);

                    if (formModel.Validated)
                    {
                        // use changes if pass validation
                        storeForm = formModel.ToStore();
                    }
                    else
                    {
                        // validation failed - use original form
                        var formItems = formsValidations.Select(r => new ValidationOutputItem(r, ValidationLocationType.Form)).ToList();
                        ValidationResult.AddRange(formItems);
                    }
                }

                ctx.Forms[storeForm.Name] = storeForm;
            }

            return(ctx);
        }
    //private readonly IProjectLoader _loader;

    //public FormCodeGenerator(IProjectLoader projectLoader)
    //{
    //    _loader = projectLoader;
    //}
    public CodeGenerationSection GenerateListFormRazorPage(StoreForm form, StoreCodeGeneratorContext ctx)
    {
        var result = new CodeGenerationSection()
        {
            FileName = form.Name + ".razor.cs"
        };
        var sb    = new StringBuilder();
        var psb   = new StringBuilder();
        var fpsb  = new StringBuilder();
        var comma = "";

        foreach (var p in form.PageParameters)
        {
            string pt = "";

            switch (p.DataType)
            {
            case "int":
                pt = ":int";
                break;
            }

            psb.Append($"/{{{p.Name}{pt}}}");
            fpsb.Append($"{comma}{p.Name}");
            comma = ", ";
        }

        sb.AppendLine(@$ "@page " "/{form.RoutingPath}{psb.ToString()}" "");

        sb.AppendLine(@$ "@using Platz.SqlForms");

        sb.AppendLine(@$ "@using {form.Namespace}");
        sb.AppendLine();

        if (!string.IsNullOrWhiteSpace(form.Caption))
        {
            sb.AppendLine(@$ "<h1>{form.Caption}</h1>");
            sb.AppendLine();
        }

        // Header
        if (!string.IsNullOrWhiteSpace(form.PageHeaderForm))
        {
            var readOnly = "";

            if (form.PageHeaderFormReadOnly)
            {
                readOnly = @"ReadOnly=""true"" ";
            }

            sb.AppendLine($@"<FormDynamicEditComponent TForm=""{form.PageHeaderForm}"" FormParameters=""GetHeaderParameters()"" {readOnly}/> ");
        }

        var serviceParams = string.Join(", ", form.PageParameters.Select(p => p.Name));

        sb.AppendLine($@"<FormDataServiceListComponent TForm=""{form.Name}"" ServiceParameters=""@(new object[] {{ {serviceParams} }})"" /> ");

        sb.AppendLine(@"
@code {");

        foreach (var p in form.PageParameters)
        {
            sb.AppendLine(@$ "    [Parameter]");
            sb.AppendLine(@$ "    public {p.DataType} {p.Name} {{ get; set; }}");
        }

        // Header Parameters
        if (!string.IsNullOrWhiteSpace(form.PageHeaderForm))
        {
            sb.AppendLine();
            sb.AppendLine($@"    private FormParameter[] GetHeaderParameters()");
            sb.AppendLine($@"    {{");
            sb.AppendLine($@"        return new FormParameter[]");
            sb.AppendLine($@"        {{");

            var headerForm = ctx.Forms[form.PageHeaderForm];

            foreach (var headerParameter in headerForm.PageParameters)
            {
                var parameter = form.PageParameters.First(p => p.HeaderFormParameterMapping == headerParameter.Name);
                sb.AppendLine(@$ "           new FormParameter(" "{parameter.Name}" ", {parameter.Name}),");
            }

            sb.AppendLine($@"        }}");
            sb.AppendLine($@"    }}");
        }

        sb.AppendLine(@"}");

        result.Code = sb.ToString();
        return(result);
    }