/*
* Copyright © 2011, Petro Protsyk, Denys Vuika
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace Scripting.SSharp.Runtime.Promotion
{
///
/// Represents implementation of Expando object via IScriptable interface.
/// By default Expando objects created with a following syntax construct:
/// [name->valueExpression, name->valueExpression];
/// This default type may be overriden by ScriptableObjectType option
/// in script configuration.
///
public class Expando : IScriptable, ISupportAssign
{
#region Fields
readonly Dictionary _fields = new Dictionary();
#endregion
#region Public Members
public IEnumerable Fields
{
get
{
return _fields.Keys;
}
}
public void AssignTo(object target)
{
var scope = target as IScriptScope;
if (scope != null)
{
foreach (string field in Fields)
scope.SetItem(field, _fields[field]);
return;
}
foreach (string field in Fields)
{
IMemberBinding bind = RuntimeHost.Binder.BindToMember(target, field, false);
if (bind != null)
bind.SetValue(_fields[field]);
//RuntimeHost.Binder.Set(field, target, fields[field], false);
}
}
public object this[string fieldName]
{
get
{
object result;
if (_fields.TryGetValue(fieldName, out result)) return result;
return null;
}
}
public override string ToString()
{
bool first = true;
var builder = new StringBuilder("[");
foreach (var field in Fields)
{
if (!first) builder.Append(','); else first = false;
builder.Append(field);
builder.Append("->");
var value = this[field];
builder.Append(value == null ? "null" : value.ToString());
}
builder.Append("]");
return builder.ToString();
}
#endregion
#region IScriptable
[Promote(false)]
public virtual object Instance
{
get { return this; }
}
[Promote(false)]
public virtual IMemberBinding GetMember(string name, params object[] arguments)
{
if (arguments != null && arguments.Length != 0) return null;
return new ExpandoBind(this, name);
}
[Promote(false)]
public virtual IBinding GetMethod(string name, params object[] arguments)
{
if (arguments != null && arguments.Length != 0) return null;
if (!_fields.ContainsKey(name)) throw new ScriptMethodNotFoundException(name);
return new ExpandoBind(this, name);
}
#endregion
#region ExpandoBind
protected class ExpandoBind : IMemberBinding
{
private readonly Expando _expando;
private readonly string _name;
public ExpandoBind(Expando expando, string name)
{
_expando = expando;
_name = name;
}
#region IMemberBind
public object Target
{
get { return _expando; }
}
public Type TargetType
{
get { return typeof(object); }
}
public System.Reflection.MemberInfo Member
{
get { throw new NotSupportedException(); }
}
public void SetValue(object value)
{
if (_expando._fields.ContainsKey(_name))
{
_expando._fields[_name] = value;
}
else
{
_expando._fields.Add(_name, value);
}
}
public object GetValue()
{
object result;
if (_expando._fields.TryGetValue(_name, out result))
return result;
throw new ScriptIdNotFoundException(_name);
}
public void AddHandler(object value)
{
throw new NotSupportedException();
}
public void RemoveHandler(object value)
{
throw new NotSupportedException();
}
#endregion
#region IInvokable
public bool CanInvoke()
{
return true;
}
public object Invoke(IScriptContext context, object[] args)
{
var method = GetValue() as IInvokable;
if (method != null)
return method.Invoke(context, args);
throw new ScriptIdNotFoundException(string.Format(Strings.MethodNotFound, _name));
}
#endregion
}
#endregion
}
}