internal InterfaceDeclaration( string key, InterfaceDeclaration otherInterfaceDeclaration )
        {
            Contract.Requires( !string.IsNullOrEmpty( key ) );
            Contract.Requires( otherInterfaceDeclaration != null );

            this.key = key;
            typeName = key + otherInterfaceDeclaration.DeclaredInterface.TypeArgumentList.ToString();
            definingClass = otherInterfaceDeclaration.definingClass;
            declaredInterface = otherInterfaceDeclaration.declaredInterface;
        }
        private static bool WriteUnitOfWork( IndentingTextWriter writer, InterfaceDeclaration declaration, ICollection<string> implementedInterfaces )
        {
            Contract.Requires( writer != null );
            Contract.Requires( declaration != null );
            Contract.Requires( implementedInterfaces != null );

            if ( implementedInterfaces.Contains( declaration.TypeName ) )
                return false;

            implementedInterfaces.Add( declaration.TypeName );

            writer.WriteLine( "bool {0}.HasPendingChanges", declaration.TypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "get" );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "return ChangeTracker.HasChanges();" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "void {0}.RegisterNew( {1} item )", declaration.TypeName, declaration.ArgumentTypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "Set<{0}>().Add( item );", declaration.ArgumentTypeName );
            writer.WriteLine( "OnPropertyChanged( new PropertyChangedEventArgs( \"HasPendingChanges\" ) );" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "void {0}.RegisterRemoved( {1} item )", declaration.TypeName, declaration.ArgumentTypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "Set<{0}>().Remove( item );", declaration.ArgumentTypeName );
            writer.WriteLine( "OnPropertyChanged( new PropertyChangedEventArgs( \"HasPendingChanges\" ) );" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "void {0}.RegisterChanged( {1} item )", declaration.TypeName, declaration.ArgumentTypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "if ( Entry( item ).State != EntityState.Detached )" );
            writer.Indent();
            writer.WriteLine( "return;" );
            writer.Unindent();
            writer.WriteLine();
            writer.WriteLine( "Set<{0}>().Attach( item );", declaration.ArgumentTypeName );
            writer.WriteLine( "Entry( item ).State = EntityState.Modified;" );
            writer.WriteLine( "OnPropertyChanged( new PropertyChangedEventArgs( \"HasPendingChanges\" ) );" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "void {0}.Unregister( {1} item )", declaration.TypeName, declaration.ArgumentTypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "Entry( item ).State = EntityState.Detached;" );
            writer.WriteLine( "OnPropertyChanged( new PropertyChangedEventArgs( \"HasPendingChanges\" ) );" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "void {0}.Rollback()", declaration.TypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "foreach ( var entry in ChangeTracker.Entries<{0}>() )", declaration.ArgumentTypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "switch ( entry.State )" );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "case EntityState.Modified:" );
            writer.WriteLine( "case EntityState.Deleted:" );
            writer.Indent();
            writer.WriteLine( "entry.CurrentValues.SetValues( entry.OriginalValues );" );
            writer.WriteLine( "entry.State = EntityState.Unchanged;" );
            writer.WriteLine( "break;" );
            writer.Unindent();
            writer.WriteLine( "case EntityState.Added:" );
            writer.Indent();
            writer.WriteLine( "entry.State = EntityState.Detached;" );
            writer.WriteLine( "break;" );
            writer.Unindent();
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "OnPropertyChanged( new PropertyChangedEventArgs( \"HasPendingChanges\" ) );" );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "async Task {0}.CommitAsync( CancellationToken cancellationToken )", declaration.TypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "await SaveChangesAsync( cancellationToken ).ConfigureAwait( false );" );
            writer.WriteLine( "OnPropertyChanged( new PropertyChangedEventArgs( \"HasPendingChanges\" ) );" );
            writer.Unindent();
            writer.WriteLine( "}" );

            return true;
        }
        private static bool WriteReadOnlyRepository( IndentingTextWriter writer, InterfaceDeclaration declaration, ICollection<string> implementedInterfaces )
        {
            Contract.Requires( writer != null );
            Contract.Requires( implementedInterfaces != null );

            if ( implementedInterfaces.Contains( declaration.TypeName ) )
                return false;

            implementedInterfaces.Add( declaration.TypeName );

            writer.WriteLine( "async Task<IEnumerable<{1}>> {0}.GetAsync( Func<IQueryable<{1}>, IQueryable<{1}>> queryShaper, CancellationToken cancellationToken )", declaration.TypeName, declaration.ArgumentTypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "return await queryShaper( Set<{0}>() ).ToArrayAsync( cancellationToken ).ConfigureAwait( false );", declaration.ArgumentTypeName );
            writer.Unindent();
            writer.WriteLine( "}" );
            writer.WriteLine();
            writer.WriteLine( "async Task<TResult> {0}.GetAsync<TResult>( Func<IQueryable<{1}>, TResult> queryShaper, CancellationToken cancellationToken )", declaration.TypeName, declaration.ArgumentTypeName );
            writer.WriteLine( "{" );
            writer.Indent();
            writer.WriteLine( "return await Task<TResult>.Factory.StartNew( () => queryShaper( Set<{0}>() ), cancellationToken ).ConfigureAwait( false );", declaration.ArgumentTypeName );
            writer.Unindent();
            writer.WriteLine( "}" );

            return true;
        }
        private static void ImplementInterface( IndentingTextWriter writer, InterfaceDeclaration declaration, ICollection<string> implementedInterfaces )
        {
            Contract.Requires( writer != null );
            Contract.Requires( declaration != null );
            Contract.Requires( implementedInterfaces != null );

            switch ( declaration.Key )
            {
                case IReadOnlyRepository:
                    WriteReadOnlyRepository( writer, declaration, implementedInterfaces );
                    break;
                case IRepository:
                    var inheritedDeclaration = new InterfaceDeclaration( IReadOnlyRepository, declaration );

                    if ( WritePropertyChangedImplementation( writer, implementedInterfaces ) )
                        writer.WriteLine();

                    if ( WriteReadOnlyRepository( writer, inheritedDeclaration, implementedInterfaces ) )
                        writer.WriteLine();

                    WriteRepository( writer, declaration, implementedInterfaces );
                    break;
                case IUnitOfWork:
                    if ( WritePropertyChangedImplementation( writer, implementedInterfaces ) )
                        writer.WriteLine();

                    WriteUnitOfWork( writer, declaration, implementedInterfaces );
                    break;
            }
        }