636 lines
19 KiB
C#
636 lines
19 KiB
C#
//-----------------------------------------------------------------------------
|
|
// <copyright file="MainModel.cs" company="BTU/IIT">
|
|
// Company copyright tag.
|
|
// </copyright>
|
|
// <author>fiedlchr</author>
|
|
// <sience>05.07.2013</sience>
|
|
//-----------------------------------------------------------------------------
|
|
namespace CampusAppWP8
|
|
{
|
|
using CampusAppWP8.Utility;
|
|
using CampusAppWPortalLib8.Model.Utility;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Net;
|
|
|
|
/// <summary>
|
|
/// Base model io handling class.
|
|
/// </summary>
|
|
/// <typeparam name="T">model type</typeparam>
|
|
public abstract class MainModel<T>
|
|
{
|
|
#region Member
|
|
|
|
/// <summary>
|
|
/// File object.
|
|
/// </summary>
|
|
protected CampusAppWP8.Utility.File file = null;
|
|
|
|
/// <summary>
|
|
/// Model io type.
|
|
/// </summary>
|
|
private ModelType modelType;
|
|
|
|
/// <summary>
|
|
/// Model object.
|
|
/// </summary>
|
|
private T model = default(T);
|
|
|
|
/// <summary>
|
|
/// Web object.
|
|
/// </summary>
|
|
private HttpRequest api = null;
|
|
|
|
/// <summary>
|
|
/// Filename of saved data.
|
|
/// </summary>
|
|
private string fileName = string.Empty;
|
|
|
|
/// <summary>
|
|
/// Url of the feed data.
|
|
/// </summary>
|
|
private Uri httpApiUri = null;
|
|
|
|
/// <summary>
|
|
/// Parameterized uri of the feed.
|
|
/// </summary>
|
|
private Uri paramizedUri = null;
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="MainModel{T}" /> class.
|
|
/// </summary>
|
|
/// <param name="modelType">Model IO type</param>
|
|
/// <param name="fileName">name of the file</param>
|
|
/// <param name="url">url of the feed</param>
|
|
public MainModel(ModelType modelType, string fileName, string url)
|
|
{
|
|
this.Init(modelType, fileName, url);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="MainModel{T}" /> class.
|
|
/// </summary>
|
|
/// <param name="modelType">Model IO type</param>
|
|
/// <param name="sourceName">name of the file or the url of the feed</param>
|
|
public MainModel(ModelType modelType, string sourceName)
|
|
{
|
|
if (modelType == ModelType.File)
|
|
{
|
|
this.Init(modelType, sourceName, string.Empty);
|
|
}
|
|
else if (modelType == ModelType.Feed)
|
|
{
|
|
this.Init(modelType, string.Empty, sourceName);
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException("Wrong constructor was called for Feed and File support.");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Events
|
|
|
|
/// <summary>
|
|
/// Delegate of the OnIO callback function.
|
|
/// </summary>
|
|
public delegate void OnIO();
|
|
|
|
/// <summary>
|
|
/// Delegate of the OnFailed(File/Web) callback function.
|
|
/// </summary>
|
|
public delegate void OnFailed();
|
|
|
|
/// <summary>
|
|
/// Delegate of the IsModelUpToDate callback function.
|
|
/// </summary>
|
|
/// <param name="model">data model</param>
|
|
/// <returns>true, model is up to date</returns>
|
|
public delegate bool IsModelUpToDate(T model);
|
|
|
|
/// <summary>
|
|
/// Delegate of the IsFileUpToDate callback function.
|
|
/// </summary>
|
|
/// <param name="model">data model</param>
|
|
/// <param name="fileInfo">info of the file</param>
|
|
/// <returns>true, is file is up to date</returns>
|
|
public delegate bool IsFileUpToDate(T model, FileInfo fileInfo);
|
|
|
|
/// <summary>
|
|
/// Callback pointer, called before loading.
|
|
/// </summary>
|
|
public event OnIO OnLoading = null;
|
|
|
|
/// <summary>
|
|
/// Callback pointer, called after loading.
|
|
/// </summary>
|
|
public event OnIO OnLoaded = null;
|
|
|
|
/// <summary>
|
|
/// Callback pointer, called before saving.
|
|
/// </summary>
|
|
public event OnIO OnSaving = null;
|
|
|
|
/// <summary>
|
|
/// Callback pointer, called after saving.
|
|
/// </summary>
|
|
public event OnIO OnSaved = null;
|
|
|
|
/// <summary>
|
|
/// Callback pointer, called after failed file loading.
|
|
/// </summary>
|
|
public event OnFailed OnFailedFile = null;
|
|
|
|
/// <summary>
|
|
/// Callback pointer, called after failed web loading.
|
|
/// </summary>
|
|
public event OnFailed OnFailedWeb = null;
|
|
|
|
/// <summary>
|
|
/// Callback pointer, called after failed file or web loading, if there
|
|
/// is no specialized onFailed callback set.
|
|
/// </summary>
|
|
public event OnFailed OnFailedLoad = null;
|
|
|
|
/// <summary>
|
|
/// Callback pointer, called after failed saving data to file.
|
|
/// </summary>
|
|
public event OnFailed OnFailedSave = null;
|
|
|
|
/// <summary>
|
|
/// Callback pointer, for checking if file is up to date at loading.
|
|
/// </summary>
|
|
public event IsFileUpToDate IsFileUpToDateOnLoad = null;
|
|
|
|
/// <summary>
|
|
/// Callback pointer, for checking if file is up to date at saving.
|
|
/// </summary>
|
|
public event IsFileUpToDate IsFileUpToDateOnSave = null;
|
|
|
|
/// <summary>
|
|
/// Callback pointer, for checking if model is up to date at loading.
|
|
/// </summary>
|
|
public event IsModelUpToDate IsModelUpToDateOnLoad = null;
|
|
|
|
/// <summary>
|
|
/// Callback pointer, for checking if model is up to date at saving.
|
|
/// (currently unused)
|
|
/// </summary>
|
|
public event IsModelUpToDate IsModelUpToDateOnSave = null;
|
|
|
|
#endregion
|
|
|
|
#region Enum
|
|
|
|
/// <summary>
|
|
/// Specifies the I/O type of the model.
|
|
/// </summary>
|
|
public enum ModelType
|
|
{
|
|
/// <summary>
|
|
/// Invalid/unset state.
|
|
/// </summary>
|
|
INVALID = 0,
|
|
|
|
/// <summary>
|
|
/// File only (01).
|
|
/// </summary>
|
|
File = 1,
|
|
|
|
/// <summary>
|
|
/// Feed only (10).
|
|
/// </summary>
|
|
Feed = 2,
|
|
|
|
/// <summary>
|
|
/// File and feed (11).
|
|
/// </summary>
|
|
FileAndFeed = 3
|
|
}
|
|
|
|
/// <summary>Values that represent ForceType for load function.</summary>
|
|
public enum ForceType
|
|
{
|
|
/// <summary>An enumeration constant representing the invalid/default/unset option.</summary>
|
|
INVALID = 0,
|
|
|
|
/// <summary>An enumeration constant representing the force file option.</summary>
|
|
FORCE_FILE = 1,
|
|
|
|
/// <summary>An enumeration constant representing the force web option.</summary>
|
|
FORCE_WEB = 2
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Property
|
|
|
|
/// <summary>
|
|
/// Gets or sets the Model.
|
|
/// </summary>
|
|
public T Model
|
|
{
|
|
get
|
|
{
|
|
return this.model;
|
|
}
|
|
|
|
set
|
|
{
|
|
this.model = value;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Method
|
|
|
|
#region public
|
|
|
|
/// <summary>
|
|
/// Forces a update from web.
|
|
/// </summary>
|
|
public void ForceWebUpdate()
|
|
{
|
|
this.LoadData(ForceType.FORCE_WEB);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Forces a update from file.
|
|
/// </summary>
|
|
public void ForceReadFile()
|
|
{
|
|
this.LoadData(ForceType.FORCE_FILE);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Load the data if necessary, from web or from file, regarding if
|
|
/// the file data is up to date.
|
|
/// </summary>
|
|
/// <param name="force">if set/not invalid/not default, force to load from web or file</param>
|
|
public void LoadData(ForceType force = ForceType.INVALID)
|
|
{
|
|
this.RunOnIOCallback(this.OnLoading);
|
|
|
|
// check which source is used for loading the data
|
|
if (force == ForceType.INVALID)
|
|
{
|
|
// if the model is not up to date
|
|
if (this.CheckIsNotUpToDate(this.IsModelUpToDateOnLoad) == true)
|
|
{
|
|
force = ForceType.FORCE_FILE;
|
|
|
|
if (this.file != null)
|
|
{
|
|
// if the file does not exist or is size of 0 or is not
|
|
// up to date, then load from web
|
|
if ((this.file.Exist() == false)
|
|
|| (this.file.GetFileInfo().Length == 0)
|
|
|| (this.CheckIsNotUpToDate(this.IsFileUpToDateOnLoad) == true))
|
|
{
|
|
force = ForceType.FORCE_WEB;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if the file object does not exist, load from web
|
|
force = ForceType.FORCE_WEB;
|
|
}
|
|
|
|
// if the web object does not exist, load from file
|
|
if (this.api == null)
|
|
{
|
|
force = ForceType.FORCE_FILE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if it is up to date, nothing has to be loaded
|
|
this.RunOnIOCallback(this.OnLoaded);
|
|
}
|
|
}
|
|
|
|
// load from web
|
|
if (force == ForceType.FORCE_WEB)
|
|
{
|
|
if (this.api != null)
|
|
{
|
|
if (this.paramizedUri != null)
|
|
{
|
|
this.api.HttpGet(this.paramizedUri, this.OnLoadDataComplete);
|
|
}
|
|
else
|
|
{
|
|
this.api.HttpGet(this.httpApiUri, this.OnLoadDataComplete);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if web object does not exist, call OnFailed callbacks
|
|
this.RunOnFailedCallback(this.OnFailedWeb, this.OnFailedLoad);
|
|
}
|
|
}
|
|
|
|
// load from file
|
|
if (force == ForceType.FORCE_FILE)
|
|
{
|
|
if (this.file != null)
|
|
{
|
|
byte[] data = this.file.ReadFile();
|
|
|
|
if (data == null)
|
|
{
|
|
this.RunOnFailedCallback(this.OnFailedFile, this.OnFailedLoad);
|
|
}
|
|
else
|
|
{
|
|
if (data.Length > 0)
|
|
{
|
|
this.DeserializeModel(data);
|
|
}
|
|
|
|
this.RunOnIOCallback(this.OnLoaded);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if file object does not exist, call OnFailed callbacks
|
|
this.RunOnFailedCallback(this.OnFailedFile, this.OnFailedLoad);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Save the model data if necessary.
|
|
/// </summary>
|
|
/// <param name="force">force saving. DEFAULT: false</param>
|
|
public void SaveData(bool force = false)
|
|
{
|
|
if ((this.file != null)
|
|
&& ((this.CheckIsNotUpToDate(this.IsFileUpToDateOnSave) == true) || (force == true)))
|
|
{
|
|
this.RunOnIOCallback(this.OnSaving);
|
|
|
|
byte[] data = this.SerializeModel();
|
|
|
|
if ((this.OnSaved != null) && (this.OnFailedSave != null))
|
|
{
|
|
this.file.WriteFile(data, delegate { this.OnSaved(); }, delegate { this.OnFailedSave(); });
|
|
}
|
|
else if (this.OnSaved != null)
|
|
{
|
|
this.file.WriteFile(data, delegate { this.OnSaved(); }, null);
|
|
}
|
|
else if (this.OnFailedSave != null)
|
|
{
|
|
this.file.WriteFile(data, null, delegate { this.OnFailedSave(); });
|
|
}
|
|
else
|
|
{
|
|
this.file.WriteFile(data, null, null);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return the model io type.
|
|
/// </summary>
|
|
/// <returns>model io type</returns>
|
|
public ModelType GetModelType()
|
|
{
|
|
return this.modelType;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return the model.
|
|
/// </summary>
|
|
/// <returns>model object</returns>
|
|
public T GetModel()
|
|
{
|
|
return this.model;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create the parameterized uri.
|
|
/// </summary>
|
|
/// <param name="parameters">uri parameter list</param>
|
|
public void SetUriParams(List<UrlParamModel> parameters)
|
|
{
|
|
if (this.api != null)
|
|
{
|
|
this.paramizedUri = this.api.CreateGetUrl(parameters);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clear the parameterized uri.
|
|
/// </summary>
|
|
public void ClearUriParams()
|
|
{
|
|
this.paramizedUri = null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region protected
|
|
|
|
/// <summary>
|
|
/// Abstract declaration of the model deserialize function.
|
|
/// </summary>
|
|
/// <param name="modelData">model data as byte array</param>
|
|
/// <returns>true, is succeeded</returns>
|
|
protected abstract bool DeserializeModel(byte[] modelData);
|
|
|
|
/// <summary>
|
|
/// Abstract declaration of the model serialize function.
|
|
/// </summary>
|
|
/// <returns>model data as byte array</returns>
|
|
protected abstract byte[] SerializeModel();
|
|
|
|
/// <summary>
|
|
/// Check if the model io type is file.
|
|
/// </summary>
|
|
/// <returns>true, if the model io type has file.</returns>
|
|
protected bool IsFile()
|
|
{
|
|
bool retValue = false;
|
|
|
|
if ((this.modelType & ModelType.File) != 0)
|
|
{
|
|
retValue = true;
|
|
}
|
|
|
|
return retValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check if the model io type is feed.
|
|
/// </summary>
|
|
/// <returns>true if the model io type has feed.</returns>
|
|
protected bool IsHttpApi()
|
|
{
|
|
bool retValue = false;
|
|
|
|
if ((this.modelType & ModelType.Feed) != 0)
|
|
{
|
|
retValue = true;
|
|
}
|
|
|
|
return retValue;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region private
|
|
|
|
/// <summary>
|
|
/// Initialize the class. Is called by the constructors.
|
|
/// </summary>
|
|
/// <param name="modelType">model IO type</param>
|
|
/// <param name="fileName">name of the data file</param>
|
|
/// <param name="url">url of the feed data</param>
|
|
private void Init(ModelType modelType, string fileName, string url)
|
|
{
|
|
this.modelType = modelType;
|
|
|
|
if ((url != null) && (url.Equals(string.Empty) == false))
|
|
{
|
|
this.httpApiUri = new Uri(url, UriKind.Absolute);
|
|
}
|
|
|
|
this.fileName = fileName;
|
|
|
|
if ((this.IsFile() == true)
|
|
&& (fileName.Equals(string.Empty) == false))
|
|
{
|
|
this.InitFile();
|
|
}
|
|
|
|
if ((this.IsHttpApi() == true)
|
|
&& (url.Equals(string.Empty) == false))
|
|
{
|
|
this.InitHttpApi();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes the file object.
|
|
/// </summary>
|
|
private void InitFile()
|
|
{
|
|
if ((this.IsFile() == true)
|
|
&& (this.file == null))
|
|
{
|
|
this.file = new CampusAppWP8.Utility.File(this.fileName);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes the web object.
|
|
/// </summary>
|
|
private void InitHttpApi()
|
|
{
|
|
if ((this.IsHttpApi() == true)
|
|
&& (this.api == null))
|
|
{
|
|
this.api = new HttpRequest(this.httpApiUri);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Is called after the loading from web is complete.
|
|
/// </summary>
|
|
/// <param name="sender">sending object</param>
|
|
/// <param name="e">event args</param>
|
|
private void OnLoadDataComplete(object sender, OpenReadCompletedEventArgs e)
|
|
{
|
|
Exception downloadError = e.Error;
|
|
if (downloadError != null)
|
|
{
|
|
this.RunOnFailedCallback(this.OnFailedWeb, this.OnFailedLoad);
|
|
}
|
|
else
|
|
{
|
|
byte[] data;
|
|
using (MemoryStream ms = new MemoryStream())
|
|
{
|
|
e.Result.CopyTo(ms);
|
|
data = ms.ToArray();
|
|
}
|
|
|
|
if (data != null && data.Length > 0)
|
|
{
|
|
this.DeserializeModel(data);
|
|
}
|
|
|
|
this.RunOnIOCallback(this.OnLoaded);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Executes the on i/o callback operation.
|
|
/// </summary>
|
|
/// <param name="callbackFunc">The callback function.</param>
|
|
private void RunOnIOCallback(OnIO callbackFunc)
|
|
{
|
|
if (callbackFunc != null)
|
|
{
|
|
callbackFunc();
|
|
}
|
|
}
|
|
|
|
/// <summary>Executes the on failed callback operation.</summary>
|
|
/// <param name="specialFunc">The special function.</param>
|
|
/// <param name="defaultFunc">The default function.</param>
|
|
private void RunOnFailedCallback(OnFailed specialFunc, OnFailed defaultFunc)
|
|
{
|
|
if (specialFunc != null)
|
|
{
|
|
specialFunc();
|
|
}
|
|
else if (defaultFunc != null)
|
|
{
|
|
defaultFunc();
|
|
}
|
|
}
|
|
|
|
/// <summary>Check if model or file is not up to date.</summary>
|
|
/// <param name="checkFunc">The check function.</param>
|
|
/// <returns>true if model or file is not up to date, false if it is.</returns>
|
|
private bool CheckIsNotUpToDate(object checkFunc)
|
|
{
|
|
bool retValue = false;
|
|
|
|
// if there is no check function, the model or file is not up to date
|
|
if (checkFunc == null)
|
|
{
|
|
retValue = true;
|
|
}
|
|
else
|
|
{
|
|
Type funcType = checkFunc.GetType();
|
|
|
|
if (funcType.Equals(typeof(IsFileUpToDate)))
|
|
{
|
|
retValue = !(checkFunc as IsFileUpToDate)(this.model, this.file.GetFileInfo());
|
|
}
|
|
else if (funcType.Equals(typeof(IsModelUpToDate)))
|
|
{
|
|
retValue = !(checkFunc as IsModelUpToDate)(this.model);
|
|
}
|
|
}
|
|
|
|
return retValue;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
}
|
|
} |