/*
* PhoneGap is available under *either* the terms of the modified BSD license *or* the
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2010-2011, Matt Lacey
* Copyright (c) 2005-2011, Nitobi Software Inc.
* Copyright (c) 2011, Microsoft Corporation
*/
using System;
using System.Diagnostics;
using System.Threading;
using Microsoft.Devices;
using Microsoft.Phone.Controls;
using WP7GapClassLib.PhoneGap.Commands;
namespace WP7GapClassLib.PhoneGap
{
///
/// Implements logic to execute native command and return result back.
/// All commands are executed asynchronous.
///
public class NativeExecution
{
///
/// Reference to web part where application is hosted
///
private readonly WebBrowser webBrowser;
///
/// Creates new instance of a NativeExecution class.
///
/// Reference to web part where application is hosted
public NativeExecution(ref WebBrowser browser)
{
if (browser == null)
{
throw new ArgumentNullException("browser");
}
this.webBrowser = browser;
}
///
/// Returns where application is running on emulator
///
/// True if running on emulator, otherwise False
public static bool IsRunningOnEmulator()
{
return Microsoft.Devices.Environment.DeviceType == DeviceType.Emulator;
}
///
/// Executes command and returns result back.
///
/// Command to execute
public void ProcessCommand(PhoneGapCommandCall commandCallParams)
{
if (commandCallParams == null)
{
throw new ArgumentNullException("commandCallParams");
}
try
{
BaseCommand bc = CommandFactory.CreateByServiceName(commandCallParams.Service);
if (bc == null)
{
this.OnCommandResult(commandCallParams.CallbackId, new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION));
return;
}
EventHandler OnCommandResultHandler = delegate(object o, PluginResult res)
{
this.OnCommandResult(commandCallParams.CallbackId, res);
};
bc.OnCommandResult += OnCommandResultHandler;
EventHandler OnCustomScriptHandler = delegate(object o, ScriptCallback script)
{
this.InvokeScriptCallback(script);
};
bc.OnCustomScript += OnCustomScriptHandler;
// TODO: alternative way is using thread pool (ThreadPool.QueueUserWorkItem) instead of
// new thread for every command call; but num threads are not sufficient - 2 threads per CPU core
Thread thread = new Thread(func =>
{
try
{
bc.InvokeMethodNamed(commandCallParams.Action, commandCallParams.Args);
}
catch (Exception)
{
bc.OnCommandResult -= OnCommandResultHandler;
bc.OnCustomScript -= OnCustomScriptHandler;
Debug.WriteLine("failed to InvokeMethodNamed :: " + commandCallParams.Action + " on Object :: " + commandCallParams.Service);
this.OnCommandResult(commandCallParams.CallbackId, new PluginResult(PluginResult.Status.INVALID_ACTION));
return;
}
});
thread.Start();
}
catch (Exception ex)
{
// ERROR
Debug.WriteLine(String.Format("Unable to execute command :: {0}:{1}:{3} ",
commandCallParams.Service, commandCallParams.Action, ex.Message));
this.OnCommandResult(commandCallParams.CallbackId, new PluginResult(PluginResult.Status.ERROR));
return;
}
}
///
/// Handles command execution result.
///
/// Command callback identifier on client side
/// Execution result
private void OnCommandResult(string callbackId, PluginResult result)
{
#region args checking
if (result == null)
{
Debug.WriteLine("OnCommandResult missing result argument");
return;
}
if (String.IsNullOrEmpty(callbackId))
{
Debug.WriteLine("OnCommandResult missing callbackId argument");
return;
}
#endregion
string status = ((int)result.Result).ToString();
string jsonResult = result.ToJSONString();
ScriptCallback scriptCallback = null;
if (String.IsNullOrEmpty(result.Cast))
{
scriptCallback = new ScriptCallback("PhoneGapCommandResult", new string[] { status, callbackId, jsonResult });
}
else
{
scriptCallback = new ScriptCallback("PhoneGapCommandResult", new string[] { status, callbackId, jsonResult, result.Cast });
}
this.InvokeScriptCallback(scriptCallback);
}
///
/// Executes client java script
///
/// Script to execute on client side
private void InvokeScriptCallback(ScriptCallback script)
{
if (script == null)
{
throw new ArgumentNullException("script");
}
if (String.IsNullOrEmpty(script.ScriptName))
{
throw new ArgumentNullException("ScriptName");
}
this.webBrowser.Dispatcher.BeginInvoke((ThreadStart)delegate()
{
try
{
this.webBrowser.InvokeScript(script.ScriptName, script.Args);
}
catch (Exception ex)
{
Debug.WriteLine("Exception in InvokeScriptCallback :: " + ex.Message);
}
});
}
}
}