Files
2018-06-29 19:47:36 +00:00

1604 lines
44 KiB
C#
Raw Permalink Blame History

///////////////////////////////////////////////////////////
// Address.cs
// Implementation of Class Address
// CSLA type: Editable Child
// Created on: 07-Jun-2004 8:41:13 AM
// Object design: Joyce
// Coded: John 30-Jun-2004
///////////////////////////////////////////////////////////
using System;
using System.Data;
using CSLA.Data;
using CSLA;
using System.Text.RegularExpressions;
using System.Text;
using System.Threading;
using CSLA.Security;
//test change for subversion testing
using System.ComponentModel;
using System.Globalization;
using GZTW.Data;
namespace GZTW.AyaNova.BLL
{
/// <summary>
/// Address object - stores physical location or postal address
/// This object used by <see cref="Client"/>, <see cref="Vendor"/>, <see cref="HeadOffice"/> and <see cref="Vendor"/> objects
/// </summary>
///
//[Serializable, TypeConverterAttribute(typeof(AddressConverter))]//case 3379, this seems to be not necessary and is interfering with json serialization?
[Serializable]
public class Address : BusinessBase
{
#region Attributes
private bool bReadOnly;
private AddressTypes mAddressType;
private Guid mRootObjectID;
private RootObjectTypes mRootObjectType;
private Guid mCreator;
private Guid mModifier;
private SmartDate mCreated;
private SmartDate mModified;
private string mDeliveryAddress="";
private string mCity="";
private string mStateProv="";
private string mCountry="";
private string mPostal="";
private string mCountryCode="";
private decimal mLatitude;
private decimal mLongitude;
#endregion
#region Constructor
private Address()
{
//Child object
MarkAsChild();
//Set to read / write initially so that properties
//can be set
bReadOnly=false;
mRootObjectType=0;
mRootObjectID=System.Guid.Empty;
mLatitude=0;
mLongitude=0;
//Set record history to defaults
mCreated = new SmartDate(DBUtil.CurrentWorkingDateTime);
mModified=new SmartDate();
mCreator=Guid.Empty;
mModifier=Guid.Empty;
}
#endregion
#region Business properties
/// <summary>
/// The root object type this address applies to
/// Valid settings are:
/// Unit, HeadOffice, Vendor, Client
/// Global or Region
/// </summary>
[Browsable(false)]
public RootObjectTypes RootObjectType
{
get
{
return mRootObjectType;
}
set
{
if(bReadOnly)
ThrowSetError();
else
{
if(mRootObjectType!=value)
{
mRootObjectType = value;
BrokenRules.Assert("RootObjectTypeInValid",
"Error.Object.FieldValueNotValid,Common.Label.RootObjectType",
"RootObjectType",
((value!=RootObjectTypes.Unit)&&(value!=RootObjectTypes.HeadOffice)&&
(value!=RootObjectTypes.Vendor)&&(value!=RootObjectTypes.Client)&&
(value!=RootObjectTypes.Global)&&(value!=RootObjectTypes.Region)));
MarkDirty();
}
}
}
}
/// <summary>
/// ID of object this address belongs to
/// </summary>
[Browsable(false)]
public Guid RootObjectID
{
get
{
return mRootObjectID;
}
set
{
if(bReadOnly)
ThrowSetError();
else
{
if(mRootObjectID!=value)
{
mRootObjectID = value;
BrokenRules.Assert("RootObjectIDRequired",
"Error.Object.RequiredFieldEmpty,Common.Label.RootObject",
"RootObjectID",value==System.Guid.Empty);
MarkDirty();
}
}
}
}
/// <summary>
/// Type of address (physical (deliver) or postal)
/// </summary>
[Browsable(false)]
public AddressTypes AddressType
{
get
{
return mAddressType;
}
set
{
if(bReadOnly)
ThrowSetError();
else
{
if(value!=AddressTypes.Unset/*<-Because we need to allow it to be set this way
* for the constructor*/ && mAddressType!=value)
{
mAddressType = value;
//A Unit can't have a mailing address
BrokenRules.Assert("AddressTypeInValid",
"Error.Object.FieldValueNotValid,Address.Label.IsMailAddress",
"IsMailAddress",
((RootObjectType==RootObjectTypes.Unit)&&(value==AddressTypes.Postal)));
//An address type *MUST* be set
BrokenRules.Assert("AddressTypeEmpty",
"Error.Object.RequiredFieldEmpty,Address.Label.AddressType","IsMailAddress",value==AddressTypes.Unset);
MarkDirty();
}
}
}
}
/// <summary>
///
/// </summary>
[Browsable(false)]
public Guid Creator
{
get
{
return mCreator;
}
}
/// <summary>
///
/// </summary>
[Browsable(false)]
public string Created
{
get
{
return mCreated.ToString();
}
}
/// <summary>
///
/// </summary>
[Browsable(false)]
public Guid Modifier
{
get
{
return mModifier;
}
}
/// <summary>
///
/// </summary>
[Browsable(false)]
public string Modified
{
get
{
return mModified.ToString();
}
}
/// <summary>
/// Get/set street address - maximum 255 char
/// </summary>
public string DeliveryAddress
{
get
{
return mDeliveryAddress;
}
set
{
if(bReadOnly)
ThrowSetError();
else
{
if(mDeliveryAddress!=value)
{
mDeliveryAddress = value;
BrokenRules.Assert("DeliveryAddressLength",
"Error.Object.FieldLengthExceeded255,Address.Label.DeliveryAddress","DeliveryAddress",value.Length>255);
MarkDirty();
}
}
}
}
/// <summary>
/// Get/set city for this address - maximum 255 char - may have default
/// entered by global/regional settings
/// </summary>
public string City
{
get
{
return mCity;
}
set
{
if(bReadOnly)
ThrowSetError();
else
{
if(mCity!=value)
{
mCity = value;
BrokenRules.Assert("CityLength",
"Error.Object.FieldLengthExceeded255,Address.Label.City","City",value.Length>255);
MarkDirty();
}
}
}
}
/// <summary>
/// Get/set state or province for this address - maximum 255 char - may
/// have default entered by global/regional settings
/// </summary>
public string StateProv
{
get
{
return mStateProv;
}
set
{
if(bReadOnly)
ThrowSetError();
else
{
if(mStateProv!=value)
{
mStateProv = value;
BrokenRules.Assert("StateProvLength",
"Error.Object.FieldLengthExceeded255,Address.Label.StateProv","StateProv",value.Length>255);
MarkDirty();
}
}
}
}
/// <summary>
/// Get/set country for this address - maximum 255 char - may have default
/// entered by global/regional settings
/// </summary>
public string Country
{
get
{
return mCountry;
}
set
{
if(bReadOnly)
ThrowSetError();
else
{
if(mCountry!=value)
{
mCountry = value;
if(mCountry!=null && mCountry!="")
{
//attempt to auto set the country code here
//for english speakers
switch(mCountry.ToLower())
{
case "canada":
mCountryCode="CA";
break;
case "us":
mCountryCode="US";
break;
case "usa":
mCountryCode="US";
break;
case "united states":
mCountryCode="US";
break;
case "united states of america":
mCountryCode="US";
break;
case "america":
mCountryCode="US";
break;
case "australia":
mCountryCode="AU";
break;
case "hong kong":
mCountryCode="HK";
break;
case "china":
mCountryCode="CN";
break;
case "ireland":
mCountryCode="IE";
break;
case "india":
mCountryCode="IN";
break;
case "israel":
mCountryCode="IL";
break;
case "italy":
mCountryCode="IT";
break;
case "japan":
mCountryCode="JP";
break;
case "malta":
mCountryCode="MT";
break;
case "mexico":
mCountryCode="MX";
break;
case "new zealand":
mCountryCode="NZ";
break;
case "puerto rico":
mCountryCode="PR";
break;
case "singapore":
mCountryCode="SG";
break;
case "united kingdom":
mCountryCode="UK";
break;
case "uk":
mCountryCode="UK";
break;
case "scotland":
mCountryCode="UK";
break;
case "england":
mCountryCode="UK";
break;
}
}
BrokenRules.Assert("CountryLength",
"Error.Object.FieldLengthExceeded255,Address.Label.Country","Country",value.Length>255);
MarkDirty();
}
}
}
}
/// <summary>
/// Get/set ISO country code for this country, maximum 2 characters
/// required for all non-US address lookups
/// </summary>
public string CountryCode
{
get
{
return mCountryCode;
}
set
{
if(bReadOnly)
ThrowSetError();
else
{
if(mCountryCode!=value)
{
mCountryCode = value;
BrokenRules.Assert("CountryCodeLength",
"Error.Object.FieldLengthExceeded,Address.Label.CountryCode,2","CountryCode",value.Length>2);
MarkDirty();
}
}
}
}
/// <summary>
/// Get/set postal code or zip code for this address - maximum 255 char
/// </summary>
public string Postal
{
get
{
return mPostal;
}
set
{
if(bReadOnly)
ThrowSetError();
else
{
if(mPostal!=value)
{
mPostal = value;
BrokenRules.Assert("PostalLength",
"Error.Object.FieldLengthExceeded255,Address.Label.Postal","Postal",value.Length>255);
MarkDirty();
}
}
}
}
/// <summary>
/// Returns a valid MapQuest url for
/// opening a map of address in a web page
/// </summary>
public string MapQuestURL
{
get
{
StringBuilder sb=new StringBuilder();
//sb.Append("http://www.mapquest.com/maps/map.adp?");
sb.Append(AyaBizUtils.SS("city=",MapQuestReplacement(this.mCity),"&"));
sb.Append(AyaBizUtils.SS("state=",MapQuestReplacement(this.mStateProv),"&"));
sb.Append(AyaBizUtils.SS("address=",MapQuestReplacement(this.mDeliveryAddress),"&"));
sb.Append(AyaBizUtils.SS("zipcode=",MapQuestReplacement(this.mPostal),"&"));
sb.Append(AyaBizUtils.SS("country=",MapQuestReplacement(this.mCountryCode),"&"));
string s=sb.ToString();
if(s.StartsWith("&"))
s=s.Remove(0,1);
return "http://www.mapquest.com/maps/map.adp?" + s +"zoom=8&style=3";
}
}
/// <summary>
/// makes replacements to any characters that might be
/// in a source string so that they conform to mapquest url specs
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
private string MapQuestReplacement(string source)
{
if(source==null || source=="")
return "";
source=source.Replace("\r\n"," ");
source=source.Replace("%","%%25");
source=source.Replace("&","%%26");
source=source.Replace("+","%%30");
return source.Replace(" ","+");
}
/// <summary>
/// Get complete address as single string for display
/// following US / Canadian postal regulations recommendations:
/// DELIVERY ADDRESS
/// CITY/STATE/ZIP
/// COUNTRY
/// </summary>
public string FullAddress
{
get
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
if(mDeliveryAddress!=null && mDeliveryAddress.Length>0)
{
sb.Append(mDeliveryAddress);
sb.Append(" \r\n");
}
if(mCity!=null && mCity.Length>0)
{
sb.Append(mCity);
sb.Append(" ");
}
if(mStateProv!=null && mStateProv.Length>0)
{
sb.Append(mStateProv);
sb.Append(" ");
}
if(mPostal!=null && mPostal.Length>0)
{
//Postal codes should have two spaces before them according to regs.
sb.Append(" ");
sb.Append(mPostal);
sb.Append(" \r\n");
}
if(mCountry!=null && mCountry.Length>0)
{
sb.Append(mCountry);
}
if(mAddressType==AddressTypes.Physical)
{
if(mLatitude!=0 || mLongitude!=0)
{
sb.Append(" \r\n");
sb.Append(LongitudeToString(mLongitude));
sb.Append(" ");
sb.Append(LatitudeToString(mLatitude));
sb.Append(" \r\n");
}
}
return sb.ToString();
}
}
/// <summary>
/// Longitude in decimal degrees
/// </summary>
public decimal Longitude
{
get
{
return mLongitude;
}
set
{
if(bReadOnly)
ThrowSetError();
else
{
if(mLongitude!=value)
{
mLongitude = value;
BrokenRules.Assert("LongitudeSetError",
"Error.Object.FieldValueNotValid,Address.Label.Longitude","Longitude",mLongitude!=0 && ((mLongitude>180) || (mLongitude < -180)));
MarkDirty();
}
}
}
}
/// <summary>
/// Latitude in decimal degrees
/// </summary>
public decimal Latitude
{
get
{
return mLatitude;
}
set
{
if(bReadOnly)
ThrowSetError();
else
{
if(mLatitude!=value)
{
mLatitude = value;
BrokenRules.Assert("LatitudeSetError",
"Error.Object.FieldValueNotValid,Address.Label.Latitude","Latitude",mLatitude !=0 && ((mLatitude>90) || (mLatitude < -90)));
MarkDirty();
}
}
}
}
/// <summary>
/// Longitude as text
/// SET: parses most text formats of different styles co-ordinates
/// <seealso cref="LatitudeFromString"/>
/// GET: Returns text formatted as per global coordinate style setting
/// </summary>
public string LongitudeText
{
get
{
return LongitudeAsString(AyaBizUtils.GlobalSettings.CoordinateStyle,true);
}
set
{
if(bReadOnly)
ThrowSetError();
else
{
string strValue=value;
if(strValue==null) strValue="";
//If there is no negative or positive sign specified then
//it's open to interpretation
if(!strValue.StartsWith("-") && !strValue.StartsWith("+"))
{
//Time to interpret...
//if the current value is zero then apply the global default chosen
if(mLongitude==0)
{
if(AyaBizUtils.GlobalSettings.DefaultLongitude==LongitudeHemisphere.West)
strValue="-" + strValue;
}
else
{//otherwise use the same Hemisphere as the existing value
if(mLongitude<0)
strValue="-" + strValue;
}
}
LongitudeFromString(strValue);
MarkDirty();
}
}
}
/// <summary>
/// Latitude as text
/// SET: parses most text formats of different styles co-ordinates
/// GET: Returns text formatted as per global coordinate style setting
///
/// </summary>
public string LatitudeText
{
get
{
return LatitudeAsString(AyaBizUtils.GlobalSettings.CoordinateStyle,true);
}
set
{
if(bReadOnly)
ThrowSetError();
else
{
string strValue=value;
if(strValue==null) strValue="";
//If there is no negative or positive sign specified then
//it's open to interpretation
if(!strValue.StartsWith("-") && !strValue.StartsWith("+"))
{
//Time to interpret...
//if the current value is zero then apply the global default chosen
if(mLatitude==0)
{
if(AyaBizUtils.GlobalSettings.DefaultLatitude==LatitudeHemisphere.South)
strValue="-" + strValue;
}
else
{//otherwise use the same Hemisphere as the existing value
if(mLatitude<0)
strValue="-" + strValue;
}
}
LatitudeFromString(strValue);
MarkDirty();
}
}
}
/// <summary>
/// Get/Set the Hemisphere of the current Latitude coordinate
/// (0 Latitude is always considered North for display purposes)
/// </summary>
public LatitudeHemisphere LatHemisphere
{
get
{
if(mLatitude<0) return LatitudeHemisphere.South;
return LatitudeHemisphere.North;
}
set
{
if(bReadOnly)
ThrowSetError();
else
{
if(mLatitude!=0 && value!=LatHemisphere)
{
mLatitude = -mLatitude;
MarkDirty();
}
}
}
}
/// <summary>
/// Get/Set the Hemisphere of the current Longitude coordinate
/// (0 Longitude is always considered West for display purposes)
/// </summary>
public LongitudeHemisphere LongHemisphere
{
get
{
if(mLongitude<=0) return LongitudeHemisphere.West;
return LongitudeHemisphere.East;
}
set
{
if(bReadOnly)
ThrowSetError();
else
{
if(mLongitude!=0 && value!=LongHemisphere)
{
mLongitude = -mLongitude;
MarkDirty();
}
}
}
}
#region various Coordinat display related methods
/// <summary>
/// Get Longitude as string
/// No indication of East / West
/// It is up to caller to check decimal value of
/// Longitude separately to determine if required
/// </summary>
/// <param name="CoOrdinateType">Format desired</param>
/// <param name="IncludeSeparatorCharacters">Return string with degrees and other symbols</param>
/// <returns>String representation of Longitude</returns>
private string LongitudeAsString(CoordinateTypes CoOrdinateType,bool IncludeSeparatorCharacters)
{
string sReturn="";
//When not set should return zero
if(mLongitude==0) return "0";
switch(CoOrdinateType)
{
case CoordinateTypes.DecimalDegrees:
sReturn= System.Math.Abs(mLongitude).ToString();
break;
case CoordinateTypes.DegreesDecimalMinutes:
sReturn=DecimalDegreesToDMText(mLongitude, IncludeSeparatorCharacters);
break;
case CoordinateTypes.DegreesMinutesSeconds:
sReturn= DecimalDegreesToDMSText(mLongitude, IncludeSeparatorCharacters);
break;
}
return sReturn;
}
/// <summary>
/// Get Latitude as string
/// No indication of North / South
/// It is up to caller to check decimal value of
/// latitude separately to determine if required
/// </summary>
/// <param name="CoOrdinateType">Format desired</param>
/// <param name="IncludeSeparatorCharacters">Return string with degrees and other symbols</param>
/// <returns>String representation of Latitude</returns>
private string LatitudeAsString(CoordinateTypes CoOrdinateType,bool IncludeSeparatorCharacters)
{
string sReturn="";
//When not set should return zero
if(mLatitude==0) return "0";
switch(CoOrdinateType)
{
case CoordinateTypes.DecimalDegrees:
sReturn= System.Math.Abs(mLatitude).ToString();
break;
case CoordinateTypes.DegreesDecimalMinutes:
sReturn= DecimalDegreesToDMText(mLatitude, IncludeSeparatorCharacters);
break;
case CoordinateTypes.DegreesMinutesSeconds:
sReturn= DecimalDegreesToDMSText(mLatitude, IncludeSeparatorCharacters);
break;
}
return sReturn;
}
/// <summary>
/// Get full Longitude as string using default format
/// </summary>
/// <param name="Longitude"></param>
/// <returns></returns>
public static string LongitudeToString(decimal Longitude)
{
return LongitudeAsStringWithEastWestIndicator(Longitude,AyaBizUtils.GlobalSettings.CoordinateStyle,true);
}
/// <summary>
/// Get Longitude as string in desired format
///
/// </summary>
/// <param name="CoOrdinateType">Format desired</param>
/// <param name="IncludeSeparatorCharacters">Return string with degrees and other symbols</param>
/// <param name="Longitude">decimal number representing longitude</param>
///
/// <returns>String representation of Longitude</returns>
public static string LongitudeAsStringWithEastWestIndicator(decimal Longitude, CoordinateTypes CoOrdinateType,bool IncludeSeparatorCharacters)
{
string NEWS="";
string sReturn="";
//When not set should return empty string
if(Longitude==0) return "";
//Negative longitudes are WEST of Greenwich
if(Longitude<=0)
NEWS=LocalizedTextTable.GetLocalizedTextDirect("UI.Label.West");
else
NEWS=LocalizedTextTable.GetLocalizedTextDirect("UI.Label.East");
switch(CoOrdinateType)
{
case CoordinateTypes.DecimalDegrees:
sReturn= NEWS + " " + System.Math.Abs(Longitude).ToString();
break;
case CoordinateTypes.DegreesDecimalMinutes:
sReturn= NEWS + " " + DecimalDegreesToDMText(Longitude, IncludeSeparatorCharacters);
break;
case CoordinateTypes.DegreesMinutesSeconds:
sReturn= NEWS + " " + DecimalDegreesToDMSText(Longitude, IncludeSeparatorCharacters);
break;
}
return sReturn;
}
/// <summary>
/// Convert decimal Latitude to full string representation in default format
/// </summary>
/// <param name="Latitude"></param>
/// <returns></returns>
public static string LatitudeToString(decimal Latitude)
{
return LatitudeAsStringWithNorthSouthIndicator(Latitude, AyaBizUtils.GlobalSettings.CoordinateStyle,true);
}
/// <summary>
/// Get Latitude as string
/// Includes localized North or South text prefix
/// </summary>
/// <param name="CoOrdinateType">Format desired</param>
/// <param name="IncludeSeparatorCharacters">Return string with degrees and other symbols</param>
/// <param name="Latitude">decimal type number representing latitude</param>
/// <returns>String representation of Latitude</returns>
public static string LatitudeAsStringWithNorthSouthIndicator(decimal Latitude, CoordinateTypes CoOrdinateType,bool IncludeSeparatorCharacters)
{
string NEWS="";
string sReturn="";
//When not set should return empty string
if(Latitude==0) return "";
//Negative Latitudes are SOUTH of the equator
if(Latitude<0)
NEWS=LocalizedTextTable.GetLocalizedTextDirect("UI.Label.South");
else
NEWS=LocalizedTextTable.GetLocalizedTextDirect("UI.Label.North");
switch(CoOrdinateType)
{
case CoordinateTypes.DecimalDegrees:
sReturn= NEWS + " " + System.Math.Abs(Latitude).ToString();
break;
case CoordinateTypes.DegreesDecimalMinutes:
sReturn= NEWS + " " + DecimalDegreesToDMText(Latitude,IncludeSeparatorCharacters);
break;
case CoordinateTypes.DegreesMinutesSeconds:
sReturn= NEWS + " " + DecimalDegreesToDMSText(Latitude, IncludeSeparatorCharacters);
break;
}
return sReturn;
}
/// <summary>
/// Convert decimal degrees to String representation
/// of Degrees minutes seconds
/// Negative input is not converted to West or South,
/// all input is returned as absolute value (with no sign)
/// it is up to the caller to add the direction.
/// </summary>
/// <param name="DecimalDegrees"></param>
/// <param name="IncludeSeparatorCharacters"></param>
/// <returns></returns>
static public string DecimalDegreesToDMSText(decimal DecimalDegrees, bool IncludeSeparatorCharacters)
{
/*
* Degrees=Whole number portion of DecimalDegrees
* Minutes = Whole number portion of (Decimal number portion of DecimalDegrees * 60)
* Seconds = Minutes decimal portion times 60
*
*/
if(IncludeSeparatorCharacters)
{
return string.Format("{0}<7D>{1}'{2}'",
System.Math.Abs((int)DecimalDegrees),System.Math.Abs((int)((DecimalDegrees-(int)DecimalDegrees)*60)),
(System.Math.Abs((((DecimalDegrees-(int)DecimalDegrees)*60)-(int)((DecimalDegrees-(int)DecimalDegrees)*60))*60)).ToString("F3"));
}
else
{
return string.Format("{0}{1}{2}",
System.Math.Abs((int)DecimalDegrees),System.Math.Abs((int)((DecimalDegrees-(int)DecimalDegrees)*60)),
(System.Math.Abs((((DecimalDegrees-(int)DecimalDegrees)*60)-(int)((DecimalDegrees-(int)DecimalDegrees)*60))*60)).ToString("F3"));
}
}
/// <summary>
/// Convert decimal degrees to String representation
/// of Degrees minutes and decimal minutes (no seconds)
/// Negative input is not converted to West or South,
/// all input is returned as as absolute value (with no sign)
/// it is up to the caller to add the direction.
/// </summary>
/// <param name="DecimalDegrees"></param>
/// <param name="IncludeSeparatorCharacters"></param>
/// <returns></returns>
static public string DecimalDegreesToDMText(decimal DecimalDegrees, bool IncludeSeparatorCharacters)
{
/*
* Degrees=Whole number portion of DecimalDegrees
* Minutes.Decimal minutes = Decimal number portion of DecimalDegrees * 60
*
*/
if(IncludeSeparatorCharacters)
{
return string.Format("{0}<7D>{1}'",System.Math.Abs((int)DecimalDegrees),
System.Math.Abs(((DecimalDegrees-(int)DecimalDegrees)*60)).ToString("F3"));
}
else
{
return string.Format("{0}{1}",(System.Math.Abs((int)DecimalDegrees)).ToString("#00"),
System.Math.Abs(((DecimalDegrees-(int)DecimalDegrees)*60)).ToString("00.000"));
}
}
#endregion
#region Various coordinate parsing and calc methods
/// <summary>
/// Set Longitude from string
/// Expects a '-' sign for West longitudes
/// any character other than a digit, decimal (period) or a - sign is
/// ignored completely and not used in parsing
///
///
/// Accepted types of co-ordinates are:
/// Decimal degrees: "-49.3435"
/// Degree decimal minutes: "49<34>22.456"
/// Degrees Minutes Seconds Decimal seconds: "49<34> 22' 13.456''"
///
/// Degree symbols are ignored and thus optional as well as minute ' or seconds '' symbols
/// traditionally used. All that is important is that there is a space or non-numeric character
/// between the groups of digits.
///
/// If a single number is found it is assumed to be decimal degrees.
/// If two separate numbers are found it is assumed to be Degree decimal minutes
/// If three separate groups of numbers are found it is assumed to be Degress minutes seconds
///
/// </summary>
/// <param name="strLongitude">String indicating coordinate</param>
public void LongitudeFromString(string strLongitude)
{
try
{
mLongitude=StringToDecimalDegrees(strLongitude);
BrokenRules.Assert("LongitudeSetError","LONGOK","Longitude",false);
MarkDirty();
}
catch(Exception ex)
{
mLongitude=0;
BrokenRules.Assert("LongitudeSetError",
"Error.Object.FieldValueNotValid,Address.Label.Longitude"+"\r\n"+ex.Message,"Longitude",true);
MarkDirty();
}
return;
}
/// <summary>
/// Set Latitude from string
/// Expects a '-' sign for South Latitudes
/// any character other than a digit, decimal (period) or a - sign is
/// ignored completely and not used in parsing
///
/// Accepted types of co-ordinates are:
/// Decimal degrees: "-49.3435"
/// Degree decimal minutes: "49<34>22.456"
/// Degrees Minutes Seconds Decimal seconds: "49<34> 22' 13.456''"
///
/// Degree symbols are ignored and thus optional as well as minute ' or seconds '' symbols
/// traditionally used. All that is important is that there is a space or non-numeric character
/// between the groups of digits.
///
/// If a single number is found it is assumed to be decimal degrees.
/// If two separate numbers are found it is assumed to be Degree decimal minutes
/// If three separate groups of numbers are found it is assumed to be Degress minutes seconds
///
///
///
/// </summary>
/// <param name="strLatitude">String indicating coordinate</param>
public void LatitudeFromString(string strLatitude)
{
try
{
mLatitude=StringToDecimalDegrees(strLatitude);
BrokenRules.Assert("LatitudeSetError","LATOK","Latitude",false);
MarkDirty();
}
catch(Exception ex)
{
mLatitude=0;
BrokenRules.Assert("LatitudeSetError",
"Error.Object.FieldValueNotValid,Address.Label.Latitude"+"\r\n"+ex.Message,"Latitude",true);
MarkDirty();
}
return;
}
/// <summary>
/// Parse a string coordinate and return a double coordinate value
/// Negative symbol must be first character if a south latitude or
/// a west longitude is input. All characters other than digits,
/// decimal point (one only) and negative symbol are ignored.
///
/// Accepted types of co-ordinates are:
/// Decimal degrees: "-49.3435"
/// Degree decimal minutes: "49<34>22.456"
/// Degrees Minutes Seconds Decimal seconds: "49<34> 22' 13.456''"
///
/// Degree symbols are ignored and thus optional as well as minute ' or seconds '' symbols
/// traditionally used. All that is important is that there is a space or non-numeric character
/// between the groups of digits.
///
/// If a single number is found it is assumed to be decimal degrees.
/// If two separate numbers are found it is assumed to be Degree decimal minutes
/// If three separate groups of numbers are found it is assumed to be Degress minutes seconds
///
/// If a null or empty string is the parameter then returns 0
///
/// </summary>
/// <param name="strCoordinate">Co-ordinate string</param>
/// <returns>Double coordinate value</returns>
static public decimal StringToDecimalDegrees(string strCoordinate)
{
decimal dLong=0;
if(strCoordinate==null || strCoordinate=="") return dLong;
//Regular expression to extract numbers groups
Regex regex = new Regex(
@"[\d.]+",
RegexOptions.IgnoreCase
| RegexOptions.Compiled
);
MatchCollection mc;
//Parse string with regular expression
mc = regex.Matches(strCoordinate);
//Ensure there is at least 1 but less than 4 matches
if(mc.Count<1 || mc.Count> 3)
throw new System.FormatException("StringToDecimalDegrees:(" + strCoordinate +") INVALID INPUT");
//Parse out the degrees
dLong=decimal.Parse(mc[0].Value);
//If there are minutes, parse them out and add to the total
if(mc.Count>1)
dLong+=(decimal.Parse(mc[1].Value)/60);
//If there are seconds, parse them out and add to the total
if(mc.Count>2)
dLong+=(decimal.Parse(mc[2].Value)/3600);
//Preserve negative-icity
if(strCoordinate[0]=='-')
dLong=0-dLong;
return dLong;
}
#endregion
//Case 518
/// <summary>
/// Address object is empty (not filled in)?
/// </summary>
public bool IsEmpty
{
get
{
if (string.IsNullOrEmpty(this.mDeliveryAddress.Trim()) && mLatitude==0 && mLongitude==0)
return true;
return false;
}
}
/// <summary>
/// Throw an error when a read only user
/// tries to set a property
/// (this should normally never be called unless someone is using the developer api since the UI
/// should prevent it from happening initially)
/// </summary>
private void ThrowSetError()
{
throw new System.Security.SecurityException
(
string.Format
(
LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToChange"),
LocalizedTextTable.GetLocalizedTextDirect("O.Address")
)
);
}
#endregion
#region System.object overrides
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return "Address" + mRootObjectID.ToString()+mRootObjectType.ToString()+mAddressType.ToString();
}
/// <summary>
///
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(Object obj)
{
if ( obj == null || GetType ( ) != obj.GetType ( ) ) return false;
Address c=(Address)obj;
return ((mRootObjectID==c.RootObjectID) && (mRootObjectType==c.RootObjectType) && (mAddressType==c.AddressType));
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return ("Address" + mRootObjectID.ToString()+mRootObjectType.ToString()+mAddressType.ToString()).GetHashCode();
}
#endregion
#region Static methods
/// <summary>
/// ID of the one and only Global object's address
/// (since a global object has no ID itself, this value is
/// used as the ID for it)
/// </summary>
public static Guid GlobalAddressID
{
get
{
return new Guid("{3A440D46-7C19-46f8-94BF-E9368DD16DED}");
}
}
/// <summary>
/// Create new Address
/// Parent MUST set RootObjectID, RootObjectType and IsMailAddress flag
/// </summary>
internal static Address NewItem()
{
return new Address();
}
/// <summary>
/// Get an address from passed in data reader
/// this is <c>GetItem</c> code
/// </summary>
/// <param name="dr"></param>
/// <example>
/// This sample shows how to call the GetZero method.
/// <code>
/// class Address
/// {
/// static int GetItem(blah)
/// { return GetZero(); }
/// }
/// </code>
/// </example>
internal static Address GetItem(SafeDataReader dr)
{
Address child = new Address();
child.Fetch(dr);
//Get access rights level
// (same as parent)
child.bReadOnly=AyaBizUtils.Right(child.mRootObjectType)<(int)SecurityLevelTypes.ReadWrite;
return child;
}
/// <summary>
/// Delete address
/// </summary>
internal static void DeleteItem(AddressTypes _AddressType,Guid _RootObjectID,RootObjectTypes _RootObjectType)
{
DataPortal.Delete(new Criteria( _AddressType, _RootObjectID, _RootObjectType));
}
/// <summary>
/// copy the contents of one address to another address
/// </summary>
/// <param name="FromAddress"></param>
/// <param name="ToAddress"></param>
public static void Copy(Address FromAddress, Address ToAddress)
{
if(FromAddress==null || ToAddress==null) return;
ToAddress.City=FromAddress.City;
ToAddress.Country=FromAddress.Country;
ToAddress.CountryCode=FromAddress.CountryCode;
ToAddress.DeliveryAddress=FromAddress.DeliveryAddress;
if(ToAddress.AddressType==AddressTypes.Physical && FromAddress.AddressType==AddressTypes.Physical)
{
ToAddress.Latitude=FromAddress.Latitude;
ToAddress.Longitude=FromAddress.Longitude;
}
ToAddress.Postal=FromAddress.Postal;
ToAddress.StateProv=FromAddress.StateProv;
}
#endregion
#region DAL DATA ACCESS
#region custom concurrency check
private static void CheckSafeToUpdate(System.DateTime LastUpdated, RootObjectTypes RootObjectType, Guid RootObjectID, AddressTypes AddressType, IDbTransaction tr)
{
DBCommandWrapper dbCommandWrapper = DBUtil.DB.GetSqlStringCommandWrapper(
"SELECT aModified, aModifier FROM AADDRESS WHERE (aRootObjectID " +
"= @RootObjectID) AND " +
"(aRootObjectType = @RootObjectType) AND (AADDRESSTYPE = @AddressType)"
);
dbCommandWrapper.AddInParameter("@RootObjectID",DbType.Guid,RootObjectID);
dbCommandWrapper.AddInParameter("@RootObjectType",DbType.Int16,(int)RootObjectType);
dbCommandWrapper.AddInParameter("@AddressType",DbType.Int16,(int)AddressType);
SafeDataReader r = new SafeDataReader(DBUtil.DB.ExecuteReader(dbCommandWrapper,tr));
if(r.Read())
{
if(!DBUtil.DatesAreEqualish(DBUtil.ToUTC(LastUpdated),r.GetSmartDate("aModified").Date))
{
Guid gModifier=r.GetGuid("aModifier");
r.Close();
dbCommandWrapper.Command.Parameters.Clear();
dbCommandWrapper.AddInParameter("@ID",DbType.Guid,gModifier);
dbCommandWrapper.Command.CommandText="SELECT aFirstName, aLastName FROM aUser WHERE aID = @ID";
r=new SafeDataReader(DBUtil.DB.ExecuteReader(dbCommandWrapper));
if(r.Read())
{
string sUser=r.GetString("aFirstName") + " " + r.GetString("aLastName");
r.Close();
throw new System.Exception(string.Format(LocalizedTextTable.GetLocalizedTextDirect("Error.DB.RecordModifiedExternally"),"Address",sUser));
}
}
else
{
//de nada
r.Close();
return;
}
}
//Added: 20-June-2006
r.Close();
}
#endregion
#region Update
/// <summary>
/// Update object to database
/// </summary>
/// <param name="RootObjectType">RootOjbect type</param>
/// <param name="RootObjectID">GUID of root object</param>
/// <param name="AddressType">Address type (must be mail or physical)</param>
/// <param name="tr">Parent object's transaction object</param>
internal void Update(RootObjectTypes RootObjectType, Guid RootObjectID, AddressTypes AddressType,IDbTransaction tr)
{
//No need to update if there is nothing changed
if(!this.IsDirty) return;
// If not a new record, check if record was modified
//by another user since original retrieval:
if(!IsNew)//call custom checksafetoupdate method for an address
CheckSafeToUpdate(this.mModified.Date,RootObjectType,RootObjectID,AddressType,tr);
#region Delete
if(IsDeleted)
{
if(!IsNew)
{
DBCommandWrapper cmDelete = DBUtil.GetCommandFromSQL("DELETE FROM AADDRESS WHERE (aRootObjectID=@RootObjectID AND aRootObjectType=@RootObjectType and AADDRESSTYPE=@AddressType);");
cmDelete.AddInParameter("@RootObjectID",DbType.Guid,RootObjectID);
cmDelete.AddInParameter("@RootObjectType",DbType.Int16,(int)RootObjectType);
cmDelete.AddInParameter("@AddressType",DbType.Int16,(int)AddressType);
DBUtil.DB.ExecuteNonQuery(cmDelete, tr);
}
MarkNew();
return;
}
#endregion
#region Add / Update
//get modification time temporarily, if update succeeds then
//set to this time
System.DateTime dtModified = DBUtil.CurrentWorkingDateTime;
DBCommandWrapper cm = null;
if(IsNew)//Add or update?
cm=DBUtil.GetCommandFromSQL(
"INSERT INTO AADDRESS (aRootObjectID,aRootObjectType, AADDRESSTYPE, aDeliveryAddress, aCity, aStateProv, " +
"aCountry, aCountryCode, aPostal, aLatitude, aLongitude, aCreated,aModified,aCreator,aModifier) " +
"VALUES (@RootObjectID,@RootObjectType,@AddressType,@DeliveryAddress,@City,@StateProv, " +
"@Country,@CountryCode,@Postal,@Latitude,@Longitude,@Created, @Modified, @CurrentUserID,@CurrentUserID)"
);
else
cm=DBUtil.GetCommandFromSQL(
"UPDATE AADDRESS SET aRootObjectID=@RootObjectID, aRootObjectType=@RootObjectType, " +
"AADDRESSTYPE=@AddressType, " +
"aDeliveryAddress=@DeliveryAddress, aCity=@City, " +
"aStateProv=@StateProv, aCountry=@Country, " +
"aCountryCode=@CountryCode, aPostal=@Postal, " +
"aLatitude=@Latitude, aLongitude=@Longitude, aModifier=@CurrentUserID, " +
"aModified=@Modified WHERE " +
"(aRootObjectID=@RootObjectID AND aRootObjectType=@RootObjectType " +
"AND AADDRESSTYPE=@AddressType)"
);
cm.AddInParameter("@AddressType",DbType.Int16,(int)AddressType);
cm.AddInParameter("@RootObjectID",DbType.Guid, RootObjectID);
cm.AddInParameter("@RootObjectType",DbType.Int16, (int)RootObjectType);
cm.AddInParameter("@CurrentUserID",DbType.Guid, CurrentUserID);
cm.AddInParameter("@Created",DbType.DateTime, DBUtil.ToUTC(mCreated.Date));
cm.AddInParameter("@Modified",DbType.DateTime, DBUtil.ToUTC(dtModified));
cm.AddInParameter("@City",DbType.String,mCity);
cm.AddInParameter("@Country",DbType.String, mCountry);
cm.AddInParameter("@CountryCode",DbType.String, mCountryCode);
cm.AddInParameter("@DeliveryAddress",DbType.String, mDeliveryAddress);
cm.AddInParameter("@Latitude",DbType.Decimal, mLatitude);
cm.AddInParameter("@Longitude",DbType.Decimal, mLongitude);
cm.AddInParameter("@Postal",DbType.String, mPostal);
cm.AddInParameter("@StateProv",DbType.String, mStateProv);
DBUtil.DB.ExecuteNonQuery(cm, tr);
MarkOld();//db is now synched with object
//Successful update so
//change modification time to match
this.mModified.Date=dtModified;
#endregion
}
#endregion
#region Fetch
/// <summary>
/// Populate this object from the values in the datareader passed to it
/// </summary>
/// <param name="dr"></param>
private void Fetch(SafeDataReader dr)
{
//Standard items
mCreated=DBUtil.ToLocal(dr.GetSmartDate("aCreated"));
mCreator=dr.GetGuid("aCreator");
mModified=DBUtil.ToLocal(dr.GetSmartDate("aModified"));
mModifier=dr.GetGuid("aModifier");
//Address specific items
mRootObjectID= dr.GetGuid("aRootObjectID");
mRootObjectType=(RootObjectTypes)dr.GetInt16("aRootObjectType");
mAddressType=(AddressTypes)dr.GetInt16("AADDRESSTYPE");
mCity=dr.GetString("aCity");
mCountry=dr.GetString("aCountry");
mCountryCode=dr.GetString("aCountryCode");
mDeliveryAddress=dr.GetString("aDeliveryAddress");
mLatitude=dr.GetDecimal("aLatitude");
mLongitude=dr.GetDecimal("aLongitude");
mPostal=dr.GetString("aPostal");
mStateProv=dr.GetString("aStateProv");
MarkOld();
}
#endregion
#endregion
#region criteria
/// <summary>
/// Criteria for identifying existing object
/// </summary>
[Serializable]
private class Criteria
{
public AddressTypes AddressType;
public Guid RootObjectID;
public RootObjectTypes RootObjectType;
public Criteria(AddressTypes _AddressType,Guid _RootObjectID,RootObjectTypes _RootObjectType)
{
AddressType=_AddressType;
RootObjectID=_RootObjectID;
RootObjectType=_RootObjectType;
}
}
#endregion
}//end Address
//case 3379, this seems to be not necessary and is interfering with json serialization?
//#region Address Type converter
///// <summary>
///// Type converter for an Address object
///// only ToString is implemented
///// and displays a full address
///// </summary>
//public class AddressConverter:ExpandableObjectConverter
//{
// /// <summary>
// /// True if address can be converted to desired type
// /// </summary>
// /// <param name="context"></param>
// /// <param name="destinationType"></param>
// /// <returns></returns>
// public override bool CanConvertTo(ITypeDescriptorContext context,System.Type destinationType)
// {
// if (destinationType == typeof(GZTW.AyaNova.BLL.Address))
// return true;
// return base.CanConvertTo(context, destinationType);
// }
// /// <summary>
// /// Convert address to desired type
// /// </summary>
// /// <param name="context"></param>
// /// <param name="culture"></param>
// /// <param name="value"></param>
// /// <param name="destinationType"></param>
// /// <returns></returns>
// public override object ConvertTo(ITypeDescriptorContext context,CultureInfo culture, object value, System.Type destinationType)
// {
// if (destinationType == typeof(System.String) &&
// value is GZTW.AyaNova.BLL.Address)
// {
// GZTW.AyaNova.BLL.Address a = (GZTW.AyaNova.BLL.Address)value;
// return a.FullAddress.Replace("\r\n"," ");
// }
// return base.ConvertTo(context, culture, value, destinationType);
// }
//}
//#endregion
}//end namespace GZTW.AyaNova.BLL