using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IronPython.Hosting;
using IronPython.Runtime;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Diagnostics;


namespace IronPythonShell
{
    class Program
    {
        static void Main(string[] args)
        {            
            PermissionSet pset = new PermissionSet(PermissionState.None);
            pset.AddPermission(new SecurityPermission(PermissionState.Unrestricted));
            pset.AddPermission(new ReflectionPermission(PermissionState.Unrestricted));
            pset.AddPermission(new FileIOPermission(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, AppDomain.CurrentDomain.BaseDirectory));
            AppDomainSetup domainSetup = new AppDomainSetup();
            domainSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;

            // create the sandboxed domain
            AppDomain sandbox = AppDomain.CreateDomain(
                "Sandboxed Domain",
                AppDomain.CurrentDomain.Evidence,
                domainSetup,
                pset,
                CreateStrongName(Assembly.GetExecutingAssembly()),
                CreateStrongName(Assembly.GetAssembly(typeof(ScriptRuntime))),
                CreateStrongName(Assembly.GetAssembly(typeof(IronPython.Modules.PythonGC))),
                CreateStrongName(Assembly.GetAssembly(typeof(PythonEngine))),
                CreateStrongName(Assembly.GetAssembly(typeof(System.Scripting.ScriptCode))));


            StringBuilder script = new StringBuilder();            
            script.AppendLine("import Artifact");
            script.AppendLine("i = 200");
            script.AppendLine("while i > 0:	i = i - 1");
            script.AppendLine("print \"Done in the second verse. Yes?\"");
            script.AppendLine("print Artifact.Name");
            script.AppendLine("Artifact.SetName(\"Tool\")");
            script.AppendLine("print Artifact.Name");

            try
            {
                ScriptRuntime runtime = ScriptRuntime.Create(sandbox);                
                runtime.Globals.SetVariable("Artifact", new ScriptableItem("Dude"));
                ScriptEngine engine = runtime.GetEngineByFileExtension("py");
                ScriptScope scope = engine.CreateScope();
                
                ScriptSource source = engine.CreateScriptSourceFromString(script.ToString(), System.Scripting.SourceCodeKind.Statements);
                source.Execute(scope);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

            Console.ReadKey();
        }

        /// <summary>
        /// Create a StrongName that matches a specific assembly
        /// </summary>
        /// <exception cref="ArgumentNullException">
        /// if <paramref name="assembly"/> is null
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// if <paramref name="assembly"/> does not represent a strongly named assembly
        /// </exception>
        /// <param name="assembly">Assembly to create a StrongName for</param>
        /// <returns>A StrongName that matches the given assembly</returns>
        public static StrongName CreateStrongName(Assembly assembly)
        {
            if (assembly == null)
                throw new ArgumentNullException("assembly");

            AssemblyName assemblyName = assembly.GetName();
            Debug.Assert(assemblyName != null, "Could not get assembly name");

            // get the public key blob
            byte[] publicKey = assemblyName.GetPublicKey();
            if (publicKey == null || publicKey.Length == 0)
                throw new InvalidOperationException("Assembly is not strongly named");

            StrongNamePublicKeyBlob keyBlob = new StrongNamePublicKeyBlob(publicKey);

            // and create the StrongName
            return new StrongName(keyBlob, assemblyName.Name, assemblyName.Version);
        }
    }

    [EnvironmentPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
    public class ScriptableItem : MarshalByRefObject
    {

        public string Name { get; set; }

        public void SetName(string name)
        {
            Name = name;
        }

        public ScriptableItem(string name)
        {
            Name = name;
        }

    }
}
