<#@ Template Language="C#" HostSpecific="True" Inherits="DynamicTransform" #>
<#@ Output extension="cshtml" #>
<#@ assembly name="System.ComponentModel.DataAnnotations" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Data.Entity" #>
<#@ assembly name="System.Data.Linq" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.ComponentModel.DataAnnotations" #>
<#@ import namespace="System.Data.Linq.Mapping" #>
<#@ import namespace="System.Data.Objects.DataClasses" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
<# var viewDataType = (EnvDTE.CodeType) Model.ViewDataType; #>
<# bool WithOrder = (Model.WithOrder == "1"); #>
@using QuickForm
<# if(viewDataType != null) { #>
@model <#= viewDataType.FullName #>
<# } #>

@{
    QuickFormModel quickFormModel = (QuickFormModel)ViewBag.QuickFormModel;    
}

<# foreach (ModelProperty property in GetModelProperties(viewDataType, false).Where(x => x.IsPrimaryKey)) { #>
@if (quickFormModel.CurrentActionType == QuickFormActionType.Edit)
{       
	@Html.HiddenFor(model => model.<#= property.Name #>)
}
<# } #>

<#
foreach (ModelProperty property in GetModelProperties(Model.ViewDataType, false)) {
        if (!property.IsPrimaryKey && !property.IsForeignKey && !property.IsReadOnly) {
            if (WithOrder && property.Name.Trim().ToUpper() == "ORDER") {
#>
@Html.HiddenFor(model => model.<#= property.Name #>)
<# } else { #>
<tr>
	<td class="table-form-label-td">
		<div class="editor-label">
            @Html.LabelFor(model => model.<#= property.Name #>):
        </div>
	</td>

	<td>
        <div class="editor-field">
            @Html.EditorFor(model => model.<#= property.Name #>)
			@Html.ValidationMessageFor(model => model.<#= property.Name #>)
        </div>
	</td>
</tr>
<# 
    }
  }
}
#>
<#
foreach (RelatedEntityInfo relation in ParentRelations) {
#>
<tr>
	<td class="table-form-label-td">
		<div class="editor-label">
            @Html.LabelFor(model => model.<#= relation.RelationProperty.Name #>)
        </div>
	</td>

	<td>
        <div class="editor-field">
            <div class="col-md-8">
                @Html.DropDownListFor(model => model.<#= relation.RelationProperty.Name #>, null, QuickFormModel.EmptyListItem, new { @class = "form-control" })
            </div>
			@Html.ValidationMessageFor(model => model.<#= relation.RelationProperty.Name #>)
        </div>
	</td>
</tr>
<#
}
#>













<#+
// Describes the information about a property on the model
class ModelProperty {
    public string Name { get; set; }
    public string ValueExpression { get; set; }
	public EnvDTE.CodeTypeRef Type { get; set; }
    public bool IsPrimaryKey { get; set; }
	public bool IsForeignKey { get; set; }
	public bool IsReadOnly { get; set; }
}

// Change this list to include any non-primitive types you think should be eligible to be edited using a textbox
static Type[] bindableNonPrimitiveTypes = new[] {
    typeof(string),
    typeof(decimal),
    typeof(Guid),
    typeof(DateTime),
    typeof(DateTimeOffset),
    typeof(TimeSpan),
};

// Call this to get the list of properties in the model. Change this to modify or add your
// own default formatting for display values.
List<ModelProperty> GetModelProperties(EnvDTE.CodeType typeInfo, bool includeUnbindableProperties) {
    List<ModelProperty> results = GetEligibleProperties(typeInfo, includeUnbindableProperties);
    
    foreach (ModelProperty prop in results) {
        if (prop.Type.UnderlyingTypeIs<double>() || prop.Type.UnderlyingTypeIs<decimal>()) {
            prop.ValueExpression = "String.Format(\"{0:F}\", " + prop.ValueExpression + ")";
        }
        else if (prop.Type.UnderlyingTypeIs<DateTime>()) {
            prop.ValueExpression = "String.Format(\"{0:g}\", " + prop.ValueExpression + ")";
        }
		else if (!IsBindableType(prop.Type)) {
			prop.ValueExpression = GetValueExpression("Model." + prop.Name, (EnvDTE.CodeType)prop.Type.CodeType);
		}
    }

    return results;
}

// Change this list to include the names of properties that should be selected to represent an entity as a single string
static string[] displayPropertyNames = new[] { "Name", "Title", "LastName", "Surname", "Subject", "Count" };

string GetValueExpression(string propertyExpression, EnvDTE.CodeType propertyType) {
	if (propertyType != null) {
		var chosenSubproperty = propertyType.DisplayColumnProperty() ?? propertyType.FindProperty(displayPropertyNames);
		if (chosenSubproperty != null) {
			var toStringSuffix = chosenSubproperty.Type.AsFullName == "System.String" ? "" : ".ToString()";
			return String.Format("({0} == null ? \"None\" : {0}.{1}{2})", propertyExpression, chosenSubproperty.Name, toStringSuffix);
		}
	}
	return "Html.DisplayTextFor(_ => " + propertyExpression + ").ToString()";
}

// Helper
List<ModelProperty> GetEligibleProperties(EnvDTE.CodeType typeInfo, bool includeUnbindableProperties) {
    List<ModelProperty> results = new List<ModelProperty>();
	if (typeInfo != null) {
		foreach (var prop in typeInfo.VisibleMembers().OfType<EnvDTE.CodeProperty>()) {
			if (prop.IsReadable() && !prop.HasIndexParameters() && (includeUnbindableProperties || IsBindableType(prop.Type))) {
				results.Add(new ModelProperty {
					Name = prop.Name,
					ValueExpression = "Model." + prop.Name,
					Type = prop.Type,
					IsPrimaryKey = Model.PrimaryKeyName == prop.Name,
					IsForeignKey = ParentRelations.Any(x => x.RelationProperty == prop),
					IsReadOnly = !prop.IsWriteable()
				});
			}
		}
	}

    return results;
}

IEnumerable<RelatedEntityInfo> ParentRelations {
	get { return ((IEnumerable)Model.RelatedEntities).OfType<RelatedEntityInfo>().Where(x => x.RelationType == RelationType.Parent); }
}

// Helper
bool IsBindableType(EnvDTE.CodeTypeRef type) {
    return type.UnderlyingIsPrimitive() || bindableNonPrimitiveTypes.Any(x => type.UnderlyingTypeIs(x));
}
#>