2004-06-09 Gonzalo Paniagua Javier <gonzalo@ximian.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                 static bool ConvertDate (string text, ValidationDataType type, ref object convertedValue)
193                 {
194                         //Console.WriteLine (DateTimeFormatInfo.CurrentInfo.Calendar.GetType ());
195                         // FIXME: sometime, somehow, the condition is true even when GetType () says
196                         // it's a GregorianCalendar.
197                         if (DateTimeFormatInfo.CurrentInfo.Calendar.GetType () != typeof (GregorianCalendar)) {
198                                 convertedValue = DateTime.Parse (text);
199                                 return true;
200                         }
201
202                         string order = GetDateElementOrder ();
203                         int date = 0, mth = 0, year = 0;
204                         string dateStr = null;
205                         string mthStr = null;
206                         string yearStr = null;
207                         Match match = Regex.Match (text, @"^\s*((\d{4})|(\d{2}))([\.\/-])(\d{1,2})\4(\d{1,2})\s*$");
208                         if (match.Success || order == "ymd") {
209                                 dateStr = match.Groups [6].Value;
210                                 mthStr = match.Groups [5].Value;
211                                 if (match.Groups [2].Success)
212                                         yearStr = match.Groups [2].Value;
213                                 else
214                                         yearStr = match.Groups [3].Value;
215                         } else {
216                                 match = Regex.Match(text, @"^\s*(\d{1,2})([\.\/-])(\d{1,2})\2((\d{4}|\d{2}))\s*$");
217                                 if (!match.Success)
218                                         return false;
219
220                                 if (order == "dmy") {
221                                         dateStr = match.Groups [1].Value;
222                                         mthStr  = match.Groups [3].Value;
223                                         if (match.Groups [5].Success)
224                                                 yearStr = match.Groups [5].Value;
225                                         else
226                                                 yearStr = match.Groups [6].Value;
227                                 } else if (order == "mdy") {
228                                         dateStr = match.Groups [3].Value;
229                                         mthStr  = match.Groups [1].Value;
230                                         if (match.Groups [5].Success)
231                                                 yearStr = match.Groups [5].Value;
232                                         else
233                                                 yearStr = match.Groups [6].Value;
234                                 }
235                         }
236
237                         if (dateStr == null || mthStr == null || yearStr == null) {
238                                 return false;
239                         }
240
241                         CultureInfo inv = CultureInfo.InvariantCulture;
242                         date = Int32.Parse (dateStr, inv);
243                         mth  = Int32.Parse (mthStr, inv);
244                         year = Int32.Parse (yearStr, inv);
245                         year = (year < 100 ? GetFullYear (year) : year);
246                         if (date != 0 && mth != 0 && year != 0) {
247                                 convertedValue = new DateTime  (year, mth, date);
248                                 return true;
249                         }
250
251                         return false;
252                 }
253
254                 static bool ConvertDouble (string text, ValidationDataType type, ref object convertedValue)
255                 {
256                         Match match = Regex.Match (text, @"^\s*([-\+])?(\d+)?(\" +
257                                                    NumberFormatInfo.CurrentInfo.NumberDecimalSeparator +
258                                                    @"(\d+))?\s*$");
259
260                         if (!match.Success)
261                                 return false;
262
263                         string sign     = (match.Groups [1].Success ? match.Groups [1].Value : "+");
264                         string decPart  = (match.Groups [2].Success ? match.Groups [2].Value : "0");
265                         string mantissa = (match.Groups [4].Success ? match.Groups [4].Value : "0");
266                         string num = sign + decPart + "." + mantissa;
267                         convertedValue  = Double.Parse (num, CultureInfo.InvariantCulture);
268                         return true;
269                 }
270
271                 static bool ConvertCurrency (string text, ValidationDataType type, ref object convertedValue)
272                 {
273                         string decSep = NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator;
274                         string grpSep = NumberFormatInfo.CurrentInfo.CurrencyGroupSeparator;
275                         int decDig = NumberFormatInfo.CurrentInfo.CurrencyDecimalDigits;
276                         if (grpSep [0] == 0xA0)
277                                 grpSep = " ";
278
279                         string [] patternArray = new string [5];
280                         patternArray [0] = "^\\s*([-\\+])?(((\\d+)\\";
281                         patternArray [1] = grpSep;
282                         patternArray [2] = @")*)(\d+)";
283                         if (decDig > 0) {
284                                 string [] decPattern = new string [5];
285                                 decPattern [0] = "(\\";
286                                 decPattern [1] = decSep;
287                                 decPattern [2] = @"(\d{1,";
288                                 decPattern [3] = decDig.ToString (NumberFormatInfo.InvariantInfo);
289                                 decPattern [4] = @"}))";
290                                 patternArray [3] = String.Concat (decPattern);
291
292                         } else {
293                                 patternArray [3] = String.Empty;
294                         }
295
296                         patternArray [4] = @"?\s*$";
297                         Match match = Regex.Match (text, String.Concat (patternArray));
298                         if (!match.Success)
299                                 return false;
300
301                         StringBuilder sb = new StringBuilder ();
302                         sb.Append (match.Groups [1]);
303                         CaptureCollection cc = match.Groups [4].Captures;
304                         foreach (IEnumerable current in cc)
305                                 sb.Append ((Capture) current);
306
307                         sb.Append (match.Groups [5]);
308                         if (decDig > 0) {
309                                 sb.Append (".");
310                                 sb.Append (match.Groups [7]);
311                         }
312
313                         convertedValue = Decimal.Parse (sb.ToString (), CultureInfo.InvariantCulture);
314                         return true;
315                 }
316
317                 /// <summary>
318                 /// Undocumented
319                 /// </summary>
320                 protected static bool Convert (string text, ValidationDataType type, out object convertedValue)
321                 {
322                         CultureInfo inv = CultureInfo.InvariantCulture;
323                         convertedValue = null;
324                         try {
325                                 switch(type) {
326                                 case ValidationDataType.String:
327                                         convertedValue = text;
328                                         break;
329                                 case ValidationDataType.Integer:
330                                         convertedValue = Int32.Parse (text, inv);
331                                         break;
332                                 case ValidationDataType.Double:
333                                         return ConvertDouble (text, type, ref convertedValue);
334                                 case ValidationDataType.Date:
335                                         return ConvertDate (text, type, ref convertedValue);
336                                 case  ValidationDataType.Currency:
337                                         return ConvertCurrency (text, type, ref convertedValue);
338                                 }
339                         } catch (Exception) {
340                                 convertedValue = null;
341                         }
342
343                         return (convertedValue != null);
344                 }
345         }
346 }