2002-10-28 Gaurav Vaish <gvaish_mono@lycos.com>
[mono.git] / mcs / class / System.Web / System.Web.UI.WebControls / BaseCompareValidator.cs
1 /**
2  * Namespace: System.Web.UI.WebControls
3  * Class:     BaseCompareValidator
4  *
5  * Author:  Gaurav Vaish
6  * Maintainer: gvaish@iitk.ac.in
7  * Implementation: yes
8  * Contact: <gvaish@iitk.ac.in>
9  * Status:  100%
10  *
11  * (C) Gaurav Vaish (2001)
12  */
13
14 using System;
15 using System.Collections;
16 using System.Globalization;
17 using System.Text;
18 using System.Text.RegularExpressions;
19 using System.Web;
20 using System.Web.UI;
21 using System.ComponentModel;
22
23 namespace System.Web.UI.WebControls
24 {
25         public abstract class BaseCompareValidator: BaseValidator
26         {
27                 protected BaseCompareValidator(): base()
28                 {
29                 }
30
31                 public static bool CanConvert(string text, ValidationDataType type)
32                 {
33                         object o = null;
34                         return Convert(text, type, out o);
35                 }
36
37                 [DefaultValue(ValidationDataType.String)]
38                 [WebCategory("Behaviour")]
39                 [WebSysDescription("RangeValidator_Type")]
40                 public ValidationDataType Type
41                 {
42                         get
43                         {
44                                 object o = ViewState["Type"];
45                                 if(o!=null)
46                                         return (ValidationDataType)o;
47                                 return ValidationDataType.String;
48                         }
49                         set
50                         {
51                                 if(!System.Enum.IsDefined(typeof(ValidationDataType), value))
52                                         throw new ArgumentException();
53                                 ViewState["Type"] = value;
54                         }
55                 }
56
57                 protected static int CutoffYear
58                 {
59                         get
60                         {
61                                 return DateTimeFormatInfo.CurrentInfo.Calendar.TwoDigitYearMax;
62                         }
63                 }
64
65                 protected static int GetFullYear(int shortYear)
66                 {
67                         int century = DateTime.Today.Year - (DateTime.Today.Year % 100);
68                         if(century < CutoffYear)
69                         {
70                                 return (shortYear + century);
71                         }
72                         return (shortYear + century - 100);
73                 }
74
75                 protected override void AddAttributesToRender(HtmlTextWriter writer)
76                 {
77                         base.AddAttributesToRender(writer);
78                         if(RenderUplevel)
79                         {
80                                 writer.AddAttribute("type", PropertyConverter.EnumToString(typeof(ValidationDataType), Type));
81                                 NumberFormatInfo currInfo = NumberFormatInfo.CurrentInfo;
82                                 if(Type == ValidationDataType.Double)
83                                 {
84                                         writer.AddAttribute("decimalchar", currInfo.NumberDecimalSeparator);
85                                         return;
86                                 }
87                                 if(Type == ValidationDataType.Currency)
88                                 {
89                                         writer.AddAttribute("decimalchar", currInfo.CurrencyDecimalSeparator);
90                                         string grpSep = currInfo.CurrencyGroupSeparator;
91                                         if(grpSep[0] == 0xA0)
92                                         {
93                                                 grpSep = " ";
94                                         }
95                                         writer.AddAttribute("groupchar", grpSep);
96                                         writer.AddAttribute("digits", currInfo.CurrencyDecimalDigits.ToString(NumberFormatInfo.InvariantInfo));
97                                         return;
98                                 }
99                                 if(Type == ValidationDataType.Date)
100                                 {
101                                         writer.AddAttribute("cutoffyear", CutoffYear.ToString());
102                                         writer.AddAttribute("century", ( DateTime.Today.Year - (DateTime.Today.Year % 100) ).ToString());
103                                         return;
104                                 }
105                         }
106                 }
107
108                 protected override bool DetermineRenderUplevel()
109                 {
110                         if(Type == ValidationDataType.Date && DateTimeFormatInfo.CurrentInfo.Calendar.GetType() != typeof(GregorianCalendar))
111                         {
112                                 return false;
113                         }
114                         return base.DetermineRenderUplevel();
115                 }
116
117                 /// <summary>
118                 /// Undocumented
119                 /// </summary>
120                 protected static bool Compare(string leftText, string rightText, ValidationCompareOperator op, ValidationDataType type)
121                 {
122                         object left = null, right = null;
123                         if(!Convert(leftText, type, out left))
124                         {
125                                 return false;
126                         }
127                         if(op == ValidationCompareOperator.DataTypeCheck)
128                         {
129                                 return true;
130                         }
131                         if(!Convert(rightText, type, out right))
132                         {
133                                 return true;
134                         }
135                         int compareResult = 0;
136                         switch(type)
137                         {
138                                 case ValidationDataType.String:
139                                         compareResult = ((String)left).CompareTo(right);
140                                         break;
141                                 case ValidationDataType.Integer:
142                                         compareResult = ((int)left).CompareTo(right);
143                                         break;
144                                 case ValidationDataType.Double:
145                                         compareResult = ((Double)left).CompareTo(right);
146                                         break;
147                                 case ValidationDataType.Date:
148                                         compareResult = ((DateTime)left).CompareTo(right);
149                                         break;
150                                 case ValidationDataType.Currency:
151                                         compareResult = ((Decimal)left).CompareTo(right);
152                                         break;
153                         }
154                         switch(op)
155                         {
156                                 case ValidationCompareOperator.Equal:
157                                         return (compareResult == 0);
158                                 case ValidationCompareOperator.NotEqual:
159                                         return (compareResult != 0);
160                                 case ValidationCompareOperator.GreaterThan:
161                                         return (compareResult > 0);
162                                 case ValidationCompareOperator.GreaterThanEqual:
163                                         return (compareResult >= 0);
164                                 case ValidationCompareOperator.LessThan:
165                                         return (compareResult < 0);
166                                 case ValidationCompareOperator.LessThanEqual:
167                                         return (compareResult <= 0);
168                         }
169                         return false;
170                 }
171
172                 /// <summary>
173                 /// Undocumented
174                 /// </summary>
175                 protected static string GetDateElementOrder()
176                 {
177                         string pattern = DateTimeFormatInfo.CurrentInfo.ShortDatePattern;
178
179                         //TODO: What are the various possibilities?
180                         // I can think of only y*/M*/d*, d*/M*/y*, M*/d*/y*
181                         if(pattern.IndexOf('y') < pattern.IndexOf('M'))
182                         {
183                                 return "ymd";
184                         }
185                         if(pattern.IndexOf('M') < pattern.IndexOf('d'))
186                         {
187                                 return "mdy";
188                         }
189                         return "dmy";
190                 }
191
192                 /// <summary>
193                 /// Undocumented
194                 /// </summary>
195                 protected static bool Convert(string text, ValidationDataType type, out object convertedValue)
196                 {
197                         convertedValue = null;
198                         try
199                         {
200                                 switch(type)
201                                 {
202                                         case ValidationDataType.String: convertedValue = text;
203                                                 break;
204                                         case ValidationDataType.Integer: convertedValue = Int32.Parse(text, CultureInfo.InvariantCulture);
205                                                 break;
206                                         case ValidationDataType.Double:
207                                                 Match matchDouble = Regex.Match(text, @"^\s*([-\+])?(\d+)?(\"
208                                     + NumberFormatInfo.CurrentInfo.NumberDecimalSeparator
209                                     + @"(\d+))?\s*$");
210                                                 if(matchDouble.Success)
211                                                 {
212                                                         string sign     = (matchDouble.Groups[1].Success ? matchDouble.Groups[1].Value : "+");
213                                                         string decPart  = (matchDouble.Groups[2].Success ? matchDouble.Groups[2].Value : "0");
214                                                         string mantissa = (matchDouble.Groups[4].Success ? matchDouble.Groups[4].Value : "0");
215                                                         convertedValue  = Double.Parse(sign + decPart + "." + mantissa, CultureInfo.InvariantCulture);
216                                                 }
217                                                 break;
218                                         case ValidationDataType.Date:
219                                                 if(DateTimeFormatInfo.CurrentInfo.Calendar.GetType() != typeof(GregorianCalendar))
220                                                 {
221                                                         convertedValue = DateTime.Parse(text);
222                                                         break;
223                                                 }
224                                                 string order = GetDateElementOrder();
225                                                 int date = 0, mth = 0, year = 0;
226                                                 Match  matchDate = Regex.Match(text, @"^\s*((\d{4})|(\d{2}))([\.\/-])(\d{1,2})\4(\d{1,2})\s*$");
227                                                 if(matchDate.Success && order == "ymd")
228                                                 {
229                                                         date = Int32.Parse(matchDate.Groups[6].Value, CultureInfo.InvariantCulture);
230                                                         mth  = Int32.Parse(matchDate.Groups[5].Value, CultureInfo.InvariantCulture);
231                                                         year = Int32.Parse((matchDate.Groups[2].Success ? matchDate.Groups[2].Value : matchDate.Groups[3].Value), CultureInfo.InvariantCulture);
232                                                 } else
233                                                 {
234                                                         matchDate = Regex.Match(text, @"^\s*(\d{1,2})([\.\/-])(\d{1,2})\2((\d{4}|\d{2}))\s*$");
235                                                         if(matchDate.Success)
236                                                         {
237                                                                 if(order == "dmy")
238                                                                 {
239                                                                         date = Int32.Parse(matchDate.Groups[1].Value, CultureInfo.InvariantCulture);
240                                                                         mth  = Int32.Parse(matchDate.Groups[3].Value, CultureInfo.InvariantCulture);
241                                                                         year = Int32.Parse((matchDate.Groups[5].Success ? matchDate.Groups[5].Value : matchDate.Groups[6].Value), CultureInfo.InvariantCulture);
242                                                                 }
243                                                                 if(order == "mdy")
244                                                                 {
245                                                                         date = Int32.Parse(matchDate.Groups[3].Value, CultureInfo.InvariantCulture);
246                                                                         mth  = Int32.Parse(matchDate.Groups[1].Value, CultureInfo.InvariantCulture);
247                                                                         year = Int32.Parse((matchDate.Groups[5].Success ? matchDate.Groups[5].Value : matchDate.Groups[6].Value), CultureInfo.InvariantCulture);
248                                                                 }
249                                                         }
250                                                 }
251                                                 year = (year < 100 ? GetFullYear(year) : year);
252                                                 if(matchDate.Success && date!=0 && mth!=0 && year!=0)
253                                                 {
254                                                         convertedValue = new DateTime(year, mth, date);
255                                                 }
256                                                 break;
257                                         case  ValidationDataType.Currency:
258                                                 string decSep = NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator;
259                                                 string grpSep = NumberFormatInfo.CurrentInfo.CurrencyGroupSeparator;
260                                                 int    decDig = NumberFormatInfo.CurrentInfo.CurrencyDecimalDigits;
261                                                 if(grpSep[0] == 0xA0)
262                                                 {
263                                                         grpSep = " ";
264                                                 }
265                                                 string[] patternArray = new string[5];
266                                                 patternArray[0] = "^\\s*([-\\+])?(((\\d+)\\";
267                                                 patternArray[1] = grpSep;
268                                                 patternArray[2] = @")*)(\d+)";
269                                                 if(decDig > 0)
270                                                 {
271                                                         string[] decPattern = new string[5];
272                                                         decPattern[0] = "(\\";
273                                                         decPattern[1] = decSep;
274                                                         decPattern[2] = @"(\d{1,";
275                                                         decPattern[3] = decDig.ToString(NumberFormatInfo.InvariantInfo);
276                                                         decPattern[4] = @"}))";
277                                                         patternArray[3] = String.Concat(decPattern);
278
279                                                 } else
280                                                 {
281                                                         patternArray[3] = String.Empty;
282                                                 }
283                                                 patternArray[4] = @"?\s*$";
284                                                 Match matchCurrency = Regex.Match(text, String.Concat(patternArray));
285                                                 if(matchCurrency.Success)
286                                                 {
287                                                         StringBuilder sb = new StringBuilder();
288                                                         sb.Append(matchCurrency.Groups[1]);
289                                                         CaptureCollection cc = matchCurrency.Groups[4].Captures;
290                                                         foreach(IEnumerable current in cc)
291                                                         {
292                                                                 sb.Append((Capture)current);
293                                                         }
294                                                         sb.Append(matchCurrency.Groups[5]);
295                                                         if(decDig > 0)
296                                                         {
297                                                                 sb.Append(".");
298                                                                 sb.Append(matchCurrency.Groups[7]);
299                                                         }
300                                                         convertedValue = Decimal.Parse(sb.ToString(), CultureInfo.InvariantCulture);
301                                                 }
302                                                 break;
303                                 }
304                         } catch(Exception e)
305                         {
306                                 convertedValue = null;
307                         }
308                         return (convertedValue != null);
309                 }
310         }
311 }