using System;
using System.Collections.Generic;
using System.Xml;
using UnityEngine;
using Ubisoft.Hotel.Localisation.Editor;
namespace Ubisoft.Hotel.Package.Editor
{
///
/// Class responsible for defining an InfoPlist property, typically through HPV via vode (https://confluence.ubisoft.com/x/CrxNQg),
/// so consumers can define InfoPlist properties easily.
///
/// Besides simple properties an InfoPlist property can be a list of InfoPlist properties and a Dictionary of InfoPlist properties.
/// Hotel's first approach to support this kind of properties was to use recursivity but this recursivity doesn't get along with
/// serialisation and produced the following warning message:
/// "Serialization depth limit 10 exceeded at 'Ubisoft.Hotel.Package.Editor::InfoPlistProperty.m_valueAsList'. There may be an object composition cycle in one or more of your serialized classes."
/// This is the reason why InfoPlistProperty relies on InfoPlistItem, which only supports simple properties.
/// This means that Hotel doesn't support a List/Dictionary of a List/Dictionary of InfoPlistProperty objects.
/// In order to address this complex cases PlatformBuildProperty_iOS provide InfoPlist raw properties which allow you to provide a string
/// with the exact paragraph that you need to add to the InfoPlist document.
///
[Serializable]
public class InfoPlistProperty
{
public const string ATTRIBUTE_ITEM = "m_item";
public const string ATTRIBUTE_VALUE_AS_LIST = "m_valueAsList";
[SerializeField]
private InfoPlistItem m_item;
[SerializeField]
private List m_valueAsList;
private InfoPlistProperty(InfoPlistItem item)
{
m_item = item;
}
public InfoPlistProperty(string key, string value) : this(new InfoPlistItem(key, value))
{
}
public InfoPlistProperty(string key, bool value) : this(new InfoPlistItem(key, value))
{
}
public InfoPlistProperty(string key, int value) : this(new InfoPlistItem(key, value))
{
}
public InfoPlistProperty(string key, float value) : this(new InfoPlistItem(key, value))
{
}
public InfoPlistProperty(string key, double value) : this(new InfoPlistItem(key, value))
{
}
public InfoPlistProperty(string key, List value) : this(new InfoPlistItem(key, value))
{
}
public InfoPlistProperty(string key, List value, bool useArrayType = true) : this(new InfoPlistItem(key, useArrayType ? InfoPlistItem.EType.Array : InfoPlistItem.EType.Dictionary, null))
{
ValueAsList = value;
}
public InfoPlistProperty Clone()
{
InfoPlistProperty returnValue = new InfoPlistProperty(Item.Clone());
if (ValueAsList != null)
{
returnValue.ValueAsList = new List();
int count = ValueAsList.Count;
for (int i = 0; i < count; i++)
{
returnValue.ValueAsList.Add(ValueAsList[i].Clone());
}
}
return returnValue;
}
private InfoPlistItem Item
{
get { return m_item; }
set { m_item = value; }
}
public string Key
{
get { return Item.Key; }
set { Item.Key = value; }
}
internal InfoPlistItem.EType Type
{
get { return Item.Type; }
set { Item.Type = value; }
}
public string TypeAsString
{
get { return Type.ToString(); }
}
public string Value
{
get { return Item.Value; }
set { Item.Value = value; }
}
public List ValueAsList
{
get { return m_valueAsList; }
set { m_valueAsList = value; }
}
public List ValueAsLocalisedString
{
get { return Item.ValueAsLocalisedString; }
set { Item.ValueAsLocalisedString = value; }
}
public bool IsLocalisedStringType()
{
return Item.IsLocalisedStringType();
}
public bool IsValid()
{
bool returnValue = Item.IsValid();
if (returnValue && IsMultipleType())
{
returnValue = IsValueAsListValid();
}
return returnValue;
}
public string GetDebugIsValidDescription()
{
string returnValue = Item.GetDebugIsValidDescription();
if (IsMultipleType())
{
string detail = null;
if (!IsValueAsListValid())
{
detail = $" {Debug.FormatTextInCodeContext("ValueAsList")} is not valid.";
}
if (ValueAsList != null)
{
int count = ValueAsList.Count;
for (int i = 0; i < count; i++)
{
if (!ValueAsList[i].IsValid())
{
detail += $" {ValueAsList[i].GetDebugIsValidDescription()}";
}
}
}
if (!string.IsNullOrEmpty(detail))
{
returnValue += detail;
}
}
return returnValue;
}
public bool IsMultipleType()
{
return Item.IsMultipleType();
}
private bool IsValueAsListValid()
{
bool returnValue = true;
if (ValueAsList != null)
{
int count = ValueAsList.Count;
for (int i = 0; i < count && returnValue; i++)
{
returnValue = ValueAsList[i].IsValid();
}
}
return returnValue;
}
public bool Validate()
{
bool returnValue = Item.Validate();
// Clear ValueAsList for single value properties in order to avoid misunderstandings
if (IsMultipleType())
{
// Multiple type properties use ValueAsList instead of Value. Value is set to empty to avoid misunderstandings
if (!string.IsNullOrEmpty(Value))
{
Value = "";
returnValue = false;
}
if (ValueAsLocalisedString != null)
{
ValueAsLocalisedString.Clear();
}
if (ValueAsList != null)
{
int count = ValueAsList.Count;
for (int i = 0; i < count; i++)
{
if (!ValueAsList[i].Validate())
{
returnValue = false;
}
}
}
}
else if (ValueAsList != null && ValueAsList.Count > 0)
{
ValueAsList.Clear();
returnValue = false;
}
return returnValue;
}
public XmlElement GetValueNode(XmlDocument xmlDocument)
{
XmlElement returnValue;
switch (Type)
{
case InfoPlistItem.EType.Array:
returnValue = xmlDocument.CreateElement("array");
if (ValueAsList != null)
{
int count = ValueAsList.Count;
for (int i = 0; i < count; i++)
{
_ = returnValue.AppendChild(ValueAsList[i].GetValueNode(xmlDocument));
}
}
break;
case InfoPlistItem.EType.Dictionary:
returnValue = xmlDocument.CreateElement("dict");
if (ValueAsList != null)
{
XmlElement keyChild;
int count = ValueAsList.Count;
for (int i = 0; i < count; i++)
{
// Key
keyChild = xmlDocument.CreateElement("key");
keyChild.InnerText = ValueAsList[i].Key;
_ = returnValue.AppendChild(keyChild);
// Value
_ = returnValue.AppendChild(ValueAsList[i].GetValueNode(xmlDocument));
}
}
break;
default:
returnValue = Item.GetValueNode(xmlDocument);
break;
}
return returnValue;
}
public override string ToString()
{
return "Property [Key: " + Key + " Value: " + Value + " Type: " + Type + "]";
}
}
}