<#@ template language="C#" HostSpecific="True"  inherits="DynamicTransform" #>
<#@ Output Extension="cs" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="EnvDTE" #>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
<# if(!string.IsNullOrEmpty(Model.ModelTypeNamespace)) { #>
using <#= Model.ModelTypeNamespace #>;
<# } #>
<# if((!string.IsNullOrEmpty(Model.RepositoriesNamespace)) && (Model.RepositoriesNamespace != Model.ModelTypeNamespace)) { #>
using <#= Model.RepositoriesNamespace #>;
<# } #>

namespace <#= Model.ControllerNamespace #>
{   
<#  
	var modelType = (CodeType)Model.ModelType; 
	var modelName = modelType.Name; 
	var modelNamePlural = Model.ModelTypePluralized; 
	var modelVariable = modelName.ToLower(); 
	var relatedEntities = ((IEnumerable)Model.RelatedEntities).OfType<RelatedEntityInfo>();
	var primaryKeyProperty = modelType.VisibleMembers().OfType<CodeProperty>().Single(x => x.Name == Model.PrimaryKey);
	var routingName = Regex.Replace(Model.ControllerName, "Controller$", "", RegexOptions.IgnoreCase);
#>
    public class <#= Model.ControllerName #> : Controller
    {
<# foreach(var repository in Repositories.Values) { #>
		private readonly I<#= repository.RepositoryTypeName #> <#= repository.VariableName #>;
<# } #>

		// If you are using Dependency Injection, you can delete the following constructor
        public <#= Model.ControllerName #>() : this(<#= String.Join(", ", Repositories.Values.Select(x => "new " + x.RepositoryTypeName + "()")) #>)
        {
        }

        public <#= Model.ControllerName #>(<#= String.Join(", ", Repositories.Values.Select(x => "I" + x.RepositoryTypeName + " " + x.VariableName)) #>)
        {
<# foreach(var repository in Repositories.Values) { #>
			this.<#= repository.VariableName #> = <#= repository.VariableName #>;
<# } #>
        }

        //
        // GET: /<#= routingName #>/

        public ViewResult Index()
        {
<#
	var propertiesToInclude = relatedEntities.Select(relation => relation.LazyLoadingProperty).Where(x => x != null);
	var includeExpression = String.Join(", ", propertiesToInclude.Select(x => String.Format("{0} => {0}.{1}", modelVariable, x.Name)));
	if (!string.IsNullOrEmpty(includeExpression)) {
		includeExpression = "Including(" + includeExpression + ")";
	}
#>
            return View(<#= Repositories[modelType.FullName].VariableName #>.All<#= includeExpression #>);
        }

        //
        // GET: /<#= routingName #>/Details/5

        public ViewResult Details(<#= primaryKeyProperty.Type.AsString #> id)
        {
            return View(<#= Repositories[modelType.FullName].VariableName #>.Find(id));
        }

        //
        // GET: /<#= routingName #>/Create

        public ActionResult Create()
        {
<# foreach(var relatedEntity in relatedEntities.Where(x => x.RelationType == RelationType.Parent)) { #>
			ViewBag.Possible<#= relatedEntity.RelationNamePlural #> = <#= Repositories[relatedEntity.RelatedEntityType.FullName].VariableName #>.All;
<# } #>
            return View();
        } 

        //
        // POST: /<#= routingName #>/Create

        [HttpPost]
        public ActionResult Create(<#= modelName #> <#= modelVariable #>)
        {
            if (ModelState.IsValid) {
                <#= Repositories[modelType.FullName].VariableName #>.InsertOrUpdate(<#= modelVariable #>);
                <#= Repositories[modelType.FullName].VariableName #>.Save();
                return RedirectToAction("Index");
            } else {
<# foreach(var relatedEntity in relatedEntities.Where(x => x.RelationType == RelationType.Parent)) { #>
				ViewBag.Possible<#= relatedEntity.RelationNamePlural #> = <#= Repositories[relatedEntity.RelatedEntityType.FullName].VariableName #>.All;
<# } #>
				return View();
			}
        }
        
        //
        // GET: /<#= routingName #>/Edit/5
 
        public ActionResult Edit(<#= primaryKeyProperty.Type.AsString #> id)
        {
<# foreach(var relatedEntity in relatedEntities.Where(x => x.RelationType == RelationType.Parent)) { #>
			ViewBag.Possible<#= relatedEntity.RelationNamePlural #> = <#= Repositories[relatedEntity.RelatedEntityType.FullName].VariableName #>.All;
<# } #>
             return View(<#= Repositories[modelType.FullName].VariableName #>.Find(id));
        }

        //
        // POST: /<#= routingName #>/Edit/5

        [HttpPost]
        public ActionResult Edit(<#= modelName #> <#= modelVariable #>)
        {
            if (ModelState.IsValid) {
                <#= Repositories[modelType.FullName].VariableName #>.InsertOrUpdate(<#= modelVariable #>);
                <#= Repositories[modelType.FullName].VariableName #>.Save();
                return RedirectToAction("Index");
            } else {
<# foreach(var relatedEntity in relatedEntities.Where(x => x.RelationType == RelationType.Parent)) { #>
				ViewBag.Possible<#= relatedEntity.RelationNamePlural #> = <#= Repositories[relatedEntity.RelatedEntityType.FullName].VariableName #>.All;
<# } #>
				return View();
			}
        }

        //
        // GET: /<#= routingName #>/Delete/5
 
        public ActionResult Delete(<#= primaryKeyProperty.Type.AsString #> id)
        {
            return View(<#= Repositories[modelType.FullName].VariableName #>.Find(id));
        }

        //
        // POST: /<#= routingName #>/Delete/5

        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(<#= primaryKeyProperty.Type.AsString #> id)
        {
            <#= Repositories[modelType.FullName].VariableName #>.Delete(id);
            <#= Repositories[modelType.FullName].VariableName #>.Save();

            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing) {
<# foreach(var repository in Repositories.Values) { #>
                <#= repository.VariableName #>.Dispose();
<# } #>
            }
            base.Dispose(disposing);
        }
    }
}

<#+
class RepositoryInfo {
    public string RepositoryTypeName { get; set; }
    public string VariableName { get; set; }
}

IDictionary<string, RepositoryInfo> _repositories;
IDictionary<string, RepositoryInfo> Repositories {
	get {
		if (_repositories == null) {
			var relatedEntities = ((IEnumerable)Model.RelatedEntities).OfType<RelatedEntityInfo>();
			var relatedTypes = relatedEntities.Where(x => x.RelationType == RelationType.Parent).Select(x => x.RelatedEntityType).Distinct();
			_repositories = relatedTypes.ToDictionary(
				relatedType => relatedType.FullName,
				relatedType => new RepositoryInfo { RepositoryTypeName = relatedType.Name + "Repository", VariableName = relatedType.Name.ToLower() + "Repository" }
			); 
			_repositories[((CodeType)Model.ModelType).FullName] = new RepositoryInfo { RepositoryTypeName = Model.Repository, VariableName = ((CodeType)Model.ModelType).Name.ToLower() + "Repository" };
		}
		return _repositories;
	}
}
#>