using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Perforce.P4
{
///
/// Describes fields and comments in a Perforce specification.
///
public class FormBase :Dictionary
{
public Dictionary IsFieldMultiLine { get; internal set; }
public String Comments { get; set; }
public FormBase()
{
IsFieldMultiLine = new Dictionary();
}
#region Tagged Form Data
///
/// Set the Values Dictionary from tagged output of a Perforce command.
///
///
/// Needed when the object's data dictionary is set after the object
/// is created using the default constructer.
///
/// Object data
internal void SetValues(TaggedObject data)
{
//if (data.ContainsKey("specdef"))
//{
// specDescription = new SpecificationMetaData(data["specdef"]);
//}
// map of base key names to max index (so far)
Dictionary baseKeys = new Dictionary();
foreach (String key in data.Keys)
{
try
{
if (char.IsNumber(key, key.Length - 1))
{
// value is part of a list
string baseKey = key.TrimEnd('0', '1', '2', '3', '4', '5', '6', '7', '8', '9');
string idxStr = key.Substring(baseKey.Length);
int idx = -1;
int.TryParse(idxStr, out idx);
IsFieldMultiLine[baseKey] = false;
if (ContainsKey(baseKey) == false)
{
this[baseKey] = new List(idx + 1);
}
List strList = this[baseKey] as List;
while (strList.Count <= idx)
{
strList.Add(null);
}
strList[idx] = data[key];
}
else
{
if (data[key].Contains("\r") ||
data[key].Contains("\n"))
{
IsFieldMultiLine[key] = true;
}
this[key] = data[key];
}
}
catch { }; //Extra tag included with TaggedInfoItem data can be ignored
}
}
#endregion
#region From string data (a spec form)
///
/// Parse a string specification in the server format into an object.
///
///
/// The base implementation parses the generic specification tag::value
/// format into the underlying dictionary
///
/// String specification
/// Success/Failure
virtual public bool Parse(String spec)
{
String currentTag = String.Empty;
IList currentValueList = null;
String[] lines = spec.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
for (int idx = 0; idx < lines.Length; idx++)
{
if (lines[idx][0] == '#') // # comment
{
if (Comments == null)
{
Comments = lines[idx];
}
else
{
Comments += "\r\n";
Comments += lines[idx];
}
continue;
}
else if (lines[idx][0] == '\t') // tab char so this is part of a value field
{
currentValueList.Add(lines[idx].TrimStart('\t'));
}
else
{
//new tag line
String line = lines[idx].Trim();
int colonPos = line.IndexOf(':');
if (colonPos <= 0) //bad line
continue;
// start of a tag
currentValueList = null;
currentTag = line.Substring(0, colonPos);
if (colonPos < line.Length - 1)
{
// right of colon is the value
this[currentTag] = line.Substring(colonPos + 1).Trim();
IsFieldMultiLine[currentTag] = false;
}
else
{
IsFieldMultiLine[currentTag] = true;
currentValueList = new List();
this[currentTag] = currentValueList;
}
}
}
return true;
}
#endregion
///
/// Create a form specification from the fields that make up a form
///
///
public override string ToString()
{
StringBuilder buff = new StringBuilder(2048);
if (Comments != null)
{
buff.AppendLine(Comments);
}
foreach (string key in Keys)
{
// ignore values that do not go into the spec form
if (key == "specdef" || key == "specFormatted" || key == "func")
{
continue;
}
if ((IsFieldMultiLine.ContainsKey(key)) && (IsFieldMultiLine[key]))
{
buff.AppendFormat("{0}:\n", key);
if (this[key] is string)
{
string multilineString = this[key] as string;
multilineString= multilineString.TrimEnd('\n', '\r');
if (multilineString.Contains("\n"))
{
multilineString = multilineString.Replace("\r", "");
multilineString = multilineString.Replace("\n", "\n\t");
}
else if (multilineString.Contains("\r"))
{
multilineString = multilineString.Replace("\r", "\n\t");
}
buff.AppendFormat("\t{0}\n", (multilineString));
}
else
{
IList lines = this[key] as IList;
for (int idx = 0; idx < lines.Count; idx++)
{
buff.AppendFormat("\t{0}\n", lines[idx]);
}
}
}
else
{
buff.AppendFormat("{0}:\t{1}\n", key, this[key] as string);
}
}
return buff.ToString();
}
///
/// Utility function to format a DateTime in the format expected in a spec
///
///
///
public static String FormatDateTime(DateTime dt)
{
if ((dt != null) && (DateTime.MinValue != dt))
return dt.ToString("yyyy|MM|dd HH:mm:ss").Replace('|','/');
return string.Empty;
}
///
/// Utility to convert a Unix time (Seconds past midnight 1/1/1970) to a DateTime
///
///
///
public static DateTime ConvertUnixTime(long unixTime)
{
return new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds(unixTime);
}
///
/// Utility to convert a Unix time (Seconds past midnight 1/1/1970) to a DateTime
///
/// Unix time as a string
///
public static DateTime ConvertUnixTime(string unixTimeStr)
{
long unixTime = 0;
if (long.TryParse(unixTimeStr, out unixTime))
{
return new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds(unixTime);
}
return new DateTime(1970, 1, 1, 0, 0, 0, 0);
}
public static bool DSTMismatch(ServerMetaData smd)
{
try
{
DateTime serverDate = smd.Date;
bool UTC_dst =
TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time").IsDaylightSavingTime(serverDate);
bool server_dst = serverDate.IsDaylightSavingTime();
if (server_dst && !UTC_dst)
{
return true;
}
}
catch { }
return false;
}
public static DateTime ConvertFromUTC(DateTime dt, string offset, bool DST_mistmatch)
{
int idx = offset.IndexOf(" ");
if (idx >= 0)
{
offset = offset.Remove(offset.IndexOf(" "));
}
offset = offset.TrimEnd('0');
int timeDiff;
bool num = int.TryParse(offset, out timeDiff);
dt = dt.AddHours(timeDiff);
bool timestampDST = dt.IsDaylightSavingTime();
if (!timestampDST&&DST_mistmatch)
{
dt = dt.AddHours(-1);
}
return dt;
}
///
/// Utility to properly format multi-line fields in forms
///
/// Multi-line field
///
public static string FormatMultilineField(string multiline)
{
String tmpMultilineStr = String.Empty;
if (!String.IsNullOrEmpty(multiline))
{
tmpMultilineStr = multiline.Replace("\r", "").Trim('\r', '\n');
tmpMultilineStr = tmpMultilineStr.Replace("\n", "\n\t").Trim();
}
return tmpMultilineStr;
}
}
}