﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace Infodinamica.Framework.Repository
{
    /// <summary>
    /// Interfaz que contiene métodos para ser aplicados sobre motores persistentes de datos
    /// </summary>
    /// <typeparam name="T">Tipo de dato</typeparam>
    public interface IRepository<T> : IDisposable where T : class
    {
        /// <summary>
        /// Guarda en el estado que el objeto debe ser agregado en el motor de persistencia
        /// </summary>
        /// <param name="entity">Objeto a guardar</param>
        void Add(T entity);

        /// <summary>
        /// Guarda en el estado de cada uno de los elementos que debe ser agregado al motor de persistencia
        /// </summary>
        /// <param name="entities">Listado de objetos a guardar</param>
        void Add(IEnumerable<T> entities);
        
        /// <summary>
        /// Guarda en el estado que el objeto debe ser actualizado en el motor de persistencia
        /// </summary>
        /// <param name="entity">Objeto a actualizar</param>
        void Update(T entity);
        
        /// <summary>
        /// Guarda en el estado de cada uno de los elementos que debe ser actualizado al motor de persistencia
        /// </summary>
        /// <param name="entities">Listado de objetos a actualizar</param>
        void Update(IEnumerable<T> entities);

        /// <summary>
        /// Guarda en el estado que el objeto debe ser eliminado en el motor de persistencia
        /// </summary>
        /// <param name="entity">Objeto a eliminar</param>
        void Delete(T entity);

        /// <summary>
        ///  Guarda en el estado de cada uno de los elementos que debe ser eliminado del motor de persistencia
        /// </summary>
        /// <param name="entities">Listado de objetos a eliminar</param>
        void Delete(IEnumerable<T> entities);

        /// <summary>
        /// Guarda los cambios solicitados en las operaciones Add, Update, Delete
        /// </summary>
        void SaveChanges();

        /// <summary>
        /// Obtiene un IQueryable para hacer consultas de los elementos almacenados en el motor de persistencia
        /// </summary>
        /// <returns></returns>
        IQueryable<T> GetQueryable();

        /// <summary>
        /// Cambia el tipo de dato de la consulta
        /// </summary>
        /// <typeparam name="TNewEntity">Tipo de dato almacenado en el motor de persistencia</typeparam>
        /// <returns>IQueryable del nuevo tipo de datos especificado</returns>
        IQueryable<TNewEntity> ChangeEntity<TNewEntity>() where TNewEntity : class;

        /// <summary>
        /// Cambia el contexto del repositorio
        /// </summary>
        /// <typeparam name="TNewEntity">Tipo de dato almacenado en el motor de persistencia</typeparam>
        /// <returns>IRepository del nuevo tipo de datos especificado</returns>
        IRepository<TNewEntity> ChangeRepository<TNewEntity>() where TNewEntity : class;

        /// <summary>
        /// Obtiene una colección de objetos hijos filtrados
        /// </summary>
        /// <typeparam name="TElement">Tipo de datos del hijo</typeparam>
        /// <param name="entity">Objeto padre</param>
        /// <param name="navigationProperty">Función de filtrado</param>
        /// <returns>Colección filtrada de los hijos del padre</returns>
        IQueryable<TElement> GetCollectionQueryable<TElement>(T entity, Expression<Func<T, ICollection<TElement>>> navigationProperty) where TElement : class;

        /// <summary>
        /// Obtiene una transacción, la cual debe ser controlada en las capas superiores. No se provee de un método "Commit"
        /// </summary>
        /// <returns></returns>
        DbContextTransaction BeginTransaction();
    }
}
