using NConcern;

using Newtonsoft.Json;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Reflection;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Activation;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Messaging;

using System.Runtime.Remoting.Proxies;

using System.Runtime.Remoting.Services;

using System.Text;

using System.Threading.Tasks;


namespace ConsoleApp2

{

  class Program

  {

    static void Main(string[] args)

    {

      TargetObject obj = new TargetObject("test");

      obj.Foo();

      obj.Bar();

      obj.Add(3, 2);

      obj.Vo();


    }

  }



  class MyProxy : RealProxy

  {

    private MarshalByRefObject target;


    public MyProxy(MarshalByRefObject target, Type serverType)

        : base(serverType)

    {

      this.target = target;

    }


    public override IMessage Invoke(IMessage msg)

    {

      IMessage retMsg = null;


      Console.WriteLine("PRE---------------------");


      if (msg is IConstructionCallMessage)

      {

        Console.WriteLine("  Constructor");


        // 객체 생성 메시지 처리

        IConstructionCallMessage ctorMsg = (IConstructionCallMessage)msg;

        RealProxy proxy = RemotingServices.GetRealProxy(target);

        // 실제 객체를 생성한다.

        proxy.InitializeServerObject(ctorMsg);

        // 객체 생성 결과를 ‘만들어’ 반환한다.

        retMsg = EnterpriseServicesHelper.CreateConstructionReturnMessage

            (ctorMsg, (MarshalByRefObject)this.GetTransparentProxy());

      }

      else if (msg is IMethodCallMessage)

      {

        IMethodCallMessage callMsg = (IMethodCallMessage)msg;

        Console.WriteLine("  method: {0}", callMsg.MethodName);

        for (int i = 0; i < callMsg.ArgCount; i++)

        {

          Console.WriteLine("      {0} | {1}: {2}", i, callMsg.GetArgName(i), callMsg.GetArg(i));

        }

        retMsg = RemotingServices.ExecuteMessage(target, callMsg);


        // 함수 결과값

        IMethodReturnMessage ret = (IMethodReturnMessage)retMsg;

        object obj = ret.ReturnValue;


        // object dumper 사용

        //var writer = new System.IO.StringWriter();

        //ObjectDumper.Dumper.Dump(obj, "test", writer);

        //Console.WriteLine("  함수 실행 결과값: {0}", writer.ToString());


        // json

        Console.WriteLine("  함수 실행 결과값: {0}", JsonConvert.SerializeObject(obj).ToString());


        //Console.WriteLine("  함수 실행 결과값: {0}", obj.ToString());

        //Console.WriteLine("  함수 실행 결과값: {0}", Convert.ToString(obj));


      }


      Console.WriteLine("POST---------------------");

      return retMsg;

    }


  }


  [AttributeUsage(AttributeTargets.Class)]

  class MyProxyAttribute : ProxyAttribute

  {

    public override MarshalByRefObject CreateInstance(Type serverType)

    {

      Console.WriteLine("CreateInstance");

      MarshalByRefObject target = base.CreateInstance(serverType);

      MyProxy proxy = new MyProxy(target, serverType);

      MarshalByRefObject obj = (MarshalByRefObject)proxy.GetTransparentProxy();

      return obj;

    }

  }


  [MyProxy]

  class TargetObject : ContextBoundObject

  {

    public TargetObject(string s)

    {

      Console.WriteLine("  constructor!!! " + s);

    }

    public void Foo()

    {

      Console.WriteLine("  foo() invoked !!!");

    }

    public void Bar()

    {

      Console.WriteLine("  bar() invoked !!!");

    } 

    public int Add(int a, int b)

    {

      Console.WriteLine("  add() invoked !!!");

      return a + b;

    }

    public VO Vo()

    {

      return new VO();

    }


  }


  class SubVO

  {

    public String A { get; set; } = "B11";

    public int B { get; set; } = 333;

    public bool C { get; set; } = true;

    public List<string> List { get; set; }

    public SubVO()

    {

      this.List = new List<string> { "a", "b" };


    }

  }

  class VO

  {

    public String A { get; set; } = "A11";

    public int B { get; set; } = 123;

    public bool C { get; set; } = false;

    public List<int> List { get; set; }

    public List<SubVO> SubList { get; set; }


    public VO()

    {

      this.List = new List<int> {1,2,3,4};

      this.SubList = new List<SubVO> { new SubVO(), new SubVO() };

    }

  }


}