/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 *
 * ***************************************************************************/

#if !SILVERLIGHT // Remoting

using System;
using System.Diagnostics;
using System.Runtime.Remoting;
using System.Threading;

namespace Microsoft.Scripting.Hosting.Shell.Remote {
    /// <summary>
    /// Customize the CommandLine for remote scenarios
    /// </summary>
    public class RemoteConsoleCommandLine : CommandLine {
        private RemoteConsoleCommandDispatcher _remoteConsoleCommandDispatcher;

        public RemoteConsoleCommandLine(ScriptScope scope, RemoteCommandDispatcher remoteCommandDispatcher, AutoResetEvent remoteOutputReceived) {
            _remoteConsoleCommandDispatcher = new RemoteConsoleCommandDispatcher(remoteCommandDispatcher, remoteOutputReceived);
            Debug.Assert(scope != null);
            ScriptScope = scope;
        }

        protected override ICommandDispatcher CreateCommandDispatcher() {
            return _remoteConsoleCommandDispatcher;
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        internal void UnhandledExceptionWorker(Exception e) {
            try {
                base.UnhandledException(e);
            } catch (Exception exceptionDuringHandling) {
                // All bets are off while accessing the remote runtime. So we catch all exceptions.
                // However, in most cases, we only expect to see RemotingException here.
                if (!(exceptionDuringHandling is RemotingException)) {
                    Console.WriteLine(String.Format("({0} thrown while trying to display unhandled exception)", exceptionDuringHandling.GetType()), Style.Error);
                }

                // The remote server may have shutdown. So just do something simple
                Console.WriteLine(e.ToString(), Style.Error);
            }
        }

        protected override void UnhandledException(Exception e) {
            UnhandledExceptionWorker(e);
        }

        /// <summary>
        /// CommandDispatcher to ensure synchronize output from the remote runtime
        /// </summary>
        class RemoteConsoleCommandDispatcher : ICommandDispatcher {
            private RemoteCommandDispatcher _remoteCommandDispatcher;
            private AutoResetEvent _remoteOutputReceived;

            internal RemoteConsoleCommandDispatcher(RemoteCommandDispatcher remoteCommandDispatcher, AutoResetEvent remoteOutputReceived) {
                _remoteCommandDispatcher = remoteCommandDispatcher;
                _remoteOutputReceived = remoteOutputReceived;
            }

            public object Execute(CompiledCode compiledCode, ScriptScope scope) {
                // Delegate the operation to the RemoteCommandDispatcher which will execute the code in the remote runtime
                object result = _remoteCommandDispatcher.Execute(compiledCode, scope);

                // Output is received async, and so we need explicit synchronization in the remote console
                _remoteOutputReceived.WaitOne();

                return result;
            }
        }
    }
}

#endif