//
// Copyright (c) CENS @ UCLA All rights reserved.
//
// Written by Taimur Hassan, Nicolai Munk Petersen
// Project to port Campaignr to WM 6
using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Threading;
using System.Data;
using System.Web;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Collections.Generic;
using Ucla.Cens.Campaignr.Library;
using Ucla.Cens.Campaignr.Location;
using Ucla.Cens.Campaignr.Messaging;
using Ucla.Cens.Campaignr.Library.Upload;
using Ucla.Cens.Campaignr.Library.Sensors;
using Ucla.Cens.Campaignr.Library.Upload.Modules;
using System.Runtime.InteropServices;
using System.Reflection;
using SimpleDOMParserCSharp;
namespace Ucla.Cens.Campaignr.MobApp
{
///
/// Main GUI
///
///
public class MainForm : System.Windows.Forms.Form
{
private enum OperationModes { Upload, CollectUpload, Collect };
private MenuItem campaignMenuItem;
private MainMenu mainMenu1;
private MenuItem exitMenuItem;
private MenuItem menuCollect;
private MenuItem menuCollectUpload;
private MenuItem menuUpload;
// Server url to send data
//private string _uploadServer = "";
// Timer delegate that points to the calling menu handler
//private Delegate _delegateMenus; // NMP: Waste
// Timer delegate for Status Textbox
private Delegate _delegateStatusUpdate;
// Timer delegate for Feedback Textbox
private Delegate _delegateFeedbackUpdate;
// Timer delegate for Upload Textbox
private Delegate _delegateUploadUpdate;
// The main sensor manager that takes care of data collection and upload to server
//private SensorDataManager _sensorDataManager;
private List manualSensorDataManagers = new List(1);
private List automaticSensorDataManagers = new List(1);
private FeedbackManager _feedbackManager;
// Points to procedure to thread
private TimerCallback _timerDelegate;
// Variable for upload monitoring
private System.Threading.Timer _uploadMonitorTimer;
// Transmit and sensors monitor frequency (ms)
private const int uploadMonitorInterval = 10000;
private const int uploadInterval = 10000;
// Lock object used for controlling access to multithreaded function resources
private object _lock = new object();
//private bool manual = false;
//private bool automatic = false;
//private UploadManager _uploadManager;
private string _campaignname = "";
private Boolean _uploadOnStart = true;
private Boolean _startOnLoad = false;
private Boolean _debugModeOn = false;
private Boolean _killUploadMonitor = false;
private MenuItem menuConfig;
private Label label1;
private Label status;
private Label upload;
private Panel loadingPanel;
private Label label2;
private ProgressBar progressBar1;
private bool _consoleMode = false;
private GraphicalInterface _graphicalInterface = null;
#region Public Delegates
// Delegate used to call MainForm functions from worker thread
public delegate void DelegateMenus(object sender, EventArgs args);
// Delegate used to call MainForm functions from worker thread
public delegate void DelegateStatusUpdate(Label ctrl, Object val);
// Delegate used to call MainForm functions from worker thread
public delegate void DelegateFeedbackUpdate(Label ctrl, Object val);
// Delegate used to call MainForm functions from worker thread
public delegate void DelegateUploadUpdate(Label ctrl, Object val);
#endregion
///
/// MainForm Constructor
///
public MainForm()
{
// First, make sure the user has accept the Terms and Conditions
string agreement = ConfigurationManager.AppSettings["UserAgreementStatus"];
if (agreement == null || agreement != "Accepted")
{
// Show Terms and Conditions dialog
UserAgreement ua = new UserAgreement();
if (ua.ShowDialog() == DialogResult.Yes)
{
ConfigurationManager.AppSettings["UserAgreementStatus"] = "Accepted";
ConfigurationManager.Save();
ua.Close();
}
else
{
// User did not agre
ConfigurationManager.AppSettings["UserAgreementStatus"] = "Declined";
ConfigurationManager.Save();
ua.Close();
this.Close();
return;
}
}
// Required for Windows Form Designer support
_delegateStatusUpdate = new DelegateStatusUpdate(StatusUpdate);
_delegateFeedbackUpdate = new DelegateFeedbackUpdate(FeedbackUpdate);
_delegateUploadUpdate = new DelegateUploadUpdate(UploadUpdate);
//_sensorDataManager = new SensorDataManager();
_feedbackManager = new FeedbackManager();
// Set the folder where campaignr will save the file (deprecated)
//_sensorDataManager.SaveFileFolder = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
InitializeComponent();
LoadConfiguration(true);
}
///
/// Clean up any resources being used.
///
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
this.mainMenu1 = new System.Windows.Forms.MainMenu();
this.campaignMenuItem = new System.Windows.Forms.MenuItem();
this.menuCollect = new System.Windows.Forms.MenuItem();
this.menuCollectUpload = new System.Windows.Forms.MenuItem();
this.menuUpload = new System.Windows.Forms.MenuItem();
this.menuConfig = new System.Windows.Forms.MenuItem();
this.exitMenuItem = new System.Windows.Forms.MenuItem();
this.label1 = new System.Windows.Forms.Label();
this.status = new System.Windows.Forms.Label();
this.upload = new System.Windows.Forms.Label();
this.loadingPanel = new System.Windows.Forms.Panel();
this.label2 = new System.Windows.Forms.Label();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.loadingPanel.SuspendLayout();
this.SuspendLayout();
//
// mainMenu1
//
this.mainMenu1.MenuItems.Add(this.campaignMenuItem);
this.mainMenu1.MenuItems.Add(this.exitMenuItem);
//
// campaignMenuItem
//
this.campaignMenuItem.Enabled = false;
this.campaignMenuItem.MenuItems.Add(this.menuCollect);
this.campaignMenuItem.MenuItems.Add(this.menuCollectUpload);
this.campaignMenuItem.MenuItems.Add(this.menuUpload);
this.campaignMenuItem.MenuItems.Add(this.menuConfig);
this.campaignMenuItem.Text = "Options";
//
// menuCollect
//
this.menuCollect.Text = "Collect / Save";
this.menuCollect.Click += new System.EventHandler(this.menuCollect_Click);
//
// menuCollectUpload
//
this.menuCollectUpload.Text = "Collect / Upload";
this.menuCollectUpload.Click += new System.EventHandler(this.menuCollectUpload_Click);
//
// menuUpload
//
this.menuUpload.Text = "Upload Saved";
this.menuUpload.Click += new System.EventHandler(this.menuUpload_Click);
//
// menuConfig
//
this.menuConfig.Text = "Change Configuration";
this.menuConfig.Click += new System.EventHandler(this.LoadConfiguration);
//
// exitMenuItem
//
this.exitMenuItem.Enabled = false;
this.exitMenuItem.Text = "Exit";
this.exitMenuItem.Click += new System.EventHandler(this.exitMenuItem_Click);
//
// label1
//
this.label1.Location = new System.Drawing.Point(0, 153);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(320, 10);
//
// status
//
this.status.Font = new System.Drawing.Font("Segoe Condensed", 8F, System.Drawing.FontStyle.Regular);
this.status.Location = new System.Drawing.Point(4, 2);
this.status.Name = "status";
this.status.Size = new System.Drawing.Size(313, 158);
//
// upload
//
this.upload.Font = new System.Drawing.Font("Segoe Condensed", 8F, System.Drawing.FontStyle.Regular);
this.upload.Location = new System.Drawing.Point(4, 167);
this.upload.Name = "upload";
this.upload.Size = new System.Drawing.Size(313, 20);
this.upload.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// loadingPanel
//
this.loadingPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.loadingPanel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255)))));
this.loadingPanel.Controls.Add(this.label2);
this.loadingPanel.Controls.Add(this.progressBar1);
this.loadingPanel.Location = new System.Drawing.Point(25, 43);
this.loadingPanel.Name = "loadingPanel";
this.loadingPanel.Size = new System.Drawing.Size(269, 91);
//
// label2
//
this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.label2.Location = new System.Drawing.Point(3, 24);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(263, 30);
this.label2.Text = "Loading please wait...";
this.label2.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// progressBar1
//
this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.progressBar1.Location = new System.Drawing.Point(3, 57);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(263, 19);
//
// MainForm
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
this.ClientSize = new System.Drawing.Size(320, 186);
this.Controls.Add(this.loadingPanel);
this.Controls.Add(this.upload);
this.Controls.Add(this.status);
this.Controls.Add(this.label1);
this.Menu = this.mainMenu1;
this.Name = "MainForm";
this.Text = "Campaignr";
this.Load += new System.EventHandler(this.MainForm_Load);
this.Closed += new System.EventHandler(this.MainForm_Closed);
this.loadingPanel.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
///
/// The main entry point for the application.
///
static void Main()
{
ThreadPool.SetMaxThreads(10, 10);
try
{
Application.Run(new MainForm());
}
catch (ObjectDisposedException ex)
{
// TODO: Fix ObjectDisposedException exception
string trace = ex.StackTrace;
}
}
///
/// Timer function that displays status and error messages to screen
///
private void monitorUpload(Object o)
{
lock (_lock)
{
Message msg;
//bool error = false;
try
{
while (!_killUploadMonitor && (msg = DatabaseManager.MessageQueue.GetItem()) != null)
{
// fetch all messages one at a time, once fetch, they are removed from queue
if (msg.MType == MessageType.Error)
{
// critical system error
// error = true; // stop the current operation if there are error messages
if (_debugModeOn)
Invoke(_delegateStatusUpdate, new Object[] { status, msg.ToString() });
}
else if (msg.MType == MessageType.Warning)
{
if (_debugModeOn)
Invoke(_delegateStatusUpdate, new Object[] { status, msg.ToString() });
}
else if (msg.MType == MessageType.Status)
{
Invoke(_delegateStatusUpdate, new Object[] { status, msg.ToString() });
}
else if (msg.MType == MessageType.Information)
{
if (_debugModeOn)
Invoke(_delegateStatusUpdate, new Object[] { status, msg.ToString() });
}
else if (msg.MType == MessageType.UploadSuccess)
{
if (msg.Text.Length == 0)
Invoke(_delegateUploadUpdate, new Object[] { upload, "" });
else
Invoke(_delegateUploadUpdate, new Object[] { upload, msg.ToString() });
}
else if (msg.MType == MessageType.Feedback)
{
if (msg.Text.Length > 0)
// Display feedback in textbox
Invoke(_delegateFeedbackUpdate, new Object[] { status, msg.ToString() });
}
else if (msg.MType == MessageType.TaskComplete)
{
Invoke(_delegateUploadUpdate, new Object[] { status, msg.ToString() });
}
}
//if (error)
// Invoke(_delegateMenus, new Object[] { null, null });
} catch {
// if there is an error at this point, it is most likely because the application is exiting and freeing resources, so don't bother showing it on screen
}
}
}
///
/// Updates the Status textbox
///
private void StatusUpdate(Label ctrl, Object val)
{
if (ctrl.Text.Length + val.ToString().Length < 5000)
{
ctrl.Text = val.ToString() + "\r\n" + ctrl.Text;
}
else
{
ctrl.Text = val.ToString() + "\r\n" + ctrl.Text.Substring(0, 1000);
}
if (this._graphicalInterface != null)
{
_graphicalInterface.OutputText = val.ToString().Substring(10);
}
}
///
/// Updates any feedback control
///
private void FeedbackUpdate(Label ctrl, Object val)
{
if (ctrl.Text.Length + val.ToString().Length < 5000)
{
ctrl.Text = val.ToString() + "\r\n" + ctrl.Text;
}
else
{
ctrl.Text = val.ToString() + "\r\n" + ctrl.Text.Substring(0, 1000);
}
}
///
/// Updates the Upload textbox
///
private void UploadUpdate(Label ctrl, Object val)
{
ctrl.Text = val.ToString();
if (this._graphicalInterface != null)
{
_graphicalInterface.OutputText = val.ToString().Substring(10);
}
}
// What do do when the exit menu item is selected
private void exitMenuItem_Click(object sender, EventArgs e)
{
if (manualSensorDataManagers.Count > 0 || automaticSensorDataManagers.Count > 0)
{
DatabaseManager.MessageQueue.PostItem(new Message("Closing Campaignr", MessageType.Status));
foreach(SensorDataManager manager in manualSensorDataManagers)
manager.Log = false; // make sure we turn off the log
foreach (SensorDataManager manager in automaticSensorDataManagers)
manager.Log = false; // make sure we turn off the log
}
try
{
Close();
}
catch (Exception ex)
{
// TODO: Fix Null Pointer exception
string exs2 = ex.Message;
}
}
// Called when MainForm loads
private void MainForm_Load(object sender, System.EventArgs e)
{
status.Width = Screen.PrimaryScreen.WorkingArea.Width;
status.Height = Screen.PrimaryScreen.WorkingArea.Height;
}
// Close sensors and any transmit monitors
private void MainForm_Closed(object sender, System.EventArgs e)
{
closeSensors();
}
// Start upload monitor thread
private void startMonitor()
{
status.Text = "";
_killUploadMonitor = false;
AutoResetEvent autoEvent = new AutoResetEvent(false);
_timerDelegate = new TimerCallback(monitorUpload);
_uploadMonitorTimer = new System.Threading.Timer(_timerDelegate, autoEvent, 0, uploadMonitorInterval);
}
private void uploadData() { }
private void collectData() { }
private void closeSensors(){
if (_uploadMonitorTimer != null)
{
_killUploadMonitor = true;
_uploadMonitorTimer.Dispose();
}
foreach (SensorDataManager manager in manualSensorDataManagers)
{
manager.CloseSensors();
}
foreach (SensorDataManager manager in automaticSensorDataManagers)
{
manager.CloseSensors();
}
}
private OperationModes _operationMode;
// Set mode of operation (upload, collect or collect_upload)
// Modes are mutually exclusive
private OperationModes Mode
{
set
{
_operationMode = value;
// Interrupt sensors and monitor while changing mode
//closeSensors();
bool activityOn = false;
switch (_operationMode)
{
case OperationModes.Upload:
menuCollect.Checked = false;
menuCollectUpload.Checked = false;
activityOn = menuUpload.Checked = !menuUpload.Checked;
if (activityOn)
{
foreach (SensorDataManager manager in manualSensorDataManagers)
{
manager.UploadOnly();
}
foreach (SensorDataManager manager in automaticSensorDataManagers)
{
manager.UploadOnly();
}
}
break;
case OperationModes.Collect:
menuUpload.Checked = false;
menuCollectUpload.Checked = false;
activityOn = menuCollect.Checked = !menuCollect.Checked;
if (activityOn)
{
/*foreach (SensorDataManager manager in manualSensorDataManagers)
{
manager.Collect(false, false);
}*/
foreach (SensorDataManager manager in automaticSensorDataManagers)
{
manager.Collect(false);
}
}
break;
case OperationModes.CollectUpload:
menuUpload.Checked = false;
menuCollect.Checked = false;
activityOn = menuCollectUpload.Checked = !menuCollectUpload.Checked;
if (activityOn && automaticSensorDataManagers.Count > 0)
{
foreach (SensorDataManager manager in automaticSensorDataManagers)
{
manager.Collect(true);
}
}
break;
}
if (activityOn)
startMonitor();
}
}
// Collect data and store locally
private void menuCollect_Click(object sender, EventArgs e)
{
this.Mode = OperationModes.Collect;
}
//! Collect data and upload to server
public void menuCollectUpload_Click(object sender, EventArgs e)
{
this.Mode = OperationModes.CollectUpload;
}
// Upload to server
private void menuUpload_Click(object sender, EventArgs e)
{
this.Mode = OperationModes.Upload;
}
// Reads the configuration xml file for campaignr
private void ParseXMLConfiguration(string filename, string path)
{
try
{
XmlTextReader rdr = new XmlTextReader(path + filename);
SimpleDOMParser sdp = new SimpleDOMParser();
SimpleElement se = sdp.parse(rdr);
bool flushDatabase = false;
foreach (SensorDataManager manager in manualSensorDataManagers)
{
manager.CloseSensors();
}
foreach (SensorDataManager manager in automaticSensorDataManagers)
{
manager.CloseSensors();
}
manualSensorDataManagers.Clear();
automaticSensorDataManagers.Clear();
if (se.TagName.ToLower().Equals("campaign"))
{
_campaignname = se.Attributes["name"];
// TODO: Flush the database if requested
if (se.Attribute("flushDatabase") != null && se.Attribute("flushDatabase") == "true")
flushDatabase = true;
this.Text = "Campaignr - "+ _campaignname;
// Whether or not to start uploading data on start
if(se.Attributes["uploadOnStart"] != null && System.Convert.ToBoolean(se.Attributes["uploadOnStart"]) == false)
_uploadOnStart = false;
_debugModeOn = System.Convert.ToBoolean(se.Attributes["debug"]);
SimpleElements elements = se.ChildElements;
if (elements.Count == 0)
{
DatabaseManager.MessageQueue.PostItem(new Message("Configuration file missing automatic or manual section", MessageType.Error));
return;
}
for (int i = 0; i < elements.Count; i++)
{
SimpleElement collection = elements.Item(i);
SensorDataManager manager = new SensorDataManager(flushDatabase);
manager.CollectInterval = uploadInterval;
manager.Log = _debugModeOn;
manager.CampaignId = filename;
if (collection.TagName == "automatic")
{
// Whether or not to start collecting data on start
_startOnLoad = System.Convert.ToBoolean(se.Attributes["startOnLoad"]);
manager.Automatic = true;
automaticSensorDataManagers.Add(manager);
}
else if (collection.TagName == "manual")
{
manualSensorDataManagers.Add(manager);
}
else
{
manager = null;
continue;
}
progressBar1.Value += 10;
int step = (int)Math.Floor(((20 / elements.Count) / collection.ChildElements.Count));
foreach (SimpleElement child in collection.ChildElements)
{
progressBar1.Value += Math.Min(progressBar1.Maximum - progressBar1.Value, step);
string name = child.TagName;
if (name.ToLower().Equals("sensor")) // activate the appropriate sensors by parsing this element
{
string type = child.Attributes["type"];
if (type != null)
{
try
{
// Get name
string sensorName = child.Attributes["name"];
if (sensorName == null)
//throw new ArgumentException("Missing name attribute for " + type + " sensor");
sensorName = type.Trim(); // make it compatible with Symbian and older xmls
else
sensorName = sensorName.Trim();
if (type.ToLower().Equals("imei"))
{
string hashed = child.Attributes["hash"];
if (hashed != null && hashed == "true")
manager.AssignSensor(new DeviceId("campaignrwm"), sensorName);
else
manager.AssignSensor(new Imei(), sensorName);
}
else if (type.ToLower().Equals("cellid"))
manager.AssignSensor(new CellTower(), sensorName);
else if (type.ToLower().Equals("timestamp"))
manager.AssignSensor(new Timestamp(), sensorName);
else if (type.ToLower().Equals("bt_stumble"))
{
if (child.ChildElements.Count == 0)
manager.AssignSensor(new BTStumbler(true), sensorName);
else
{
foreach (SimpleElement btchild in child.ChildElements)
{
if (btchild.TagName == "address_only")
manager.AssignSensor(new BTStumbler(false), sensorName);
}
}
}
else if (type.ToLower().Equals("location"))
{
Gps gps = new Gps();
gps.Open();
gps.LocationChanged += new LocationChangedEventHandler(LocationChanged);
manager.AssignSensor(gps, sensorName);
}
else if (type.ToLower().Equals("audio"))
manager.AssignSensor(new Microphone(), sensorName);
else if (type.ToLower().Equals("tag"))
{
SimpleElement prompt = child.ChildElements.Item("prompt");
SimpleElement input = child.ChildElements.Item("text");
if (input != null)
{
Ucla.Cens.Campaignr.Library.Sensors.TextInput text = new Ucla.Cens.Campaignr.Library.Sensors.TextInput(false);
if (prompt != null)
text.Prompt = prompt.Text;
text.InputText = input.Text;
manager.AssignSensor(text, sensorName);
}
else
{
Ucla.Cens.Campaignr.Library.Sensors.Tag tag = new Ucla.Cens.Campaignr.Library.Sensors.Tag();
if (child.Attribute("multiselect") == "false")
tag.Multiselect = false;
if (prompt != null)
tag.Prompt = prompt.Text;
input = child.ChildElements.Item("list");
if (input == null)
throw new ArgumentNullException("An input (text or list) element must be specified for this sensor");
foreach (SimpleElement item in input.ChildElements)
{
if (item.TagName == "text")
tag.AddItem(item.Text);
}
manager.AssignSensor(tag, sensorName);
}
}
else if (type.ToLower().Equals("text"))
{
Ucla.Cens.Campaignr.Library.Sensors.TextInput text = new Ucla.Cens.Campaignr.Library.Sensors.TextInput(true);
SimpleElement input = child.ChildElements.Item("text");
if (input != null)
text.InputText = input.Text;
manager.AssignSensor(text, sensorName);
}
else if (type.ToLower().Equals("pedometer"))
{
string portName = (child.Attributes["port"] != null) ? child.Attributes["port"] : "com0";
manager.AssignSensor(new NikePedometer(portName), sensorName); // TODO: Must read port name from configuration file
}
else if (type.ToLower().Equals("video"))
{
SimpleElement size = child.ChildElements.Item("size");
SimpleElement audio = child.ChildElements.Item("audio");
Ucla.Cens.Campaignr.Library.Sensors.ManualCamera.Modes mode = Ucla.Cens.Campaignr.Library.Sensors.ManualCamera.Modes.VIDEO;
if (audio != null)
mode = Ucla.Cens.Campaignr.Library.Sensors.ManualCamera.Modes.VIDEOAUDIO;
Ucla.Cens.Campaignr.Library.Sensors.ManualCamera camera = new Ucla.Cens.Campaignr.Library.Sensors.ManualCamera(mode);
if (size != null)
camera.Resolution = size.Text;
manager.AssignSensor(camera, sensorName);
}
else if (type.ToLower().Equals("image"))
{
SimpleElement size = child.ChildElements.Item("size");
SimpleElement format = child.ChildElements.Item("format");
string review = child.Attribute("review");
if (child.ChildElements.Item("viewfinder") != null)
{
/*ManualCamera camera = new ManualCamera();
if (size != null)
camera.Resolution = size.Text;
// Format is not supported by CameraCaptureDialog but still quality is...
if (format != null)
camera.Quality = format.Text;*/
NativeCamera camera = new NativeCamera();
//if (size != null)
// camera.Resolution = size.Text;
if (review != null)
{
if (review == "false")
camera.Review = false;
else
camera.Review = true;
}
manager.AssignSensor(camera, sensorName);
}
else
{
manager.AssignSensor(new ImageSensor(), sensorName); // TODO: Must set image size
}
}
else
{
// TODO: Check for runtime libraries
//object[] args = new object[5];
List