using System;
using System.Collections.Generic;

namespace My.Ioc.Sample
{
public interface IConcurrency
{
int Code { get; }
}

public interface IConcurrencyService
{
string Name { get; }
void AddConcurrency(IConcurrency concurrency);
void RemoveConcurrency(IConcurrency concurrency);
}

public class ConcurrencyService : IConcurrencyService
{
readonly Dictionary<int, IConcurrency> _concurrencies = new Dictionary<int, IConcurrency>();

public string Name
{
get { return GetType().Name; }
}

public void AddConcurrency(IConcurrency concurrency)
{
_concurrencies.Add(concurrency.Code, concurrency);
}

public void RemoveConcurrency(IConcurrency concurrency)
{
_concurrencies.Remove(concurrency.Code);
}
}

public class NewConcurrencyService : IConcurrencyService
{
#region IConcurrencyService Members

public string Name
{
get { return GetType().Name; }
}

public void AddConcurrency(IConcurrency concurrency)
{
throw new NotImplementedException();
}

public void RemoveConcurrency(IConcurrency concurrency)
{
throw new NotImplementedException();
}

#endregion
}

public interface ISimpleConsumer
{
IConcurrencyService ConcurrencyService { get; }
}

public class SimpleConsumer : ISimpleConsumer
{
readonly IConcurrencyService _concurrencyService;

public SimpleConsumer(IConcurrencyService concurrencyService)
{
_concurrencyService = concurrencyService;
}

public IConcurrencyService ConcurrencyService
{
get { return _concurrencyService; }
}
}

public interface IComplexConsumer : IDisposable
{
IConcurrencyService ConcurrencyService { get; }
}

public class ComplexConsumer : IComplexConsumer
{
readonly string _name;
readonly IConcurrencyService _concurrencyService;

public ComplexConsumer(string name, IConcurrencyService concurrencyService)
{
_name = name;
_concurrencyService = concurrencyService;
}

public IConcurrencyService ConcurrencyService
{
get { return _concurrencyService; }
}

public string Name
{
get { return _name; }
}

public string Address { get; set; }

public void Print()
{
Console.WriteLine(_name + " who lives in " + (Address ?? "Fujian") + " is using the service " + _concurrencyService.Name);
}

public void Dispose()
{
Console.WriteLine("ComplexConsumer is disposing...");
}
}

class Program
{
static IObjectRegistration _concurrencyServiceRegistration;
static IObjectObserver<ISimpleConsumer> _simpleConsumerObserver;
static void Main(string[] args)
{
// First, we need to create an instance of IObjectContainer.
IObjectContainer container = new ObjectContainer(true);

// Then, we register some services
container.Register<IConcurrencyService, ConcurrencyService>()
.WhenParentTypeIsAny(typeof(SimpleConsumer), typeof(ComplexConsumer))
.In(Lifetime.Container())
.Set("ConcurrencyService")
.Return(out _concurrencyServiceRegistration);

container.Register<ISimpleConsumer, SimpleConsumer>();

var consumerName = Parameter.Positional("Johnny.Liu");
container.Register<IComplexConsumer, ComplexConsumer>()
.WithConstructor(consumerName)
.WithPropertyValue("Address", "Fujian")
.WithMethod("Print")
.In(Lifetime.Transient());

// Finally, don't forget to commit the registrations to the registry.
container.CommitRegistrations();

// Now you can ask the container to build instances for you.
var simpleConsumer1 = container.Resolve<ISimpleConsumer>();

if (!container.TryGetObserver(out _simpleConsumerObserver))
throw new Exception();
_simpleConsumerObserver.Changed += OnObjectBuilderChanged;
var simpleConsumer2 = container.Resolve(_simpleConsumerObserver);

using (var scope = container.BeginLifetimeScope())
{
var complexConsumer = scope.Resolve<IComplexConsumer>();
}

// At last, we will unregister the current concurrency service to let the other concurrency
// service implementations to have a chance to replace it.
container.Unregister(_concurrencyServiceRegistration);
container.Register(typeof(IConcurrencyService), typeof(NewConcurrencyService));
// As we said, don't forget to commit the registrations to the registry.
container.CommitRegistrations();

using (var scope = container.BeginLifetimeScope())
{
var complexConsumer = scope.Resolve<IComplexConsumer>();
}

Console.ReadLine();
}

static void OnObjectBuilderChanged(ObjectBuilderChangedEventArgs args)
{
Console.WriteLine(args.ChangeMode);
}
}
}